Bug 9031 fixed: Misalignment when using xstring with a matrix 99/13099/2
Calixte DENIZET [Thu, 7 Nov 2013 13:49:29 +0000 (14:49 +0100)]
Change-Id: I8c9883cc217cc1056df5002213d77e4f6c27a651

scilab/CHANGES_5.5.X
scilab/modules/console/src/java/org/scilab/modules/console/utils/ScilabSpecialTextUtilities.java
scilab/modules/graphics/tests/nonreg_tests/bug_9031.tst [new file with mode: 0644]
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextSpriteDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureDrawingTools.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextEntity.java

index 6e25634..dce4e8d 100644 (file)
@@ -47,6 +47,8 @@ Scilab Bug Fixes
 
 * Bug #8337 fixed - mtlb_rand now uses the "uniform" rule, whatever the random rule set is.
 
+* Bug #9031 fixed - Misalignment of text when using xstring with a matrix fixed.
+
 * Bug #9110 fixed - Examples and references to other functions added in the Statistics help pages.
 
 * Bug #9627 fixed - Arguments checking added in optimsimplex_* functions.
index 064c825..8373955 100644 (file)
@@ -63,13 +63,13 @@ public final class ScilabSpecialTextUtilities {
                 icon = compileMathMLExpression(text, component.getFont().getSize());
             }
         }
-        
+
         if (icon == null) {
             // Shortcut when we are sure text is
             // neither Latex nor MathML
             return false;
         }
-        
+
         try {
             setIcon(component, icon);
         } catch (InvocationTargetException e) {
@@ -258,16 +258,17 @@ public final class ScilabSpecialTextUtilities {
             jev.draw(g2d, 0, ascent);
             g2d.dispose();
 
-            return new SpecialIcon(new ImageIcon(bimg));
+            return new SpecialIcon(new ImageIcon(bimg), (int) Math.ceil(jev.getDescentHeight()));
         }
     }
 
     /**
      * Inner class to distinguish normal icons and icons coming from a LaTeX or a MathML compilation
      */
