aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java13
-rw-r--r--src/java/org/apache/fop/render/AbstractGenericSVGHandler.java21
-rw-r--r--src/java/org/apache/fop/render/afp/AFPSVGHandler.java20
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java13
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java1
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFSVGHandler.java15
-rw-r--r--src/java/org/apache/fop/render/ps/PSSVGHandler.java10
-rw-r--r--status.xml3
8 files changed, 70 insertions, 26 deletions
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
index 81c12a628..2bb521dc9 100644
--- a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
+++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
@@ -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);
}
diff --git a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
index 5c253fe94..35876a728 100644
--- a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
+++ b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
@@ -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();
diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java
index 9deea77b4..ca64d6bc2 100644
--- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java
@@ -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
diff --git a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java
index ba5c86059..2d16b120d 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java
@@ -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());
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index e31f1eaea..dda7e2083 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -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;
diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
index 5d027aefe..0bf9bd95b 100644
--- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
@@ -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());
diff --git a/src/java/org/apache/fop/render/ps/PSSVGHandler.java b/src/java/org/apache/fop/render/ps/PSSVGHandler.java
index 1e65dfb98..646cd3823 100644
--- a/src/java/org/apache/fop/render/ps/PSSVGHandler.java
+++ b/src/java/org/apache/fop/render/ps/PSSVGHandler.java
@@ -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");
diff --git a/status.xml b/status.xml
index 0f139fba7..b2e37dd33 100644
--- a/status.xml
+++ b/status.xml
@@ -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>