]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2391: fix NSM reordering issue and ensure same PDF output as XSL-FO code path...
authorGlenn Adams <gadams@apache.org>
Sat, 20 Sep 2014 19:02:18 +0000 (19:02 +0000)
committerGlenn Adams <gadams@apache.org>
Sat, 20 Sep 2014 19:02:18 +0000 (19:02 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1626491 13f79535-47bb-0310-9956-ffa450edef68

lib/batik-all-trunk.jar
src/java/org/apache/fop/fonts/Font.java
src/java/org/apache/fop/fonts/FontMetrics.java
src/java/org/apache/fop/svg/NativeTextPainter.java
src/java/org/apache/fop/svg/PDFTextPainter.java
src/java/org/apache/fop/svg/font/ComplexGlyphVector.java
src/java/org/apache/fop/svg/font/FOPGVTFont.java
src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java
src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java

index cdf42316465b30d276d6e69c48b4acd59d70da22..5aac032d7074af1267334b97ae62338db035364e 100644 (file)
Binary files a/lib/batik-all-trunk.jar and b/lib/batik-all-trunk.jar differ
index 305e8f78a563e1c8fe536afdde71550786cc5943..399be056a65bd8dcc0a13c28fa62b4e66981000b 100644 (file)
@@ -102,6 +102,14 @@ public class Font implements Substitutable, Positionable {
         return this.metric;
     }
 
+    /**
+     * Determines whether the font is a multibyte font.
+     * @return True if it is multibyte
+     */
+    public boolean isMultiByte() {
+        return getFontMetrics().isMultiByte();
+    }
+
     /**
      * Returns the font's ascender.
      * @return the ascender
index 4b1fb1f1f16103426f642de26bb4254c5a52cdfd..ce00e34b9c7ddf3b06f4be5cfe7552df7b25a42e 100644 (file)
@@ -190,4 +190,11 @@ public interface FontMetrics {
      * @return true if feature supported (and has at least one lookup)
      */
     boolean hasFeature(int tableType, String script, String language, String feature);
+
+    /**
+     * Determines whether the font is a multibyte font.
+     * @return True if it is multibyte
+     */
+    boolean isMultiByte();
+
 }
index 18c140163868c1aa61811ccd1c1175bb850d14bd..cb96368c80462a8900905da8bbefb542d4bd1f69 100644 (file)
@@ -51,6 +51,7 @@ import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
 import org.apache.fop.svg.font.FOPGVTFont;
+import org.apache.fop.svg.font.FOPGVTGlyphVector;
 import org.apache.fop.svg.text.BidiAttributedCharacterIterator;
 import org.apache.fop.svg.text.ComplexGlyphLayout;
 import org.apache.fop.util.CharUtilities;
@@ -64,8 +65,6 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
     /** the logger for this class */
     protected static final Log log = LogFactory.getLog(NativeTextPainter.class);
 
-    private static final boolean DEBUG = false;
-
     /** the font collection */
     protected final FontInfo fontInfo;
 
