JAL-3055 refinements to alternatives to deriveFont
[jalview.git] / src / jalview / renderer / AnnotationRenderer.java
index 4dd91da..102b3ee 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.CodingUtils;
 import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
+import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
@@ -475,9 +476,6 @@ public class AnnotationRenderer
 
     BitSet graphGroupDrawn = new BitSet();
     int charOffset = 0; // offset for a label
-    float fmWidth, fmScaling = 1f; // scaling for a label to fit it into a
-    // column.
-    Font ofont = g.getFont();
     // \u03B2 \u03B1
     // debug ints
     int yfrom = 0, f_i = 0, yto = 0, f_to = 0;
@@ -653,35 +651,24 @@ public class AnnotationRenderer
                     && (displayChar.length() > 0))
             {
               Graphics2D gg = ((Graphics2D) g);
-              AffineTransform t = gg.getTransform();
-              fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
+              float fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
                       displayChar.length());
-              if (/* centreColLabels || */scaleColLabel)
+
+              /*
+               * shrink label width to fit in column, if that is
+               * both configured and necessary
+               */
+              boolean scaledToFit = false;
+              float fmScaling = 1f;
+              if (scaleColLabel && fmWidth > charWidth)
               {
-                // fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
-                // displayChar.length());
-                //
-                // if (scaleColLabel)
-                // {
-                // justify the label and scale to fit in column
-                if (fmWidth > charWidth)
-                {
-                  // scale only if the current font isn't already small enough
-                  fmScaling = charWidth;
-                  fmScaling /= fmWidth;
-                  gg.setFont(ofont);
-                  gg.transform(
-                          AffineTransform.getScaleInstance(fmScaling, 1.0));
-                  // and update the label's width to reflect the scaling.
-                  fmWidth = charWidth;
-                }
-                // }
+                scaledToFit = true;
+                fmScaling = charWidth;
+                fmScaling /= fmWidth;
+                // and update the label's width to reflect the scaling.
+                fmWidth = charWidth;
               }
-              // TODO is it ok to use width of / show all characters here?
-              // else
-              // {
-              // fmWidth = fm.charWidth(displayChar.charAt(0));
-              // }
+
               charOffset = (int) ((charWidth - fmWidth) / 2f);
 
               if (row_annotations[column].colour == null)
@@ -693,10 +680,29 @@ public class AnnotationRenderer
                 gg.setColor(row_annotations[column].colour);
               }
 
+              /*
+               * draw the label, unless it is the same secondary structure
+               * symbol (excluding RNA Helix) as the previous column
+               */
+              final int xPos = (x * charWidth) + charOffset;
+              final int yPos = y + iconOffset;
+
+              /*
+               * translate to drawing position _before_ applying any scaling
+               */
+              gg.translate(xPos, yPos);
+              if (scaledToFit)
+              {
+                /*
+                 * use a scaling transform to make the label narrower
+                 * (JalviewJS doesn't have Font.deriveFont(AffineTransform))
+                 */
+                gg.transform(
+                        AffineTransform.getScaleInstance(fmScaling, 1.0));
+              }
               if (column == 0 || row.graph > 0)
               {
-                gg.drawString(displayChar, (x * charWidth) + charOffset,
-                        y + iconOffset);
+                gg.drawString(displayChar, 0, 0);
               }
               else if (row_annotations[column - 1] == null || (labelAllCols
                       || !displayChar.equals(
@@ -704,11 +710,18 @@ public class AnnotationRenderer
                       || (displayChar.length() < 2
                               && row_annotations[column].secondaryStructure == ' ')))
               {
-                gg.drawString(displayChar, x * charWidth + charOffset,
-                        y + iconOffset);
+                gg.drawString(displayChar, 0, 0);
               }
-              g.setFont(ofont);
-              gg.setTransform(t);
+              if (scaledToFit)
+              {
+                /*
+                 * undo scaling before translating back 
+                 * (restoring saved transform does NOT work in JS PDFGraphics!)
+                 */
+                gg.transform(AffineTransform
+                        .getScaleInstance(1D / fmScaling, 1.0));
+              }
+              gg.translate(-xPos, -yPos);
             }
           }
           if (row.hasIcons)
