git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1626491 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -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 |
@@ -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(); | |||
} |
@@ -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("================================================"); |
@@ -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); |
@@ -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 ]; | |||
} | |||
} | |||
} | |||
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -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]); |