JAL-3079 JAL-3055 remember to reset font transform after rendering logo
[jalview.git] / src / jalview / renderer / AnnotationRenderer.java
index 0aeb45a..deb2b6f 100644 (file)
@@ -25,7 +25,6 @@ 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;
@@ -68,7 +67,7 @@ public class AnnotationRenderer
 
   private FontMetrics fm;
 
-  private final boolean MAC = Platform.isAMac();
+  private final boolean USE_FILL_ROUND_RECT = Platform.isAMacAndNotJS();
 
   boolean av_renderHistogram = true, av_renderProfile = true,
           av_normaliseProfile = false;
@@ -81,9 +80,9 @@ public class AnnotationRenderer
 
   private ProfilesI hconsensus;
 
-  private Hashtable[] complementConsensus;
+  private Hashtable<String, Object>[] complementConsensus;
 
-  private Hashtable[] hStrucConsensus;
+  private Hashtable<String, Object>[] hStrucConsensus;
 
   private boolean av_ignoreGapsConsensus;
 
@@ -150,6 +149,7 @@ public class AnnotationRenderer
    */
   public void dispose()
   {
+    hiddenColumns = null;
     hconsensus = null;
     complementConsensus = null;
     hStrucConsensus = null;
@@ -417,8 +417,6 @@ public class AnnotationRenderer
     return null;
   }
 
-  boolean rna = false;
-
   /**
    * Render the annotation rows associated with an alignment.
    * 
@@ -449,7 +447,7 @@ public class AnnotationRenderer
     updateFromAwtRenderPanel(annotPanel, av);
     fm = g.getFontMetrics();
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
-    int temp = 0;
+    // int temp = 0;
     if (aa == null)
     {
       return false;
@@ -462,8 +460,8 @@ public class AnnotationRenderer
     boolean validRes = false;
     boolean validEnd = false;
     boolean labelAllCols = false;
-    boolean centreColLabels;
-    boolean centreColLabelsDef = av.isCentreColumnLabels();
+//    boolean centreColLabels;
+//    boolean centreColLabelsDef = av.isCentreColumnLabels();
     boolean scaleColLabel = false;
     final AlignmentAnnotation consensusAnnot = av
             .getAlignmentConsensusAnnotation();
@@ -471,8 +469,6 @@ public class AnnotationRenderer
             .getAlignmentStrucConsensusAnnotation();
     final AlignmentAnnotation complementConsensusAnnot = av
             .getComplementConsensusAnnotation();
-    boolean renderHistogram = true, renderProfile = true,
-            normaliseProfile = false, isRNA = rna;
 
     BitSet graphGroupDrawn = new BitSet();
     int charOffset = 0; // offset for a label
@@ -483,38 +479,35 @@ public class AnnotationRenderer
     for (int i = 0; i < aa.length; i++)
     {
       AlignmentAnnotation row = aa[i];
-      isRNA = row.isRNA();
+      boolean renderHistogram = true;
+      boolean renderProfile = false;
+      boolean normaliseProfile = false;
+      boolean isRNA = row.isRNA();
+
+      // check if this is a consensus annotation row and set the display
+      // settings appropriately
+      // TODO: generalise this to have render styles for consensus/profile
+      // data
+      if (row.groupRef != null && row == row.groupRef.getConsensus())
       {
-        // check if this is a consensus annotation row and set the display
-        // settings appropriately
-        // TODO: generalise this to have render styles for consensus/profile
-        // data
-        if (row.groupRef != null && row == row.groupRef.getConsensus())
-        {
-          renderHistogram = row.groupRef.isShowConsensusHistogram();
-          renderProfile = row.groupRef.isShowSequenceLogo();
-          normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
-        }
-        else if (row == consensusAnnot || row == structConsensusAnnot
-                || row == complementConsensusAnnot)
-        {
-          renderHistogram = av_renderHistogram;
-          renderProfile = av_renderProfile;
-          normaliseProfile = av_normaliseProfile;
-        }
-        else
-        {
-          renderHistogram = true;
-          // don't need to set render/normaliseProfile since they are not
-          // currently used in any other annotation track renderer
-        }
+        renderHistogram = row.groupRef.isShowConsensusHistogram();
+        renderProfile = row.groupRef.isShowSequenceLogo();
+        normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
+      }
+      else if (row == consensusAnnot || row == structConsensusAnnot
+              || row == complementConsensusAnnot)
+      {
+        renderHistogram = av_renderHistogram;
+        renderProfile = av_renderProfile;
+        normaliseProfile = av_normaliseProfile;
       }
+
       Annotation[] row_annotations = row.annotations;
       if (!row.visible)
       {
         continue;
       }
-      centreColLabels = row.centreColLabels || centreColLabelsDef;
+//      centreColLabels = row.centreColLabels || centreColLabelsDef;
       labelAllCols = row.showAllColLabels;
       scaleColLabel = row.scaleColLabel;
       lastSS = ' ';
@@ -651,7 +644,6 @@ public class AnnotationRenderer
                     && (displayChar.length() > 0))
             {
               Graphics2D gg = ((Graphics2D) g);
-              AffineTransform oldTransform = gg.getTransform();
               float fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
                       displayChar.length());
 
@@ -687,6 +679,10 @@ public class AnnotationRenderer
                */
               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)
               {
@@ -709,8 +705,16 @@ public class AnnotationRenderer
               {
                 gg.drawString(displayChar, 0, 0);
               }
+              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);
-              gg.setTransform(oldTransform);
             }
           }
           if (row.hasIcons)