@@ -1384,7 +1397,7 @@ public class AnnotationRenderer
           boolean isStructureProfile = profl[0] == AlignmentAnnotation.STRUCTURE_PROFILE;
           boolean isCdnaProfile = profl[0] == AlignmentAnnotation.CDNA_PROFILE;
           float ht = normaliseProfile ? y - _aa.graphHeight : y1;
-          double htn = normaliseProfile ? _aa.graphHeight : (y2 - y1);// aa.graphHeight;
+          final double normaliseFactor = normaliseProfile ? _aa.graphHeight : (y2 - y1);
 
           /**
            * Render a single base for a sequence profile, a base pair for
@@ -1436,7 +1449,7 @@ public class AnnotationRenderer
             }
             // next profl[] position is profile % for the character(s)
             
-            double newHeight = htn * scale * profl[c++];
+            double newHeight = normaliseFactor * scale * profl[c++];
 
             /*
              * Set character colour as per alignment colour scheme; use the
@@ -1466,35 +1479,42 @@ public class AnnotationRenderer
             double sy = newHeight / asc;
             double newAsc = asc * sy; 
             double newDec = dec * sy;
-            // it is not necessary to recalculated lm for the new font.
+            // it is not necessary to recalculate lm for the new font.
             // note: lm.getBaselineOffsets()[lm.getBaselineIndex()]) must be 0
             // by definition. Was:
-            // int hght = (int) (ht + (newAsc - newDec - lm.getBaselineOffsets()[lm.getBaselineIndex()]));
-
-            // original:
-
-             if (/** @j2sNative false && */ true) {
-               int hght = (int) (ht + (newAsc - newDec)); // Q: why " - newDec " ? (0,0) is on the font baseline, I think
-               Font font = ofont.deriveFont(AffineTransform.getScaleInstance(sx, sy));
-               g.setFont(font);
-               g.drawChars(dc, 0, dc.length, x * charWidth, hght);
-               ht += newHeight;
-             } else {
-              // SwingJS does not implement font.deriveFont() 
-              // this is off by a very small amount. 
-              int hght2 = (int) (ht2 + newAsc);               
-              Graphics2D gg = (Graphics2D) g.create();
-              gg.setFont(ofont);
+            // int hght = (int) (ht + (newAsc - newDec);
+            // - lm.getBaselineOffsets()[lm.getBaselineIndex()]));
+
+            if (Jalview.isJS())
+            {
+              /*
+               * SwingJS does not implement font.deriveFont()
+               * so use a scaling transform to draw instead,
+               * this is off by a very small amount
+               */
+              final int hght = (int) (ht2 + (newAsc - newDec));
+              Graphics2D gg = (Graphics2D) g;
+              int xShift = (int) Math.round(x * charWidth / sx);
+              int yShift = (int) Math.round(hght / sy);
               gg.transform(AffineTransform.getScaleInstance(sx, sy));
-              //System.out.println("sx " + sx + " sy " + sy + " " + hght + " " + lm.getDescent() + " " + dec + " " + newDec + " " + lm.getAscent() + " " + asc + " " + newAsc);
-              gg.drawString(s, (int) (x * charWidth / sx),
-                      (int) (hght2 / sy));
-              gg.dispose();
+              gg.drawString(s, xShift, yShift);
+              gg.transform(
+                      AffineTransform.getScaleInstance(1D / sx, 1D / sy));
               ht2 += newHeight;
             }
-            
+            else
+            {
+              /*
+               * Java ('normal') method is to scale the font to fit
+               */
+              final int hght = (int) (ht + (newAsc - newDec));
+              Font font = ofont
+                      .deriveFont(AffineTransform.getScaleInstance(sx, sy));
+              g.setFont(font);
+              g.drawChars(dc, 0, dc.length, x * charWidth, hght);
+              ht += newHeight;
+            }
           }
-          g.setFont(ofont);
         }
       }
       x++;