Browse Source

FOP-2391: fix NSM reordering issue and ensure same PDF output as XSL-FO code path (using Td/Tj operators)

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1626491 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Glenn Adams 9 years ago
parent
commit
ec1da9e25c

BIN
lib/batik-all-trunk.jar View File


+ 8
- 0
src/java/org/apache/fop/fonts/Font.java View 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

+ 7
- 0
src/java/org/apache/fop/fonts/FontMetrics.java View 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();

}

+ 25
- 31
src/java/org/apache/fop/svg/NativeTextPainter.java View 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("================================================");

+ 45
- 0
src/java/org/apache/fop/svg/PDFTextPainter.java View 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);

+ 18
- 2
src/java/org/apache/fop/svg/font/ComplexGlyphVector.java View 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 ];
}
}
}


+ 14
- 0
src/java/org/apache/fop/svg/font/FOPGVTFont.java View 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();
}

+ 12
- 0
src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java View 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;
}

+ 8
- 1
src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java View 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]);

Loading…
Cancel
Save