Fixed a multi-threading issue when rendering SVG. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@724163 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -23,6 +23,8 @@ import java.awt.Dimension; | |||
import java.awt.geom.AffineTransform; | |||
import java.util.Map; | |||
import org.w3c.dom.Document; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.GVTBuilder; | |||
import org.apache.batik.bridge.UserAgent; | |||
@@ -30,7 +32,7 @@ import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.svg.SimpleSVGUserAgent; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageException; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
@@ -43,6 +45,8 @@ import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.UnitConv; | |||
import org.apache.fop.svg.SimpleSVGUserAgent; | |||
/** | |||
* This ImageConverter converts SVG images to Java2D. | |||
* <p> | |||
@@ -75,10 +79,15 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { | |||
GVTBuilder builder = new GVTBuilder(); | |||
final BridgeContext ctx = new BridgeContext(ua); | |||
Document doc = svg.getDocument(); | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = BatikUtil.cloneSVGDocument(doc); | |||
//Build the GVT tree | |||
final GraphicsNode root; | |||
try { | |||
root = builder.build(ctx, svg.getDocument()); | |||
root = builder.build(ctx, clonedDoc); | |||
} catch (Exception e) { | |||
throw new ImageException("GVT tree could not be built for SVG graphic", e); | |||
} |
@@ -24,22 +24,25 @@ import java.awt.Dimension; | |||
import java.awt.geom.AffineTransform; | |||
import java.io.IOException; | |||
import org.w3c.dom.Document; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.GVTBuilder; | |||
import org.apache.batik.dom.AbstractDocument; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.dom.util.DOMUtilities; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.events.EventBroadcaster; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; | |||
import org.apache.fop.render.RendererContext.RendererContextWrapper; | |||
import org.apache.fop.render.afp.AFPGraphics2DAdapter; | |||
import org.apache.fop.svg.SVGEventProducer; | |||
import org.apache.fop.svg.SVGUserAgent; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.w3c.dom.Document; | |||
/** | |||
* Generic XML handler for SVG. Uses Apache Batik for SVG processing and simply paints to | |||
@@ -133,15 +136,19 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC | |||
//Create Batik BridgeContext | |||
final BridgeContext bridgeContext = new BridgeContext(svgUserAgent); | |||
//Build the GVT tree | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); | |||
final GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, doc); | |||
//Build the GVT tree | |||
final GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc); | |||
// Create Graphics2DImagePainter | |||
final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext( | |||
rendererContext); | |||
Dimension imageSize = getImageSize(wrappedContext); | |||
final Graphics2DImagePainter painter = createGraphics2DImagePainter(root, bridgeContext, imageSize); | |||
final Graphics2DImagePainter painter = createGraphics2DImagePainter( | |||
root, bridgeContext, imageSize); | |||
//Let the painter paint the SVG on the Graphics2D instance | |||
Graphics2DAdapter g2dAdapter = rendererContext.getRenderer().getGraphics2DAdapter(); |
@@ -24,9 +24,18 @@ import java.awt.Dimension; | |||
import java.awt.geom.AffineTransform; | |||
import java.io.IOException; | |||
import org.w3c.dom.Document; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.dom.util.DOMUtilities; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.MimeConstants; | |||
import org.apache.fop.afp.AFPGraphics2D; | |||
import org.apache.fop.afp.AFPGraphicsObjectInfo; | |||
import org.apache.fop.afp.AFPObjectAreaInfo; | |||
@@ -44,11 +53,6 @@ import org.apache.fop.render.RendererContext; | |||
import org.apache.fop.render.RendererContext.RendererContextWrapper; | |||
import org.apache.fop.svg.SVGEventProducer; | |||
import org.apache.fop.svg.SVGUserAgent; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.MimeConstants; | |||
import org.w3c.dom.Document; | |||
/** | |||
* AFP XML handler for SVG. Uses Apache Batik for SVG processing. | |||
@@ -107,8 +111,12 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { | |||
// Create an AFPBridgeContext | |||
BridgeContext bridgeContext = createBridgeContext(userAgent, g2d); | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); | |||
// Build the SVG DOM and provide the painter with it | |||
GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, doc); | |||
GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc); | |||
// Create Graphics2DImagePainter | |||
final RendererContextWrapper wrappedContext |
@@ -23,18 +23,21 @@ import java.awt.geom.AffineTransform; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
import org.w3c.dom.Document; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.GVTBuilder; | |||
import org.apache.batik.dom.util.DOMUtilities; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.render.AbstractGenericSVGHandler; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.RendererContext; | |||
import org.apache.fop.render.RendererContextConstants; | |||
import org.apache.fop.svg.SVGEventProducer; | |||
import org.apache.fop.svg.SVGUserAgent; | |||
import org.w3c.dom.Document; | |||
/** | |||
* Java2D XML handler for SVG (uses Apache Batik). | |||
@@ -128,12 +131,16 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler | |||
SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(), new AffineTransform()); | |||
GVTBuilder builder = new GVTBuilder(); | |||
BridgeContext ctx = new BridgeContext(ua); | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); | |||
GraphicsNode root; | |||
try { | |||
root = builder.build(ctx, doc); | |||
GVTBuilder builder = new GVTBuilder(); | |||
root = builder.build(ctx, clonedDoc); | |||
} catch (Exception e) { | |||
SVGEventProducer eventProducer = SVGEventProducer.Provider.get( | |||
context.getUserAgent().getEventBroadcaster()); |
@@ -1635,6 +1635,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { | |||
(int)pos.getHeight()); | |||
uri = URISpecification.getURL(uri); | |||
uri = URISpecification.preResolveURI(uri, userAgent.getBaseURL()); | |||
PDFXObject xobject = pdfDoc.getXObject(uri); | |||
if (xobject != null) { | |||
float w = (float) pos.getWidth() / 1000f; |
@@ -25,14 +25,18 @@ import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.Map; | |||
import org.w3c.dom.Document; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.GVTBuilder; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.dom.util.DOMUtilities; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.batik.util.SVGConstants; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.pdf.PDFDocument; | |||
@@ -49,7 +53,6 @@ import org.apache.fop.svg.PDFBridgeContext; | |||
import org.apache.fop.svg.PDFGraphics2D; | |||
import org.apache.fop.svg.SVGEventProducer; | |||
import org.apache.fop.svg.SVGUserAgent; | |||
import org.w3c.dom.Document; | |||
/** | |||
* PDF XML handler for SVG (uses Apache Batik). | |||
@@ -164,8 +167,6 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler | |||
AffineTransform resolutionScaling = new AffineTransform(); | |||
resolutionScaling.scale(s, s); | |||
GVTBuilder builder = new GVTBuilder(); | |||
//Controls whether text painted by Batik is generated using text or path operations | |||
boolean strokeText = false; | |||
Configuration cfg = pdfInfo.cfg; | |||
@@ -179,10 +180,14 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler | |||
userAgent.getImageSessionContext(), | |||
new AffineTransform()); | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); | |||
GraphicsNode root; | |||
try { | |||
root = builder.build(ctx, doc); | |||
builder = null; | |||
GVTBuilder builder = new GVTBuilder(); | |||
root = builder.build(ctx, clonedDoc); | |||
} catch (Exception e) { | |||
SVGEventProducer eventProducer = SVGEventProducer.Provider.get( | |||
context.getUserAgent().getEventBroadcaster()); |
@@ -29,6 +29,7 @@ import org.w3c.dom.Document; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.GVTBuilder; | |||
import org.apache.batik.dom.util.DOMUtilities; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -258,7 +259,6 @@ public class PSSVGHandler extends AbstractGenericSVGHandler | |||
PSGraphics2D graphics = new PSGraphics2D(strokeText, gen); | |||
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); | |||
GVTBuilder builder = new GVTBuilder(); | |||
NativeTextHandler nativeTextHandler = null; | |||
BridgeContext ctx = new BridgeContext(ua); | |||
if (!strokeText) { | |||
@@ -271,9 +271,14 @@ public class PSSVGHandler extends AbstractGenericSVGHandler | |||
ctx.putBridge(tBridge); | |||
} | |||
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) | |||
//to it. | |||
Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); | |||
GraphicsNode root; | |||
try { | |||
root = builder.build(ctx, doc); | |||
GVTBuilder builder = new GVTBuilder(); | |||
root = builder.build(ctx, clonedDoc); | |||
} catch (Exception e) { | |||
SVGEventProducer eventProducer = SVGEventProducer.Provider.get( | |||
context.getUserAgent().getEventBroadcaster()); | |||
@@ -288,7 +293,6 @@ public class PSSVGHandler extends AbstractGenericSVGHandler | |||
float sy = psInfo.getHeight() / h; | |||
ctx = null; | |||
builder = null; | |||
try { | |||
gen.commentln("%FOPBeginSVG"); |
@@ -53,6 +53,9 @@ | |||
<changes> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Renderers" dev="JM" type="fix" fixed-bug="46360"> | |||
Fixed a multi-threading issue when rendering SVG. | |||
</action> | |||
<action context="Renderers" dev="AC" importance="high" type="add"> | |||
AFP Output: An AFPGraphics2D implementation which provides the ability to use Batik to drive the production of AFP Graphics (GOCA) output from SVG. | |||
</action> |