this.resourceManager = resourceManager;
}
+ /**
+ * Returns the AFP resource manager associated with this {@link Graphics2D} instance.
+ * @return the resource manager
+ */
+ public AFPResourceManager getResourceManager() {
+ return this.resourceManager;
+ }
+
/**
* Sets the AFP resource info
*
}
/** {@inheritDoc} */
+ @Override
public void draw(Shape shape) {
LOG.debug("draw() shape=" + shape);
doDrawing(shape, false);
}
/** {@inheritDoc} */
+ @Override
public void fill(Shape shape) {
LOG.debug("fill() shape=" + shape);
doDrawing(shape, true);
}
/** {@inheritDoc} */
+ @Override
public void drawString(String str, float x, float y) {
try {
if (customTextHandler != null && !textAsShapes) {
}
/** {@inheritDoc} */
+ @Override
public GraphicsConfiguration getDeviceConfiguration() {
return graphicsConfig;
}
/** {@inheritDoc} */
+ @Override
public Graphics create() {
return new AFPGraphics2D(this);
}
/** {@inheritDoc} */
+ @Override
public void dispose() {
this.graphicsObj = null;
}
/** {@inheritDoc} */
+ @Override
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer);
}
}
/** {@inheritDoc} */
+ @Override
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer) {
// draw with AWT Graphics2D
}
/** {@inheritDoc} */
+ @Override
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
int imgWidth = img.getWidth();
int imgHeight = img.getHeight();
}
/** {@inheritDoc} */
+ @Override
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
LOG.debug("drawRenderableImage() NYI: img=" + img + ", xform=" + xform);
}
/** {@inheritDoc} */
+ @Override
public FontMetrics getFontMetrics(Font f) {
LOG.debug("getFontMetrics() NYI: f=" + f);
return null;
}
/** {@inheritDoc} */
+ @Override
public void setXORMode(Color col) {
LOG.debug("setXORMode() NYI: col=" + col);
}
}
/** {@inheritDoc} */
+ @Override
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
LOG.debug("copyArea() NYI: ");
}
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.gvt.TextPainter;
+
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+
import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.svg.AbstractFOPBridgeContext;
-import org.apache.xmlgraphics.image.loader.ImageManager;
-import org.apache.xmlgraphics.image.loader.ImageSessionContext;
/**
* An AFP specific implementation of a Batik BridgeContext
}
/** {@inheritDoc} */
+ @Override
public void registerSVGBridges() {
super.registerSVGBridges();
if (fontInfo != null) {
- AFPTextHandler textHandler = new AFPTextHandler(fontInfo);
+ AFPTextHandler textHandler = new AFPTextHandler(fontInfo, g2d.getResourceManager());
g2d.setCustomTextHandler(textHandler);
TextPainter textPainter = new AFPTextPainter(textHandler);
}
/** {@inheritDoc} */
+ @Override
public BridgeContext createBridgeContext() {
return new AFPBridgeContext(getUserAgent(), getDocumentLoader(),
fontInfo,
import java.awt.Color;
import java.awt.Graphics2D;
+import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPPaintingState;
+import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.fonts.AFPFontAttributes;
import org.apache.fop.afp.fonts.AFPPageFonts;
+import org.apache.fop.afp.fonts.CharacterSet;
import org.apache.fop.afp.modca.GraphicsObject;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
/** Font information */
private final FontInfo fontInfo;
+ /** the resource manager */
+ private AFPResourceManager resourceManager;
+
/**
* Main constructor.
*
* @param fontInfo the AFPGraphics2D instance
*/
- public AFPTextHandler(FontInfo fontInfo) {
+ public AFPTextHandler(FontInfo fontInfo, AFPResourceManager resourceManager) {
this.fontInfo = fontInfo;
+ this.resourceManager = resourceManager;
}
/**
afpFont,
fontSize
);
+ if (afpFont.isEmbeddable()) {
+ try {
+ final CharacterSet charSet = afpFont.getCharacterSet(fontSize);
+ this.resourceManager.embedFont(afpFont, charSet);
+ } catch (IOException ioe) {
+ throw new RuntimeException("Error while embedding font resources", ioe);
+ }
+ }
return afpFontAttributes.getFontReference();
}
*
* {@inheritDoc}
*/
+ @Override
public void drawString(Graphics2D g, String str, float x, float y) {
if (log.isDebugEnabled()) {
log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y);
if (overrideFont != null) {
internalFontName = overrideFont.getFontName();
fontSize = overrideFont.getFontSize();
+ if (log.isDebugEnabled()) {
+ log.debug(" with overriding font: " + internalFontName + ", " + fontSize);
+ }
} else {
java.awt.Font awtFont = g2d.getFont();
Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
+ if (log.isDebugEnabled()) {
+ log.debug(" with font: " + fopFont);
+ }
internalFontName = fopFont.getFontName();
fontSize = fopFont.getFontSize();
}
package org.apache.fop.svg;
+import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
-import java.util.Iterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.batik.bridge.SVGFontFamily;
+import org.apache.batik.gvt.font.GVTFont;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+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;
/**
* Utilities for java.text.AttributedCharacterIterator.
*/
public final class ACIUtils {
+ /** the logger for this class */
+ private static final Log LOG = LogFactory.getLog(ACIUtils.class);
+
private ACIUtils() {
//This class shouldn't be instantiated.
}
+ /**
+ * Tries to find matching fonts in FOP's {@link FontInfo} instance for fonts used by
+ * Apache Batik. The method inspects the various GVT attributes found in the ACI.
+ * @param aci the ACI to find matching fonts for
+ * @param fontInfo the font info instance with FOP's fonts
+ * @return an array of matching fonts
+ */
+ public static Font[] findFontsForBatikACI(AttributedCharacterIterator aci, FontInfo fontInfo) {
+ List<Font> fonts = new java.util.ArrayList<Font>();
+ @SuppressWarnings("unchecked")
+ List<GVTFontFamily> gvtFonts = (List<GVTFontFamily>) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+ Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
+ Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
+ Float fontSize = (Float) aci.getAttribute(TextAttribute.SIZE);
+
+ String style = toStyle(posture);
+ int weight = toCSSWeight(taWeight);
+ int fsize = (int)(fontSize.floatValue() * 1000);
+
+ String firstFontFamily = null;
+
+ //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES
+ //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set
+ /* The following code section is not available until Batik 1.7 is released. */
+ GVTFont gvtFont = (GVTFont)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
+ if (gvtFont != null) {
+ try {
+ String gvtFontFamily = gvtFont.getFamilyName(); //Not available in Batik 1.6!
+ if (fontInfo.hasFont(gvtFontFamily, style, weight)) {
+ FontTriplet triplet = fontInfo.fontLookup(gvtFontFamily, style,
+ weight);
+ Font f = fontInfo.getFontInstance(triplet, fsize);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found a font that matches the GVT font: "
+ + gvtFontFamily + ", " + weight + ", " + style
+ + " -> " + f);
+ }
+ fonts.add(f);
+ }
+ firstFontFamily = gvtFontFamily;
+ } catch (Exception e) {
+ //Most likely NoSuchMethodError here when using Batik 1.6
+ //Just skip this section in this case
+ }
+ }
+
+ if (gvtFonts != null) {
+ for (GVTFontFamily fam : gvtFonts) {
+ if (fam instanceof SVGFontFamily) {
+ return null; //Let Batik paint this text!
+ }
+ String fontFamily = fam.getFamilyName();
+ if (fontInfo.hasFont(fontFamily, style, weight)) {
+ FontTriplet triplet = fontInfo.fontLookup(fontFamily, style,
+ weight);
+ Font f = fontInfo.getFontInstance(triplet, fsize);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found a font that matches the GVT font family: "
+ + fontFamily + ", " + weight + ", " + style
+ + " -> " + f);
+ }
+ fonts.add(f);
+ }
+ if (firstFontFamily == null) {
+ firstFontFamily = fontFamily;
+ }
+ }
+ }
+ if (fonts.isEmpty()) {
+ if (firstFontFamily == null) {
+ //This will probably never happen. Just to be on the safe side.
+ firstFontFamily = "any";
+ }
+ //lookup with fallback possibility (incl. substitution notification)
+ FontTriplet triplet = fontInfo.fontLookup(firstFontFamily, style, weight);
+ Font f = fontInfo.getFontInstance(triplet, fsize);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Falling back to adjustable font lookup up for: "
+ + firstFontFamily + ", " + weight + ", " + style
+ + " -> " + f);
+ }
+ fonts.add(f);
+ }
+ return fonts.toArray(new Font[fonts.size()]);
+ }
+
+ private static int toCSSWeight(Float weight) {
+ if (weight == null) {
+ return 400;
+ } else if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
+ return 100;
+ } else if (weight <= TextAttribute.WEIGHT_LIGHT.floatValue()) {
+ return 200;
+ } else if (weight <= TextAttribute.WEIGHT_DEMILIGHT.floatValue()) {
+ return 300;
+ } else if (weight <= TextAttribute.WEIGHT_REGULAR.floatValue()) {
+ return 400;
+ } else if (weight <= TextAttribute.WEIGHT_SEMIBOLD.floatValue()) {
+ return 500;
+ } else if (weight <= TextAttribute.WEIGHT_BOLD.floatValue()) {
+ return 600;
+ } else if (weight <= TextAttribute.WEIGHT_HEAVY.floatValue()) {
+ return 700;
+ } else if (weight <= TextAttribute.WEIGHT_EXTRABOLD.floatValue()) {
+ return 800;
+ } else {
+ return 900;
+ }
+ }
+
+ private static String toStyle(Float posture) {
+ return ((posture != null) && (posture.floatValue() > 0.0))
+ ? Font.STYLE_ITALIC
+ : Font.STYLE_NORMAL;
+ }
+
/**
* Dumps the contents of an ACI to System.out. Used for debugging only.
* @param aci the ACI to dump
*/
public static void dumpAttrs(AttributedCharacterIterator aci) {
aci.first();
- Iterator i = aci.getAttributes().entrySet().iterator();
- while (i.hasNext()) {
- Map.Entry entry = (Map.Entry)i.next();
+ Set<Entry<Attribute, Object>> entries = aci.getAttributes().entrySet();
+ for (Map.Entry<Attribute, Object> entry : entries) {
if (entry.getValue() != null) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
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.fop.afp.AFPGraphics2D;
import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontTriplet;
/**
* Renders the attributed character iterator of a {@link TextNode}.
}
}
- private String getStyle(AttributedCharacterIterator aci) {
- Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
- return ((posture != null) && (posture.floatValue() > 0.0))
- ? 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))
- ? Font.WEIGHT_BOLD
- : Font.WEIGHT_NORMAL;
- }
-
private Font getFont(AttributedCharacterIterator aci) {
- Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE);
- if (fontSize == null) {
- fontSize = new Float(10f);
- }
- String style = getStyle(aci);
- int weight = getWeight(aci);
-
- FontInfo fontInfo = nativeTextHandler.getFontInfo();
- String fontFamily = null;
- List gvtFonts = (List) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
- if (gvtFonts != null) {
- Iterator i = gvtFonts.iterator();
- while (i.hasNext()) {
- GVTFontFamily fam = (GVTFontFamily) i.next();
- /* (todo) Enable SVG Font painting
- if (fam instanceof SVGFontFamily) {
- PROXY_PAINTER.paint(node, g2d);
- return;
- }*/
- fontFamily = fam.getFamilyName();
- if (fontInfo.hasFont(fontFamily, style, weight)) {
- FontTriplet triplet = fontInfo.fontLookup(
- fontFamily, style, weight);
- int fsize = (int)(fontSize.floatValue() * 1000);
- return fontInfo.getFontInstance(triplet, fsize);
- }
- }
- }
- FontTriplet triplet = fontInfo.fontLookup("any", style, Font.WEIGHT_NORMAL);
- int fsize = (int)(fontSize.floatValue() * 1000);
- return fontInfo.getFontInstance(triplet, fsize);
+ Font[] fonts = ACIUtils.findFontsForBatikACI(aci, nativeTextHandler.getFontInfo());
+ return fonts[0];
}
private float getStringWidth(String str, Font font) {
package org.apache.fop.svg;
import java.awt.Graphics2D;
-import java.awt.font.TextAttribute;
import java.io.IOException;
import java.text.AttributedCharacterIterator;
-import java.util.Iterator;
import java.util.List;
-import org.apache.batik.bridge.SVGFontFamily;
-import org.apache.batik.gvt.font.GVTFont;
-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.TextSpanLayout;
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.fop.util.CharUtilities;
/**
protected abstract void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException;
/** {@inheritDoc} */
+ @Override
protected void paintTextRuns(List textRuns, Graphics2D g2d) {
if (log.isTraceEnabled()) {
log.trace("paintTextRuns: count = " + textRuns.size());
* @return the array of fonts
*/
protected Font[] findFonts(AttributedCharacterIterator aci) {
- List fonts = new java.util.ArrayList();
- List gvtFonts = (List) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
- Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
- Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
- Float fontSize = (Float) aci.getAttribute(TextAttribute.SIZE);
-
- String style = ((posture != null) && (posture.floatValue() > 0.0))
- ? Font.STYLE_ITALIC : Font.STYLE_NORMAL;
- int weight = toCSSWeight(taWeight != null
- ? taWeight.floatValue()
- : TextAttribute.WEIGHT_REGULAR.floatValue());
-
- String firstFontFamily = null;
-
- //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES
- //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set
- /* The following code section is not available until Batik 1.7 is released. */
- GVTFont gvtFont = (GVTFont)aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
- if (gvtFont != null) {
- try {
- String gvtFontFamily = gvtFont.getFamilyName(); //Not available in Batik 1.6!
- if (log.isDebugEnabled()) {
- log.debug("Matching font family: " + gvtFontFamily);
- }
- if (fontInfo.hasFont(gvtFontFamily, style, weight)) {
- FontTriplet triplet = fontInfo.fontLookup(gvtFontFamily, style,
- weight);
- int fsize = (int)(fontSize.floatValue() * 1000);
- fonts.add(fontInfo.getFontInstance(triplet, fsize));
- }
- firstFontFamily = gvtFontFamily;
- } catch (Exception e) {
- //Most likely NoSuchMethodError here when using Batik 1.6
- //Just skip this section in this case
- }
- }
-
- if (gvtFonts != null) {
- Iterator i = gvtFonts.iterator();
- while (i.hasNext()) {
- GVTFontFamily fam = (GVTFontFamily) i.next();
- if (fam instanceof SVGFontFamily) {
- return null; //Let Batik paint this text!
- }
- String fontFamily = fam.getFamilyName();
- if (log.isDebugEnabled()) {
- log.debug("Matching font family: " + fontFamily);
- }
- if (fontInfo.hasFont(fontFamily, style, weight)) {
- FontTriplet triplet = fontInfo.fontLookup(fontFamily, style,
- weight);
- int fsize = (int)(fontSize.floatValue() * 1000);
- fonts.add(fontInfo.getFontInstance(triplet, fsize));
- }
- if (firstFontFamily == null) {
- firstFontFamily = fontFamily;
- }
- }
- }
- if (fonts.size() == 0) {
- if (firstFontFamily == null) {
- //This will probably never happen. Just to be on the safe side.
- firstFontFamily = "any";
- }
- //lookup with fallback possibility (incl. substitution notification)
- FontTriplet triplet = fontInfo.fontLookup(firstFontFamily, style, weight);
- int fsize = (int)(fontSize.floatValue() * 1000);
- fonts.add(fontInfo.getFontInstance(triplet, fsize));
- }
- return (Font[])fonts.toArray(new Font[fonts.size()]);
- }
-
- private int toCSSWeight(float weight) {
- if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
- return 100;
- } else if (weight <= TextAttribute.WEIGHT_LIGHT.floatValue()) {
- return 200;
- } else if (weight <= TextAttribute.WEIGHT_DEMILIGHT.floatValue()) {
- return 300;
- } else if (weight <= TextAttribute.WEIGHT_REGULAR.floatValue()) {
- return 400;
- } else if (weight <= TextAttribute.WEIGHT_SEMIBOLD.floatValue()) {
- return 500;
- } else if (weight <= TextAttribute.WEIGHT_BOLD.floatValue()) {
- return 600;
- } else if (weight <= TextAttribute.WEIGHT_HEAVY.floatValue()) {
- return 700;
- } else if (weight <= TextAttribute.WEIGHT_EXTRABOLD.floatValue()) {
- return 800;
- } else {
- return 900;
- }
+ Font[] fonts = ACIUtils.findFontsForBatikACI(aci, fontInfo);
+ return fonts;
}
/**
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Renderers" dev="JM" type="fix">
+ AFP GOCA: fonts were not embedded from within AFPGraphics2D.
+ </action>
+ <action context="Renderers" dev="JM" type="fix">
+ AFP GOCA: Changed the way FOP fonts are selected based on Batik's GVT fonts to match
+ the behaviour of PDF/PS output.
+ </action>
<action context="Renderers" dev="JM" type="add">
Added option to place AFP NOPs right before the end of a named page group (page-sequence),
rather than after the start.