Bug relates to PCL painter thread safetly. Previous fix in rev 895012 worked by synchronizing methods of a static instance of Java2DFontMetrics. This fix uses a unique instance for per thread. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1161612 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1old
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) | public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) | ||||
throws FOPException { | throws FOPException { | ||||
FontManager fontManager = userAgent.getFactory().getFontManager(); | |||||
final FontManager fontManager = userAgent.getFactory().getFontManager(); | |||||
Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); | |||||
final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); | |||||
List fontCollections = new java.util.ArrayList(); | |||||
fontCollections.add(new Base14FontCollection(graphics2D)); | |||||
fontCollections.add(new InstalledFontCollection(graphics2D)); | |||||
final List fontCollections = new java.util.ArrayList(); | |||||
fontCollections.add(new Base14FontCollection(java2DFontMetrics)); | |||||
fontCollections.add(new InstalledFontCollection(java2DFontMetrics)); | |||||
Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | ||||
if (cfg != null) { | if (cfg != null) { |
*/ | */ | ||||
public class Base14FontCollection implements FontCollection { | public class Base14FontCollection implements FontCollection { | ||||
private Graphics2D graphics2d = null; | |||||
/** required when creating new instances of SystemFontMetricsMapper */ | |||||
private final Java2DFontMetrics java2DFontMetrics; | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* @param graphics2d a graphics 2D | |||||
* @param java2DFontMetrics required when creating new instances of SystemFontMetricsMapper | |||||
*/ | */ | ||||
public Base14FontCollection(Graphics2D graphics2d) { | |||||
this.graphics2d = graphics2d; | |||||
public Base14FontCollection(Java2DFontMetrics java2DFontMetrics) { | |||||
this.java2DFontMetrics = java2DFontMetrics; | |||||
} | } | ||||
/** | /** | ||||
final int bolditalic = java.awt.Font.BOLD + java.awt.Font.ITALIC; | final int bolditalic = java.awt.Font.BOLD + java.awt.Font.ITALIC; | ||||
FontMetricsMapper metric; | FontMetricsMapper metric; | ||||
metric = new SystemFontMetricsMapper("SansSerif", normal, graphics2d); | |||||
metric = new SystemFontMetricsMapper("SansSerif", normal, java2DFontMetrics); | |||||
// --> goes to F1 | // --> goes to F1 | ||||
fontInfo.addMetrics("F1", metric); | fontInfo.addMetrics("F1", metric); | ||||
metric = new SystemFontMetricsMapper("SansSerif", italic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("SansSerif", italic, java2DFontMetrics); | |||||
// --> goes to F2 | // --> goes to F2 | ||||
fontInfo.addMetrics("F2", metric); | fontInfo.addMetrics("F2", metric); | ||||
metric = new SystemFontMetricsMapper("SansSerif", bold, graphics2d); | |||||
metric = new SystemFontMetricsMapper("SansSerif", bold, java2DFontMetrics); | |||||
// --> goes to F3 | // --> goes to F3 | ||||
fontInfo.addMetrics("F3", metric); | fontInfo.addMetrics("F3", metric); | ||||
metric = new SystemFontMetricsMapper("SansSerif", bolditalic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("SansSerif", bolditalic, java2DFontMetrics); | |||||
// --> goes to F4 | // --> goes to F4 | ||||
fontInfo.addMetrics("F4", metric); | fontInfo.addMetrics("F4", metric); | ||||
metric = new SystemFontMetricsMapper("Serif", normal, graphics2d); | |||||
metric = new SystemFontMetricsMapper("Serif", normal, java2DFontMetrics); | |||||
// --> goes to F5 | // --> goes to F5 | ||||
fontInfo.addMetrics("F5", metric); | fontInfo.addMetrics("F5", metric); | ||||
metric = new SystemFontMetricsMapper("Serif", italic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("Serif", italic, java2DFontMetrics); | |||||
// --> goes to F6 | // --> goes to F6 | ||||
fontInfo.addMetrics("F6", metric); | fontInfo.addMetrics("F6", metric); | ||||
metric = new SystemFontMetricsMapper("Serif", bold, graphics2d); | |||||
metric = new SystemFontMetricsMapper("Serif", bold, java2DFontMetrics); | |||||
// --> goes to F7 | // --> goes to F7 | ||||
fontInfo.addMetrics("F7", metric); | fontInfo.addMetrics("F7", metric); | ||||
metric = new SystemFontMetricsMapper("Serif", bolditalic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("Serif", bolditalic, java2DFontMetrics); | |||||
// --> goes to F8 | // --> goes to F8 | ||||
fontInfo.addMetrics("F8", metric); | fontInfo.addMetrics("F8", metric); | ||||
metric = new SystemFontMetricsMapper("MonoSpaced", normal, graphics2d); | |||||
metric = new SystemFontMetricsMapper("MonoSpaced", normal, java2DFontMetrics); | |||||
// --> goes to F9 | // --> goes to F9 | ||||
fontInfo.addMetrics("F9", metric); | fontInfo.addMetrics("F9", metric); | ||||
metric = new SystemFontMetricsMapper("MonoSpaced", italic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("MonoSpaced", italic, java2DFontMetrics); | |||||
// --> goes to F10 | // --> goes to F10 | ||||
fontInfo.addMetrics("F10", metric); | fontInfo.addMetrics("F10", metric); | ||||
metric = new SystemFontMetricsMapper("MonoSpaced", bold, graphics2d); | |||||
metric = new SystemFontMetricsMapper("MonoSpaced", bold, java2DFontMetrics); | |||||
// --> goes to F11 | // --> goes to F11 | ||||
fontInfo.addMetrics("F11", metric); | fontInfo.addMetrics("F11", metric); | ||||
metric = new SystemFontMetricsMapper("MonoSpaced", bolditalic, graphics2d); | |||||
metric = new SystemFontMetricsMapper("MonoSpaced", bolditalic, java2DFontMetrics); | |||||
// --> goes to F12 | // --> goes to F12 | ||||
fontInfo.addMetrics("F12", metric); | fontInfo.addMetrics("F12", metric); | ||||
metric = new SystemFontMetricsMapper("Serif", normal, graphics2d); | |||||
metric = new SystemFontMetricsMapper("Serif", normal, java2DFontMetrics); | |||||
//"Symbol" doesn't seem to work here, but "Serif" does the job just fine. *shrug* | //"Symbol" doesn't seem to work here, but "Serif" does the job just fine. *shrug* | ||||
// --> goes to F13 and F14 | // --> goes to F13 and F14 | ||||
fontInfo.addMetrics("F13", metric); | fontInfo.addMetrics("F13", metric); |
HARDCODED_FONT_NAMES.add("Computer-Modern-Typewriter"); | HARDCODED_FONT_NAMES.add("Computer-Modern-Typewriter"); | ||||
} | } | ||||
private Graphics2D graphics2D = null; | |||||
/** Required by new instances of FontMetricsMapper */ | |||||
final private Java2DFontMetrics java2DFontMetrics; | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* | * | ||||
* @param graphics2D a graphics 2D | |||||
* @param java2DFontMetrics required by new instances of FontMetricsMapper | |||||
*/ | */ | ||||
public InstalledFontCollection(Graphics2D graphics2D) { | |||||
this.graphics2D = graphics2D; | |||||
public InstalledFontCollection(Java2DFontMetrics java2DFontMetrics) { | |||||
this.java2DFontMetrics = java2DFontMetrics; | |||||
} | } | ||||
/** | /** | ||||
num++; | num++; | ||||
String fontKey = "F" + num; | String fontKey = "F" + num; | ||||
int style = convertToAWTFontStyle(guessedStyle, guessedWeight); | int style = convertToAWTFontStyle(guessedStyle, guessedWeight); | ||||
addFontMetricsMapper(fontInfo, f.getName(), fontKey, graphics2D, style); | |||||
addFontMetricsMapper(fontInfo, f.getName(), fontKey, java2DFontMetrics, style); | |||||
//Register appropriate font triplets matching the font. Two different strategies: | //Register appropriate font triplets matching the font. Two different strategies: | ||||
//Example: "Arial Bold", normal, normal | //Example: "Arial Bold", normal, normal | ||||
} | } | ||||
private static void addFontMetricsMapper(FontInfo fontInfo, String family, String fontKey, | private static void addFontMetricsMapper(FontInfo fontInfo, String family, String fontKey, | ||||
Graphics2D graphics, int style) { | |||||
FontMetricsMapper metric = new SystemFontMetricsMapper(family, style, graphics); | |||||
Java2DFontMetrics java2DFontMetrics, int style) { | |||||
FontMetricsMapper metric = new SystemFontMetricsMapper(family, style, java2DFontMetrics); | |||||
fontInfo.addMetrics(fontKey, metric); | fontInfo.addMetrics(fontKey, metric); | ||||
} | } | ||||
/** | /** | ||||
* Temp graphics object needed to get the font metrics | * Temp graphics object needed to get the font metrics | ||||
*/ | */ | ||||
private Graphics2D graphics; | |||||
private final Graphics2D graphics; | |||||
/** | /** | ||||
* Creates a Graphics2D object for the sole purpose of getting font metrics. | * Creates a Graphics2D object for the sole purpose of getting font metrics. | ||||
* @return a Graphics2D object | * @return a Graphics2D object | ||||
*/ | */ | ||||
public static Graphics2D createFontMetricsGraphics2D() { | |||||
private static Graphics2D createFontMetricsGraphics2D() { | |||||
BufferedImage fontImage = new BufferedImage(100, 100, | BufferedImage fontImage = new BufferedImage(100, 100, | ||||
BufferedImage.TYPE_INT_RGB); | BufferedImage.TYPE_INT_RGB); | ||||
Graphics2D graphics2D = fontImage.createGraphics(); | Graphics2D graphics2D = fontImage.createGraphics(); | ||||
/** | /** | ||||
* Constructs a new Font-metrics. | * Constructs a new Font-metrics. | ||||
* @param graphics a temp graphics object - this is needed so | |||||
* that we can get an instance of java.awt.FontMetrics | |||||
*/ | */ | ||||
public Java2DFontMetrics(Graphics2D graphics) { | |||||
this.graphics = graphics; | |||||
public Java2DFontMetrics() { | |||||
this.graphics = createFontMetricsGraphics2D(); | |||||
} | } | ||||
/** | /** | ||||
* @param size font size | * @param size font size | ||||
* @return ascent in milliponts | * @return ascent in milliponts | ||||
*/ | */ | ||||
public synchronized int getMaxAscent(String family, int style, int size) { | |||||
public int getMaxAscent(String family, int style, int size) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return Math.round(lineMetrics.getAscent() * FONT_FACTOR); | return Math.round(lineMetrics.getAscent() * FONT_FACTOR); | ||||
} | } | ||||
* @param size font size | * @param size font size | ||||
* @return ascent in milliponts | * @return ascent in milliponts | ||||
*/ | */ | ||||
public synchronized int getAscender(String family, int style, int size) { | |||||
public int getAscender(String family, int style, int size) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return ascender * 1000; | return ascender * 1000; | ||||
* @param size font size | * @param size font size | ||||
* @return capital height in millipoints | * @return capital height in millipoints | ||||
*/ | */ | ||||
public synchronized int getCapHeight(String family, int style, int size) { | |||||
public int getCapHeight(String family, int style, int size) { | |||||
// currently just gets Ascent value but maybe should use | // currently just gets Ascent value but maybe should use | ||||
// getMaxAcent() at some stage | // getMaxAcent() at some stage | ||||
return getAscender(family, style, size); | return getAscender(family, style, size); | ||||
* @param size font size | * @param size font size | ||||
* @return descent in milliponts | * @return descent in milliponts | ||||
*/ | */ | ||||
public synchronized int getDescender(String family, int style, int size) { | |||||
public int getDescender(String family, int style, int size) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return descender * 1000; | return descender * 1000; | ||||
} | } | ||||
* @param size font size | * @param size font size | ||||
* @return font height in milliponts | * @return font height in milliponts | ||||
*/ | */ | ||||
public synchronized int getXHeight(String family, int style, int size) { | |||||
public int getXHeight(String family, int style, int size) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return xHeight * 1000; | return xHeight * 1000; | ||||
} | } | ||||
* @param size font size | * @param size font size | ||||
* @return character width in millipoints | * @return character width in millipoints | ||||
*/ | */ | ||||
public synchronized int width(int i, String family, int style, int size) { | |||||
public int width(int i, String family, int style, int size) { | |||||
int w; | int w; | ||||
setFont(family, style, size); | setFont(family, style, size); | ||||
w = internalCharWidth(i) * 1000; | w = internalCharWidth(i) * 1000; | ||||
* @param size font size | * @param size font size | ||||
* @return array of character widths in millipoints | * @return array of character widths in millipoints | ||||
*/ | */ | ||||
public synchronized int[] getWidths(String family, int style, int size) { | |||||
public int[] getWidths(String family, int style, int size) { | |||||
int i; | int i; | ||||
if (width == null) { | if (width == null) { | ||||
* @param size font size | * @param size font size | ||||
* @return font with the desired characeristics. | * @return font with the desired characeristics. | ||||
*/ | */ | ||||
public synchronized java.awt.Font getFont(String family, int style, int size) { | |||||
public java.awt.Font getFont(String family, int style, int size) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return f1; | return f1; | ||||
/* | /* | ||||
* @param c the glyph to check | * @param c the glyph to check | ||||
* @return true if the character is supported | * @return true if the character is supported | ||||
*/ | */ | ||||
public synchronized boolean hasChar(String family, int style, int size, char c) { | |||||
public boolean hasChar(String family, int style, int size, char c) { | |||||
setFont(family, style, size); | setFont(family, style, size); | ||||
return f1.canDisplay(c); | return f1.canDisplay(c); | ||||
} | } |
//Don't call super.setupFontInfo() here! Java2D needs a special font setup | //Don't call super.setupFontInfo() here! Java2D needs a special font setup | ||||
// create a temp Image to test font metrics on | // create a temp Image to test font metrics on | ||||
this.fontInfo = inFontInfo; | this.fontInfo = inFontInfo; | ||||
Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); | |||||
final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); | |||||
FontCollection[] fontCollections = new FontCollection[] { | FontCollection[] fontCollections = new FontCollection[] { | ||||
new Base14FontCollection(graphics2D), | |||||
new InstalledFontCollection(graphics2D), | |||||
new Base14FontCollection(java2DFontMetrics), | |||||
new InstalledFontCollection(java2DFontMetrics), | |||||
new ConfiguredFontCollection(getFontResolver(), getFontList()) | new ConfiguredFontCollection(getFontResolver(), getFontList()) | ||||
}; | }; | ||||
userAgent.getFactory().getFontManager().setup( | userAgent.getFactory().getFontManager().setup( |
*/ | */ | ||||
public static FontInfo buildDefaultJava2DBasedFontInfo( | public static FontInfo buildDefaultJava2DBasedFontInfo( | ||||
FontInfo fontInfo, FOUserAgent userAgent) { | FontInfo fontInfo, FOUserAgent userAgent) { | ||||
Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); | |||||
Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); | |||||
FontManager fontManager = userAgent.getFactory().getFontManager(); | FontManager fontManager = userAgent.getFactory().getFontManager(); | ||||
FontCollection[] fontCollections = new FontCollection[] { | FontCollection[] fontCollections = new FontCollection[] { | ||||
new org.apache.fop.render.java2d.Base14FontCollection(graphics2D), | |||||
new InstalledFontCollection(graphics2D) | |||||
new org.apache.fop.render.java2d.Base14FontCollection(java2DFontMetrics), | |||||
new InstalledFontCollection(java2DFontMetrics) | |||||
}; | }; | ||||
FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo()); | FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo()); |
* This is a Java2DFontMetrics that does the real calculation. | * This is a Java2DFontMetrics that does the real calculation. | ||||
* It is only one class that dynamically determines the font-size. | * It is only one class that dynamically determines the font-size. | ||||
*/ | */ | ||||
private static Java2DFontMetrics metric = null; | |||||
private final Java2DFontMetrics java2DFontMetrics; | |||||
/** | /** | ||||
* The java name of the font. | * The java name of the font. | ||||
* Constructs a new Font-metrics. | * Constructs a new Font-metrics. | ||||
* @param family the family name of the font (java value) | * @param family the family name of the font (java value) | ||||
* @param style the java type style value of the font | * @param style the java type style value of the font | ||||
* @param graphics a Graphics2D object - this is needed so | |||||
* that we can get an instance of java.awt.FontMetrics | |||||
* @param java2DFontMetrics metric calculations delegated to this | |||||
*/ | */ | ||||
public SystemFontMetricsMapper(String family, int style, Graphics2D graphics) { | |||||
public SystemFontMetricsMapper(String family, int style, Java2DFontMetrics java2DFontMetrics) { | |||||
this.family = family; | this.family = family; | ||||
this.style = style; | this.style = style; | ||||
if (metric == null) { | |||||
metric = new Java2DFontMetrics(graphics); | |||||
} | |||||
this.java2DFontMetrics = java2DFontMetrics; | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getMaxAscent(int size) { | public int getMaxAscent(int size) { | ||||
return metric.getMaxAscent(family, style, size); | |||||
return java2DFontMetrics.getMaxAscent(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getAscender(int size) { | public int getAscender(int size) { | ||||
return metric.getAscender(family, style, size); | |||||
return java2DFontMetrics.getAscender(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getCapHeight(int size) { | public int getCapHeight(int size) { | ||||
return metric.getCapHeight(family, style, size); | |||||
return java2DFontMetrics.getCapHeight(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getDescender(int size) { | public int getDescender(int size) { | ||||
return metric.getDescender(family, style, size); | |||||
return java2DFontMetrics.getDescender(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getXHeight(int size) { | public int getXHeight(int size) { | ||||
return metric.getXHeight(family, style, size); | |||||
return java2DFontMetrics.getXHeight(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int getWidth(int i, int size) { | public int getWidth(int i, int size) { | ||||
return metric.width(i, family, style, size); | |||||
return java2DFontMetrics.width(i, family, style, size); | |||||
} | } | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public int[] getWidths() { | public int[] getWidths() { | ||||
return metric.getWidths(family, style, Java2DFontMetrics.FONT_SIZE); | |||||
return java2DFontMetrics.getWidths(family, style, Java2DFontMetrics.FONT_SIZE); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public java.awt.Font getFont(int size) { | public java.awt.Font getFont(int size) { | ||||
return metric.getFont(family, style, size); | |||||
return java2DFontMetrics.getFont(family, style, size); | |||||
} | } | ||||
/** | /** | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public boolean hasChar(char c) { | public boolean hasChar(char c) { | ||||
return metric.hasChar(family, style, Java2DFontMetrics.FONT_SIZE, c); | |||||
return java2DFontMetrics.hasChar(family, style, Java2DFontMetrics.FONT_SIZE, c); | |||||
} | } | ||||
} | } |
throws FOPException { | throws FOPException { | ||||
FontManager fontManager = userAgent.getFactory().getFontManager(); | FontManager fontManager = userAgent.getFactory().getFontManager(); | ||||
Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D(); | |||||
List fontCollections = new java.util.ArrayList(); | |||||
fontCollections.add(new Base14FontCollection(graphics2D)); | |||||
fontCollections.add(new InstalledFontCollection(graphics2D)); | |||||
final Java2DFontMetrics java2DFontMetrics = new Java2DFontMetrics(); | |||||
final List fontCollections = new java.util.ArrayList(); | |||||
fontCollections.add(new Base14FontCollection(java2DFontMetrics)); | |||||
fontCollections.add(new InstalledFontCollection(java2DFontMetrics)); | |||||
Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | ||||
if (cfg != null) { | if (cfg != null) { |
documents. Example: the fix of marks layering will be such a case when it's done. | documents. Example: the fix of marks layering will be such a case when it's done. | ||||
--> | --> | ||||
<release version="FOP Trunk" date="TBD"> | <release version="FOP Trunk" date="TBD"> | ||||
<action context="Renderers" dev="PH" type="fix" fixes-bug="48062"> | |||||
Improved fix of a bug relating to PCL painter thread safetly. Previous fix in rev 895012 | |||||
worked by synchronizing methods of a static instance of Java2DFontMetrics. This fix uses a | |||||
unique instance for per thread. | |||||
</action> | |||||
<action context="Renderers" dev="PH" type="fix"> | <action context="Renderers" dev="PH" type="fix"> | ||||
Fixed a bug in AFP where an ArrayOutofBoundsException is throwqn when embedding a Page | Fixed a bug in AFP where an ArrayOutofBoundsException is throwqn when embedding a Page | ||||
Segment. | Segment. |