-    private static class SpecialIcon implements Icon {
+    public static class SpecialIcon implements Icon {
 
         Icon icon;
+        int depth;
 
         /**
          * @param icon the Icon to wrap
@@ -277,6 +278,14 @@ public final class ScilabSpecialTextUtilities {
         }
 
         /**
+         * @param icon the Icon to wrap
+         */
+        SpecialIcon(Icon icon, int depth) {
+            this.icon = icon;
+            this.depth = depth;
+        }
+
+        /**
          * {@inheritedDoc}
          */
         public int getIconHeight() {
@@ -290,6 +299,10 @@ public final class ScilabSpecialTextUtilities {
             return icon.getIconWidth();
         }
 
+        public int getIconDepth() {
+            return depth;
+        }
+
         /**
          * {@inheritedDoc}
          */
diff --git a/scilab/modules/graphics/tests/nonreg_tests/bug_9031.tst b/scilab/modules/graphics/tests/nonreg_tests/bug_9031.tst
new file mode 100644 (file)
index 0000000..4edfcf3
--- /dev/null
@@ -0,0 +1,25 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+//
+// <-- INTERACTIVE TEST -->
+//
+// <-- Non-regression test for bug 9031 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/9031
+//
+// <-- Short Description -->
+// Misalignment when using xstring with a matrix
+
+clf();
+
+// Observe that all the string are aligned on the same baseline
+xstring(0.2, 0.5,["$\overbrace{Scilab}$" "n''est ";"pas" "$\underbrace{Matlab}$"])
+xstring(0.2, 0.4, ["|_" , "_"]);
+xstring(0.2, 0.3, ["|-" , "-"]);
+xstring(0.2, 0.2, ["hp" , "a"]);
+xstring(0.2, 0.1,["Scilab" "n''est ";"pas" "Octave"]);
index 6198c89..8631f8d 100644 (file)
@@ -380,7 +380,7 @@ public class LegendDrawer {
         double normSpriteMargin = 0.0;
 
         if (nbValidLinks > 0) {
-            normSpriteMargin = (double) legendSpriteDrawer.getMargin() / (double) canvasHeight;
+            normSpriteMargin = (double) legendSpriteDrawer.getVMargin() / (double) canvasHeight;
         }
 
         lineVertexData[0] = (float) (legendCorner[0] + xOffset);
index c1acffd..91fe1a4 100644 (file)
@@ -91,15 +91,22 @@ class TextSpriteDrawer extends TextObjectSpriteDrawer implements TextureDrawer {
     /**
      * Returns the margin modified by the scale factor.
      */
-    public int getMargin() {
-        return (int)(scaleFactor * (double)super.getMargin());
+    public int getHMargin() {
+        return (int)(scaleFactor * (double) super.getHMargin());
+    }
+
+    /**
+     * Returns the margin modified by the scale factor.
+     */
+    public int getVMargin() {
+        return (int)(scaleFactor * (double) super.getVMargin());
     }
 
     /**
      * Returns the space width modified by the scale factor.
      */
     public int getSpaceWidth() {
-        return (int)(scaleFactor * (double)super.getSpaceWidth());
+        return (int)(scaleFactor * (double) super.getSpaceWidth());
     }
 
 }
index c407124..b4b0bd5 100644 (file)
@@ -14,11 +14,14 @@ package org.scilab.modules.renderer.JoGLView.util;
 
 import java.awt.Dimension;
 import java.awt.Font;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
 
 import javax.swing.Icon;
 
 import org.scilab.forge.jlatexmath.TeXConstants;
 import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
 import org.scilab.forge.scirenderer.shapes.appearance.Color;
 import org.scilab.forge.scirenderer.texture.TextEntity;
@@ -40,16 +43,18 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
     /**
      * Scilab text margin.
      */
-    private static final int MARGIN = 2;
+    private static final int HMARGIN = 2;
+    private static final int VMARGIN = 2;
+    private static final int SPACEWIDTH = (int) Math.ceil(new TextEntity("_").getSize().getWidth()) - 2;
 
     private Appearance appearance;
     private int thickness;
     private final Object[][] entities;
     private float alignmentFactor;
-    private final int spaceWidth;
 
     private final int[] lineHeight;
     private final int[] columnWidth;
+    private final float[] lineAscent;
 
     private final int width;
     private final int height;
@@ -60,8 +65,6 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
      * @param textObject the scilab {@see Text} to draw.
      */
     public TextObjectSpriteDrawer(final ColorMap colorMap, final TextObject textObject) {
-        this.spaceWidth = computeSpaceWidth();
-
         String[][] stringArray = computeTextData(textObject);
         int columnNumber = -1;
         for (String[] stringLine : stringArray) {
@@ -70,6 +73,7 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
         int lineNumber = stringArray.length;
 
         this.lineHeight = new int[lineNumber];
+        this.lineAscent = new float[lineNumber];
         this.columnWidth = new int[columnNumber];
         this.entities = new Object[columnNumber][lineNumber];
 
@@ -79,8 +83,8 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
 
         fillEntityMatrix(stringArray, fractionalFont, textColor, font);
 
-        this.width  = sum(columnWidth) + MARGIN * (columnNumber + 1) + 2 * thickness + spaceWidth * (columnNumber - 1);
-        this.height = sum(lineHeight)  + MARGIN * (lineNumber + 1) + 2 * thickness;
+        this.width  = sum(columnWidth) + HMARGIN * (columnNumber + 1) + 2 * thickness + SPACEWIDTH * (columnNumber - 1);
+        this.height = sum(lineHeight)  + VMARGIN * (lineNumber + 1) + 2 * thickness;
     }
 
     /**
@@ -91,8 +95,6 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
      * @param scaleFactor the scale factor to apply.
      */
     public TextObjectSpriteDrawer(final ColorMap colorMap, final TextObject textObject, double scaleFactor) {
-        this.spaceWidth = computeSpaceWidth();
-
         String[][] stringArray = computeTextData(textObject);
         int columnNumber = -1;
         for (String[] stringLine : stringArray) {
@@ -101,6 +103,7 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
         int lineNumber = stringArray.length;
 
         this.lineHeight = new int[lineNumber];
+        this.lineAscent = new float[lineNumber];
         this.columnWidth = new int[columnNumber];
         this.entities = new Object[columnNumber][lineNumber];
 
@@ -111,8 +114,8 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
         /* Fill the entity matrix */
         fillEntityMatrix(stringArray, fractionalFont, textColor, font);
 
-        this.width  = (int)((double)sum(columnWidth) + scaleFactor * (double)(MARGIN * (columnNumber + 1)) + 2 * thickness + scaleFactor * (double)(spaceWidth * (columnNumber - 1)));
-        this.height = (int)((double)sum(lineHeight)  + scaleFactor * (double)(MARGIN * (lineNumber + 1)) + 2 * thickness);
+        this.width  = (int)((double)sum(columnWidth) + scaleFactor * (double)(HMARGIN * (columnNumber + 1)) + 2 * thickness + scaleFactor * (double)(SPACEWIDTH * (columnNumber - 1)));
+        this.height = (int)((double)sum(lineHeight)  + scaleFactor * (double)(VMARGIN * (lineNumber + 1)) + 2 * thickness);
     }
 
     /**
@@ -130,17 +133,21 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
                 if (text != null) {
                     Dimension dimension = null;
                     Icon icon = null;
+                    float ascent = 0;
                     if (isLatex(text)) {
                         LoadClassPath.loadOnUse("graphics_latex_textrendering");
                         try {
                             TeXFormula formula = new TeXFormula(text.substring(1, text.length() - 1));
                             formula.setColor(textColor);
                             icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, font.getSize());
+                            ascent = ((TeXIcon) icon).getIconHeight() - ((TeXIcon) icon).getIconDepth();
                         } catch (Exception e) { }
                     } else if (isMathML(text)) {
                         LoadClassPath.loadOnUse("graphics_mathml_textrendering");
                         try {
                             icon = ScilabSpecialTextUtilities.compileMathMLExpression(text, font.getSize(), textColor);
+                            ScilabSpecialTextUtilities.SpecialIcon si = (ScilabSpecialTextUtilities.SpecialIcon) icon;
+                            ascent = si.getIconHeight() - si.getIconDepth();
                         } catch (Exception e) { }
                     }
 
@@ -155,8 +162,11 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
                         textEntity.setFont(font);
                         entities[column][line] = textEntity;
                         dimension = textEntity.getSize();
+                        ascent = textEntity.getLayout().getAscent();
                     }
 
+                    lineAscent[line] = Math.max(lineAscent[line], ascent);
+
                     if (dimension != null) {
                         columnWidth[column] = Math.max(columnWidth[column], dimension.width);
                         lineHeight[line] = Math.max(lineHeight[line], dimension.height);
@@ -193,33 +203,44 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
             drawingTools.clear(appearance.getFillColor());
         }
 
-        int currentMargin = getMargin();
-        int currentSpaceWidth = getSpaceWidth();
+        final int currentHMargin = getHMargin();
+        final int currentVMargin = getVMargin();
+        final int currentSpaceWidth = getSpaceWidth();
 
         // Draw text.
-        int x = currentMargin + thickness;
+        int x = currentHMargin + thickness;
         int column = 0;
         for (Object[] entitiesLine : entities) {
-            int y = currentMargin + thickness;
+            int y = currentVMargin + thickness;
             int line = 0;
             for (Object entity : entitiesLine) {
                 if (entity != null) {
                     if (entity instanceof TextEntity) {
                         TextEntity textEntity = (TextEntity) entity;
+                        TextLayout layout = textEntity.getLayout();
                         double deltaX = alignmentFactor * (columnWidth[column] - textEntity.getSize().getWidth());
-                        drawingTools.draw(textEntity, (int) (x + deltaX), y);
-                        y += lineHeight[line] + currentMargin;
+                        drawingTools.draw(textEntity, (int) (x + deltaX), Math.round(y - layout.getAscent() + lineAscent[line]));
+                        y += lineHeight[line] + currentVMargin;
                         line++;
                     } else if (entity instanceof Icon) {
                         Icon icon = (Icon) entity;
                         double deltaX = alignmentFactor * (columnWidth[column] - icon.getIconWidth());
-                        drawingTools.draw(icon, (int) (x + deltaX), y);
-                        y += lineHeight[line] + currentMargin;
+                        if (icon instanceof TeXIcon) {
+                            TeXIcon tex = (TeXIcon) icon;
+                            float ascent = tex.getIconHeight() - tex.getIconDepth();
+                            drawingTools.draw(icon, (int) (x + deltaX), Math.round(y - ascent + lineAscent[line]));
+                        } else {
+                            // MathML
+                            ScilabSpecialTextUtilities.SpecialIcon si = (ScilabSpecialTextUtilities.SpecialIcon) icon;
+                            int ascent = si.getIconHeight() - si.getIconDepth();
+                            drawingTools.draw(icon, (int) (x + deltaX), y - ascent + Math.round(lineAscent[line]));
+                        }
+                        y += lineHeight[line] + currentVMargin;
                         line++;
                     }
                 }
             }
-            x += columnWidth[column] + currentMargin + currentSpaceWidth;
+            x += columnWidth[column] + currentHMargin + currentSpaceWidth;
             column++;
         }
 
@@ -272,12 +293,16 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
         this.thickness = thickness;
     }
 
-    public int getMargin() {
-        return MARGIN;
+    public int getHMargin() {
+        return HMARGIN;
+    }
+
+    public int getVMargin() {
+        return VMARGIN;
     }
 
     public int getSpaceWidth() {
-        return spaceWidth;
+        return SPACEWIDTH;
     }
 
     /**
@@ -316,7 +341,7 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
      * @return the {@see Font} adapted to the given Scilab text.
      */
     private Font computeFont(final TextObject text, double scaleFactor) {
-        Font font  = FontManager.getSciFontManager().getFontFromIndex(text.getFontStyle(), 1.0);
+        Font font = FontManager.getSciFontManager().getFontFromIndex(text.getFontStyle(), 1.0);
         return font.deriveFont(font.getSize2D() * (float)scaleFactor);
     }
 
@@ -339,15 +364,6 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
     }
 
     /**
-     * Compute and return the width of the space character.
-     * @return the width of the space character.
-     */
-    private int computeSpaceWidth() {
-        TextEntity spaceText = new TextEntity("_");
-        return (int) Math.ceil(spaceText.getSize().getWidth());
-    }
-
-    /**
      * Util function.
      * Return sum of the element of the given array.
      * @param values the given array.
index af211b7..f1a187a 100644 (file)
@@ -190,7 +190,7 @@ public class G2DTextureDrawingTools implements TextureDrawingTools {
             TextLayout textLayout = new TextLayout(textEntity.getText(), textEntity.getFont(), g2d.getFontRenderContext());
             Rectangle2D bounds = textLayout.getBounds();
             g2d.setFont(textEntity.getFont());
-            g2d.drawString(textEntity.getText(), (float) (x - bounds.getX()), (float) (y - bounds.getY()));
+            g2d.drawString(textEntity.getText(), (float) (x - bounds.getX()), (float) (y + textLayout.getAscent()));
         }
     }
 
index 92d3dd3..e225f18 100644 (file)
@@ -173,7 +173,7 @@ public class BufferedImageTextureDrawingTools implements TextureDrawingTools {
             g2d.setColor(textEntity.getTextColor());
             TextLayout textLayout = new TextLayout(textEntity.getText(), textEntity.getFont(), g2d.getFontRenderContext());
             Rectangle2D bounds = textLayout.getBounds();
-            textLayout.draw(g2d, (float) (x + 1 - bounds.getX()), (float) (y + 1 - bounds.getY()));
+            textLayout.draw(g2d, (float) (x + 1 - bounds.getX()), (float) (y + textLayout.getAscent()));
         }
     }
 
index 9aeaece..21df6e2 100644 (file)
@@ -69,6 +69,8 @@ public class TextEntity {
      */
     private Font font;
 
+    private TextLayout layout;
+
     /**
      * Default constructor.
      * @param text the text content.
@@ -92,6 +94,7 @@ public class TextEntity {
      */
     public void setText(String text) {
         this.text = text;
+        this.layout = null;
     }
 
     /**
@@ -108,6 +111,7 @@ public class TextEntity {
      */
     public void setFont(Font font) {
         this.font = font;
+        this.layout = null;
     }
 
     /**
@@ -140,6 +144,7 @@ public class TextEntity {
      */
     public void setTextAntiAliased(boolean textAntiAliased) {
         this.textAntiAliased = textAntiAliased;
+        this.layout = null;
     }
 
     /**
@@ -156,6 +161,7 @@ public class TextEntity {
      */
     public void setTextUseFractionalMetrics(boolean textUseFractionalMetrics) {
         this.textUseFractionalMetrics = textUseFractionalMetrics;
+        this.layout = null;
     }
 
     /**
@@ -169,18 +175,26 @@ public class TextEntity {
                );
     }
 
+    public TextLayout getLayout() {
+        if (layout == null) {
+            FontRenderContext frc = new FontRenderContext(null, isTextAntiAliased(), isTextUseFractionalMetrics());
+            layout = new TextLayout(getText(), getFont(), frc);
+        }
+
+        return layout;
+    }
+
     /**
      * Return the dimension in pixel of the text entity.
      * @return the dimension in pixel of the text entity.
      */
     public Dimension getSize() {
         if (isValid()) {
-            FontRenderContext frc = new FontRenderContext(null, isTextAntiAliased(), isTextUseFractionalMetrics());
-            TextLayout textLayout = new TextLayout(getText(), getFont(), frc);
+            TextLayout textLayout = getLayout();
             Dimension dimension = new Dimension();
             Rectangle2D r = textLayout.getBounds();
             /* +1 added to fix rendering of ticks labels, a pixel row/column was missing */
-            dimension.setSize(r.getWidth() + 2, r.getHeight() + 1);
+            dimension.setSize(r.getWidth() + 2, textLayout.getAscent() + textLayout.getDescent() + 1);
             return dimension;
         } else {
             return new Dimension(0, 0);