/**
* Main constructor.
+ *
* @param g2d the AFPGraphics2D instance
*/
public AFPTextHandler(AFPGraphics2D g2d) {
return g2d.getFontInfo();
}
+ /**
+ * Registers a page font
+ *
+ * @param internalFontName the internal font name
+ * @param fontSize the font size
+ * @return a font reference
+ */
+ private int registerPageFont(String internalFontName, int fontSize) {
+ FontInfo fontInfo = getFontInfo();
+ AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName);
+ AFPPaintingState paintingState = g2d.getPaintingState();
+ AFPPageFonts pageFonts = paintingState.getPageFonts();
+ // register if necessary
+ AFPFontAttributes afpFontAttributes = pageFonts.registerFont(
+ internalFontName,
+ afpFont,
+ fontSize
+ );
+ return afpFontAttributes.getFontReference();
+ }
+
/**
* Add a text string to the current data object of the AFP datastream.
* The text is painted using text operations.
GraphicsObject graphicsObj = g2d.getGraphicsObject();
Color color = g2d.getColor();
+ // set the color
AFPPaintingState paintingState = g2d.getPaintingState();
if (paintingState.setColor(color)) {
graphicsObj.setColor(color);
}
+
+ // set the character set
+ int fontReference = 0;
if (overrideFont != null) {
- FontInfo fontInfo = getFontInfo();
- AFPPageFonts pageFonts = paintingState.getPageFonts();
String internalFontName = overrideFont.getFontName();
int fontSize = overrideFont.getFontSize();
- if (paintingState.setFontName(internalFontName) || paintingState.setFontSize(fontSize)) {
- AFPFont font = (AFPFont)fontInfo.getFonts().get(internalFontName);
- AFPFontAttributes afpFontAttributes = pageFonts.registerFont(
- internalFontName,
- font,
- fontSize
- );
- int fontReference = afpFontAttributes.getFontReference();
- graphicsObj.setCharacterSet(fontReference);
- }
+ fontReference = registerPageFont(internalFontName, fontSize);
+ } else {
+ java.awt.Font awtFont = g2d.getFont();
+ AffineTransform fontTransform = awtFont.getTransform();
+ FontInfo fontInfo = getFontInfo();
+ Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
+ String internalFontName = fopFont.getFontName();
+ int fontSize = fopFont.getFontSize();
+ fontReference = registerPageFont(internalFontName, fontSize);
}
+ graphicsObj.setCharacterSet(fontReference);
// calculate x, y plotting coordinates from graphics context
AffineTransform at = g2d.getTransform();
float[] dstPts = new float[srcPts.length];
at.transform(srcPts, 0, dstPts, 0, 1);
+ // add the character string
graphicsObj.addString(str, Math.round(dstPts[X]), Math.round(dstPts[Y]));
}
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
package org.apache.fop.afp;
+import java.awt.Color;
import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.font.TextAttribute;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.io.IOException;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
-import java.awt.font.TextAttribute;
-import java.awt.Shape;
-import java.awt.Paint;
-import java.awt.Color;
-import java.io.IOException;
-import java.util.List;
import java.util.Iterator;
+import java.util.List;
+import org.apache.batik.dom.svg.SVGOMTextElement;
+import org.apache.batik.gvt.TextNode;
+import org.apache.batik.gvt.TextPainter;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.gvt.renderer.StrokingTextPainter;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+import org.apache.batik.gvt.text.Mark;
+import org.apache.batik.gvt.text.TextPaintInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
-import org.apache.batik.dom.svg.SVGOMTextElement;
-import org.apache.batik.gvt.text.Mark;
-import org.apache.batik.gvt.TextPainter;
-import org.apache.batik.gvt.TextNode;
-import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
-import org.apache.batik.gvt.text.TextPaintInfo;
-import org.apache.batik.gvt.font.GVTFontFamily;
-import org.apache.batik.gvt.renderer.StrokingTextPainter;
-
/**
* Renders the attributed character iterator of a <tt>TextNode</tt>.
* into a simple drawString the StrokingTextPainter is used instead.
*/
public class AFPTextPainter implements TextPainter {
-
+
/** the logger for this class */
protected Log log = LogFactory.getLog(AFPTextPainter.class);
-
- private AFPTextHandler nativeTextHandler;
+
+ private final AFPTextHandler nativeTextHandler;
/**
* Use the stroking text painter to get the bounds and shape.
* Also used as a fallback to draw the string with strokes.
*/
- protected static final TextPainter
+ protected static final TextPainter
PROXY_PAINTER = StrokingTextPainter.getInstance();
/**
paintTextRuns(node.getTextRuns(), g2d, loc);
}
}
-
+
private boolean hasUnsupportedAttributes(TextNode node) {
Iterator iter = node.getTextRuns().iterator();
while (iter.hasNext()) {
- StrokingTextPainter.TextRun
+ StrokingTextPainter.TextRun
run = (StrokingTextPainter.TextRun)iter.next();
AttributedCharacterIterator aci = run.getACI();
boolean hasUnsupported = hasUnsupportedAttributes(aci);
}
private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
- boolean hasunsupported = false;
-
+ boolean hasUnsupported = false;
+
String text = getText(aci);
Font font = makeFont(aci);
if (hasUnsupportedGlyphs(text, font)) {
log.trace("-> Unsupported glyphs found");
- hasunsupported = true;
+ hasUnsupported = true;
}
-
+
TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
- if ((tpi != null)
+ if ((tpi != null)
&& ((tpi.strokeStroke != null && tpi.strokePaint != null)
|| (tpi.strikethroughStroke != null)
|| (tpi.underlineStroke != null)
|| (tpi.overlineStroke != null))) {
log.trace("-> under/overlines etc. found");
- hasunsupported = true;
+ hasUnsupported = true;
}
//Alpha is not supported
Color col = (Color)foreground;
if (col.getAlpha() != 255) {
log.trace("-> transparency found");
- hasunsupported = true;
+ hasUnsupported = true;
}
}
GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
if (letSpace != null) {
log.trace("-> letter spacing found");
- hasunsupported = true;
+ hasUnsupported = true;
}
Object wordSpace = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
if (wordSpace != null) {
log.trace("-> word spacing found");
- hasunsupported = true;
+ hasUnsupported = true;
}
-
+
Object lengthAdjust = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST);
if (lengthAdjust != null) {
log.trace("-> length adjustments found");
- hasunsupported = true;
+ hasUnsupported = true;
}
Object writeMod = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE);
- if (writeMod != null
+ if (writeMod != null
&& !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
writeMod)) {
log.trace("-> Unsupported writing modes found");
- hasunsupported = true;
+ hasUnsupported = true;
}
Object vertOr = aci.getAttribute(
if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
vertOr)) {
log.trace("-> vertical orientation found");
- hasunsupported = true;
+ hasUnsupported = true;
}
-
+
Object rcDel = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
//Batik 1.6 returns null here which makes it impossible to determine whether this can
//be painted or not, i.e. fall back to stroking. :-(
if (rcDel != null && !(rcDel instanceof SVGOMTextElement)) {
log.trace("-> spans found");
- hasunsupported = true; //Filter spans
+ hasUnsupported = true; //Filter spans
}
-
- if (hasunsupported) {
+
+ if (hasUnsupported) {
log.trace("Unsupported attributes found in ACI, using StrokingTextPainter");
}
- return hasunsupported;
+ return hasUnsupported;
}
/**
Point2D currentloc = loc;
Iterator i = textRuns.iterator();
while (i.hasNext()) {
- StrokingTextPainter.TextRun
+ StrokingTextPainter.TextRun
run = (StrokingTextPainter.TextRun)i.next();
currentloc = paintTextRun(run, g2d, currentloc);
}
// font
Font font = makeFont(aci);
nativeTextHandler.setOverrideFont(font);
-
+
// color
TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
g2d.setColor(col);
}
g2d.setPaint(foreground);
-
+
String txt = getText(aci);
float advance = getStringWidth(txt, font);
float tx = 0;
} finally {
nativeTextHandler.setOverrideFont(null);
}
- loc.setLocation(loc.getX() + (double)advance, loc.getY());
+ loc.setLocation(loc.getX() + advance, loc.getY());
return loc;
}
}
if (ypos != null) {
loc.setLocation(loc.getX(), ypos.doubleValue());
- }
+ }
if (dxpos != null) {
loc.setLocation(loc.getX() + dxpos.doubleValue(), loc.getY());
- }
+ }
if (dypos != null) {
loc.setLocation(loc.getX(), loc.getY() + dypos.doubleValue());
- }
+ }
}
private String getStyle(AttributedCharacterIterator aci) {
Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
return ((posture != null) && (posture.floatValue() > 0.0))
- ? "italic"
- : "normal";
+ ? Font.STYLE_ITALIC
+ : Font.STYLE_NORMAL;
}
private int getWeight(AttributedCharacterIterator aci) {
Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT);
- return ((taWeight != null) && (taWeight.floatValue() > 1.0))
+ return ((taWeight != null) && (taWeight.floatValue() > 1.0))
? Font.WEIGHT_BOLD
: Font.WEIGHT_NORMAL;
}
* @return the bounds of the text
*/
public Rectangle2D getBounds2D(TextNode node) {
- /* (todo) getBounds2D() is too slow
- * because it uses the StrokingTextPainter. We should implement this
+ /* (todo) getBounds2D() is too slow
+ * because it uses the StrokingTextPainter. We should implement this
* method ourselves. */
return PROXY_PAINTER.getBounds2D(node);
}
/**
* Get the mark.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param node the text node
* @param pos the position
* @param all select all
/**
* Select at.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param x the x position
* @param y the y position
* @param node the text node
/**
* Select to.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param x the x position
* @param y the y position
* @param beginMark the start mark
/**
* Selec first.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param node the text node
* @return null
*/
/**
* Select last.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param node the text node
* @return null
*/
/**
* Get selected.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param start the start mark
* @param finish the finish mark
* @return null
/**
* Get the highlighted shape.
- * This does nothing since the output is pdf and not interactive.
+ * This does nothing since the output is AFP and not interactive.
* @param beginMark the start mark
* @param endMark the end mark
* @return null
/**
* Retrieves a (possibly cached) Font instance based on a FontTriplet and a font size.
+ *
* @param triplet the font triplet designating the requested font
* @param fontSize the font size
* @return the requested Font instance
return font;
}
+ private List/*<FontTriplet>*/ getTripletsForName(String fontName) {
+ List/*<FontTriplet>*/ matchedTriplets = new java.util.ArrayList/*<FontTriplet>*/();
+ Iterator it = triplets.keySet().iterator();
+ while (it.hasNext()) {
+ FontTriplet triplet = (FontTriplet)it.next();
+ String tripletName = triplet.getName();
+ if (tripletName.toLowerCase().equals(fontName.toLowerCase())) {
+ matchedTriplets.add(triplet);
+ }
+ }
+ return matchedTriplets;
+ }
+
+ /**
+ * Returns a suitable internal font given an AWT Font instance.
+ *
+ * @param awtFont the AWT font
+ * @return a best matching internal Font
+ */
+ public Font getFontInstanceForAWTFont(java.awt.Font awtFont) {
+ String awtFontName = awtFont.getName();
+ String awtFontFamily = awtFont.getFamily();
+ String awtFontStyle = awtFont.isItalic() ? Font.STYLE_ITALIC : Font.STYLE_NORMAL;
+ int awtFontWeight = awtFont.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL;
+
+ FontTriplet matchedTriplet = null;
+ List/*<FontTriplet>*/ triplets = getTripletsForName(awtFontName);
+ if (!triplets.isEmpty()) {
+ Iterator it = triplets.iterator();
+ while (it.hasNext()) {
+ FontTriplet triplet = (FontTriplet)it.next();
+ boolean styleMatched = triplet.getStyle().equals(awtFontStyle);
+ boolean weightMatched = triplet.getWeight() == awtFontWeight;
+ if (styleMatched && weightMatched) {
+ matchedTriplet = triplet;
+ break;
+ }
+ }
+ }
+
+ // not matched on font name so do a lookup using family
+ if (matchedTriplet == null) {
+ if (awtFontFamily.equals("sanserif")) {
+ awtFontFamily = "sans-serif";
+ }
+ matchedTriplet = fontLookup(awtFontFamily, awtFontStyle, awtFontWeight);
+ }
+ float awtFontSize = awtFont.getSize2D();
+ return getFontInstance(matchedTriplet, (int)(awtFontSize * 1000 + 0.5));
+ }
+
/**
* Lookup a font.
* <br>