@@ -771,7 +775,7 @@ public class AnnotationRenderer
               if (x > -1)
               {
 
-                int nb_annot = x - temp;
+                // int nb_annot = x - temp;
                 // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre
                 // annot :"+nb_annot);
                 switch (lastSS)
@@ -780,7 +784,7 @@ public class AnnotationRenderer
                 case ')': // and opposite direction
                   drawStemAnnot(g, row_annotations, lastSSX, x, y,
                           iconOffset, startRes, column, validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
 
                 case 'H':
@@ -863,13 +867,13 @@ public class AnnotationRenderer
                   drawNotCanonicalAnnot(g, nonCanColor, row_annotations,
                           lastSSX, x, y, iconOffset, startRes, column,
                           validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
                 default:
                   g.setColor(Color.gray);
                   g.fillRect(lastSSX, y + 6 + iconOffset,
                           (x * charWidth) - lastSSX, 2);
-                  temp = x;
+                  // temp = x;
                   break;
                 }
               }
@@ -1110,7 +1114,7 @@ public class AnnotationRenderer
 
   public static final Color STEM_COLOUR = Color.blue;
 
-  private Color sdNOTCANONICAL_COLOUR;
+  // private Color sdNOTCANONICAL_COLOUR;
 
   void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
           int y, int iconOffset, int startRes, int column, boolean validRes,
@@ -1158,7 +1162,7 @@ public class AnnotationRenderer
     int x1 = lastSSX;
     int x2 = (x * charWidth);
 
-    if (MAC)
+    if (USE_FILL_ROUND_RECT)
     {
       int ofs = charWidth / 2;
       // Off by 1 offset when drawing rects and ovals
@@ -1386,7 +1390,8 @@ 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
@@ -1437,8 +1442,14 @@ public class AnnotationRenderer
               s = new String(dc);
             }
             // next profl[] position is profile % for the character(s)
-            
-            double newHeight = htn * scale * profl[c++];
+
+            int percent = profl[c++];
+            if (percent == 0)
+            {
+              // failsafe in case a count rounds down to 0%
+              continue;
+            }
+            double newHeight = normaliseFactor * scale * percent;
 
             /*
              * Set character colour as per alignment colour scheme; use the
@@ -1464,9 +1475,9 @@ public class AnnotationRenderer
             // (int)(scl));
             // g.setColor(profcolour.findColour(dc[0]).darker());
 
-            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);            
+            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);
             double sy = newHeight / asc;
-            double newAsc = asc * sy; 
+            double newAsc = asc * sy;
             double newDec = dec * sy;
             // it is not necessary to recalculate lm for the new font.
             // note: lm.getBaselineOffsets()[lm.getBaselineIndex()]) must be 0
@@ -1474,7 +1485,7 @@ public class AnnotationRenderer
             // int hght = (int) (ht + (newAsc - newDec);
             // - lm.getBaselineOffsets()[lm.getBaselineIndex()]));
 
-            if (Jalview.isJS())
+            if (Platform.isJS())
             {
               /*
                * SwingJS does not implement font.deriveFont()
@@ -1482,26 +1493,34 @@ public class AnnotationRenderer
                * this is off by a very small amount
                */
               final int hght = (int) (ht2 + (newAsc - newDec));
-              Graphics2D gg = (Graphics2D) g.create();
-              gg.setFont(ofont);
-              int xShift = (int) (x * charWidth / sx);
-              int yShift = (int) (hght / sy);
+              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));
               gg.drawString(s, xShift, yShift);
-              gg.dispose();
+              gg.transform(
+                      AffineTransform.getScaleInstance(1D / sx, 1D / sy));
               ht2 += newHeight;
             }
             else
+            /**
+             * Java only
+             * 
+             * @j2sIgnore
+             */
             {
+              // 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);
+              g.setFont(ofont);
+
               ht += newHeight;
             }
           }
-          g.setFont(ofont);
         }
       }
       x++;
@@ -1512,7 +1531,7 @@ public class AnnotationRenderer
       Graphics2D g2 = (Graphics2D) g;
       g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
               BasicStroke.JOIN_ROUND, 3f, new float[]
-      { 5f, 3f }, 0f));
+              { 5f, 3f }, 0f));
 
       y2 = (int) (y
               - ((_aa.threshold.value - min) / range) * _aa.graphHeight);