@@ -99,9 +98,9 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
      * @throws IOException if an I/O error occurs while rendering the text
      */
     protected final void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException {
+        logTextRun(textRun);
         AttributedCharacterIterator runaci = textRun.getACI();
         runaci.first();
-
         tpi = (TextPaintInfo) runaci.getAttribute(PAINT_INFO);
         if (tpi == null || !tpi.visible) {
             return;
@@ -109,36 +108,36 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
         if (tpi.composite != null) {
             g2d.setComposite(tpi.composite);
         }
-
-        //------------------------------------
         TextSpanLayout layout = textRun.getLayout();
-        logTextRun(runaci, layout);
-        runaci.first(); //Reset ACI
-
-        GeneralPath debugShapes = null;
-        if (DEBUG) {
-            debugShapes = new GeneralPath();
-        }
-
-        preparePainting(g2d);
-
         GVTGlyphVector gv = layout.getGlyphVector();
         if (!(gv.getFont() instanceof FOPGVTFont)) {
             assert gv.getFont() == null || gv.getFont() instanceof SVGGVTFont;
             //Draw using Java2D when no native fonts are available
             textRun.getLayout().draw(g2d);
             return;
+        } else {
+            GeneralPath debugShapes = log.isDebugEnabled() ? new GeneralPath() : null;
+            preparePainting(g2d);
+            saveGraphicsState();
+            setInitialTransform(g2d.getTransform());
+            clip(g2d.getClip());
+            beginTextObject();
+            writeGlyphs((FOPGVTGlyphVector) gv, debugShapes);
+            endTextObject();
+            restoreGraphicsState();
+            if (debugShapes != null) {
+                g2d.setStroke(new BasicStroke(0));
+                g2d.setColor(Color.LIGHT_GRAY);
+                g2d.draw(debugShapes);
+            }
         }
-        font = ((FOPGVTFont) gv.getFont()).getFont();
-
-        saveGraphicsState();
-        setInitialTransform(g2d.getTransform());
-        clip(g2d.getClip());
-        beginTextObject();
+    }
 
+    protected void writeGlyphs(FOPGVTGlyphVector gv, GeneralPath debugShapes) throws IOException {
         AffineTransform localTransform = new AffineTransform();
         Point2D prevPos = null;
         AffineTransform prevGlyphTransform = null;
+        font = ((FOPGVTFont) gv.getFont()).getFont();
         for (int index = 0, c = gv.getNumGlyphs(); index < c; index++) {
             if (!gv.isGlyphVisible(index)) {
                 continue;
@@ -149,7 +148,7 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
             if (log.isTraceEnabled()) {
                 log.trace("pos " + glyphPos + ", transform " + glyphTransform);
             }
-            if (DEBUG) {
+            if (debugShapes != null) {
                 Shape sh = gv.getGlyphLogicalBounds(index);
                 if (sh == null) {
                     sh = new Ellipse2D.Double(glyphPos.getX(), glyphPos.getY(), 2, 2);
@@ -173,14 +172,6 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
 
             writeGlyph(glyph, localTransform);
         }
-        endTextObject();
-        restoreGraphicsState();
-        if (DEBUG) {
-            //Paint debug shapes
-            g2d.setStroke(new BasicStroke(0));
-            g2d.setColor(Color.LIGHT_GRAY);
-            g2d.draw(debugShapes);
-        }
     }
 
     @Override
@@ -348,7 +339,10 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
      * @param runaci an attributed character iterator
      * @param layout a text span layout
      */
-    protected final void logTextRun(AttributedCharacterIterator runaci, TextSpanLayout layout) {
+    protected final void logTextRun(TextRun textRun) {
+        AttributedCharacterIterator runaci = textRun.getACI();
+        TextSpanLayout layout = textRun.getLayout();
+        runaci.first();
         if (log.isTraceEnabled()) {
             int charCount = runaci.getEndIndex() - runaci.getBeginIndex();
             log.trace("================================================");
index c5fa9f04e20ba0c66d683aa58daf232b2627aa26..0320438f8d5ff09272c480a6a2d01d96e0a587c4 100644 (file)
@@ -25,11 +25,16 @@ import java.awt.Paint;
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
+import java.io.IOException;
 
 import org.apache.batik.gvt.text.TextPaintInfo;
 
+import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.svg.font.FOPGVTFont;
+import org.apache.fop.svg.font.FOPGVTGlyphVector;
 
 /**
  * Renders the attributed character iterator of a {@link org.apache.batik.gvt.TextNode}.
@@ -104,6 +109,46 @@ class PDFTextPainter extends NativeTextPainter {
         pdf.writeClip(clip);
     }
 
+    private static int[] paZero = new int[4];
+
+    protected void writeGlyphs(FOPGVTGlyphVector gv, GeneralPath debugShapes) throws IOException {
+        if (gv.getGlyphPositionAdjustments() == null) {
+            super.writeGlyphs(gv, debugShapes);
+        } else {
+            FOPGVTFont gvtFont = (FOPGVTFont) gv.getFont();
+            String fk = gvtFont.getFontKey();
+            Font f = gvtFont.getFont();
+            Point2D initialPos = gv.getGlyphPosition(0);
+            if (f.isMultiByte()) {
+                int         fs              = f.getFontSize();
+                float       fsPoints        = fs / 1000f;
+                double      xc              = 0f;
+                double      yc              = 0f;
+                double      xoLast          = 0f;
+                double      yoLast          = 0f;
+                textUtil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, initialPos.getX(), initialPos.getY()));
+                textUtil.updateTf(fk, fsPoints, true);
+                int[][] dp = gv.getGlyphPositionAdjustments();
+                for (int i = 0, n = gv.getNumGlyphs(); i < n; i++) {
+                    int     gc              = gv.getGlyphCode(i);
+                    int[]   pa              = ((i > dp.length) || (dp[i] == null)) ? paZero : dp[i];
+                    double  xo              = xc + pa[0];
+                    double  yo              = yc + pa[1];
+                    double  xa              = f.getWidth(gc);
+                    double  ya              = 0;
+                    double  xd              = (xo - xoLast) / 1000f;
+                    double  yd              = (yo - yoLast) / 1000f;
+                    textUtil.writeTd(xd, yd);
+                    textUtil.writeTj((char) gc);
+                    xc += xa + pa[2];
+                    yc += ya + pa[3];
+                    xoLast = xo;
+                    yoLast = yo;
+                }
+            }
+        }
+    }
+
     @Override
     protected void beginTextObject() {
         applyColorAndPaint(tpi);
index 8fa705e4cea68c394747c599281e75ced7f1b4ed..567f9726a1b55a714f20701943e9bc7e4f8aa1be 100644 (file)
@@ -64,6 +64,9 @@ class ComplexGlyphVector extends FOPGVTGlyphVector {
                     if (associations != null) {
                         Collections.reverse(associations);
                     }
+                    if (gposAdjustments != null) {
+                        reverse(gposAdjustments);
+                    }
                     if (positions != null) {
                         reverse(positions);
                     }
@@ -139,6 +142,15 @@ class ComplexGlyphVector extends FOPGVTGlyphVector {
         }
     }
 
+    private static void reverse(int[][] iaa) {
+        for (int i = 0, n = iaa.length, m = n / 2; i < m; i++) {
+            int k = n - i - 1;
+            int[] t = iaa [ k ];
+            iaa [ k ] = iaa [ i ];
+            iaa [ i ] = t;
+        }
+    }
+
     private static void reverse(float[] fa) {
         int skip = 2;
         int numPositions = fa.length / skip;
@@ -153,8 +165,12 @@ class ComplexGlyphVector extends FOPGVTGlyphVector {
             }
         }
         float runAdvanceX = fa [ 0 ];
-        for (int i = 0, n = fa.length; i < n; i += 2) {
-            fa [ i ] = runAdvanceX - fa [ i ];
+        for (int i = 0, n = numPositions; i < n; ++i) {
+            int k = i * 2;
+            fa [ k + 0 ] = runAdvanceX - fa [ k + 0 ];
+            if (i > 0) {
+                fa [ k - 1 ] = fa [ k + 1 ];
+            }
         }
     }
 
index 76f77d367101c697c4782f1a435fbe2067687ee7..fd92e36bcdb14a9027ac3184489c114a95c5a695 100644 (file)
@@ -31,7 +31,9 @@ import org.apache.batik.gvt.font.GVTLineMetrics;
 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
 
 import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.fonts.FontTriplet;
 
 public class FOPGVTFont implements GVTFont {
 
@@ -122,6 +124,18 @@ public class FOPGVTFont implements GVTFont {
         throw new UnsupportedOperationException("Not implemented");
     }
 
+    public FontInfo getFontInfo() {
+        return ((FOPGVTFontFamily) fontFamily).getFontInfo();
+    }
+
+    public String getFontKey() {
+        return ((FOPGVTFontFamily) fontFamily).getFontKey();
+    }
+
+    public FontTriplet getFontTriplet() {
+        return ((FOPGVTFontFamily) fontFamily).getFontTriplet();
+    }
+
     public String getFamilyName() {
         return fontFamily.getFamilyName();
     }
index 5be9419d388c34d79774984e3913f862f61b1db2..b9351af44e96263e59fea934d455f68c91012e8d 100644 (file)
@@ -47,6 +47,18 @@ public class FOPGVTFontFamily implements GVTFontFamily {
         this.fontFace = fontFace;
     }
 
+    public FontInfo getFontInfo() {
+        return fontInfo;
+    }
+
+    public FontTriplet getFontTriplet() {
+        return fontTriplet;
+    }
+
+    public String getFontKey() {
+        return fontInfo.getInternalFontKey(fontTriplet);
+    }
+
     public String getFamilyName() {
         return familyName;
     }
index 2b2115935d747a103fcce3e220c3d7f5c7580595..77bdec48d415039e85795ffa8827333a59026837 100644 (file)
@@ -47,7 +47,7 @@ import org.apache.fop.fonts.GlyphMapping;
 import org.apache.fop.fonts.TextFragment;
 import org.apache.fop.traits.MinOptMax;
 
-class FOPGVTGlyphVector implements GVTGlyphVector {
+public class FOPGVTGlyphVector implements GVTGlyphVector {
 
     protected final TextFragment text;
 
@@ -63,6 +63,8 @@ class FOPGVTGlyphVector implements GVTGlyphVector {
 
     protected List associations;
 
+    protected int[][] gposAdjustments;
+
     protected float[] positions;
 
     protected Rectangle2D[] boundingBoxes;
@@ -94,6 +96,7 @@ class FOPGVTGlyphVector implements GVTGlyphVector {
             mapping.mapping != null ? new StringCharacterIterator(mapping.mapping) : text.getIterator();
         this.glyphs = buildGlyphs(f, glyphAsCharIter);
         this.associations = mapping.associations;
+        this.gposAdjustments = mapping.gposAdjustments;
         this.positions = buildGlyphPositions(glyphAsCharIter, mapping.gposAdjustments, letterSpaceAdjustments);
         this.glyphVisibilities = new boolean[this.glyphs.length];
         Arrays.fill(glyphVisibilities, true);
@@ -304,6 +307,10 @@ class FOPGVTGlyphVector implements GVTGlyphVector {
         throw new UnsupportedOperationException();
     }
 
+    public int[][] getGlyphPositionAdjustments() {
+        return gposAdjustments;
+    }
+
     public Point2D getGlyphPosition(int glyphIndex) {
         int positionIndex = glyphIndex * 2;
         return new Point2D.Float(positions[positionIndex], positions[positionIndex + 1]);