diff options
21 files changed, 779 insertions, 583 deletions
@@ -376,6 +376,11 @@ list of possible build targets. <patternset refid="exclude-jimi"/> <classpath refid="libs-build-classpath"/> </javac> + <copy todir="${build.classes.dir}"> + <fileset dir="${src.java.dir}"> + <include name="META-INF/**"/> + </fileset> + </copy> <mkdir dir="${build.viewer.resources.dir}"/> <copy todir="${build.viewer.resources.dir}"> <fileset dir="${src.viewer.resources.dir}"/> @@ -451,7 +456,7 @@ list of possible build targets. <tstamp> <format property="ts" pattern="yyyyMMdd-HHmmss-z"/> </tstamp> - <jar jarfile="${build.dir}/fop.jar" basedir="${build.classes.dir}" includes="org/**"> + <jar jarfile="${build.dir}/fop.jar" basedir="${build.classes.dir}"> <manifest> <attribute name="Main-Class" value="org.apache.fop.cli.Main"/> <attribute name="Build-Id" value="${ts} (${user.name} [${os.name} ${os.version} ${os.arch}, Java ${java.runtime.version}])"/> diff --git a/conf/fop.xconf b/conf/fop.xconf index 243226574..c542c8953 100644 --- a/conf/fop.xconf +++ b/conf/fop.xconf @@ -79,14 +79,18 @@ the location of this file. --> </fonts> - <xmlHandler mime="text/svg+xml"> - </xmlHandler> + <!-- This option lets you specify additional options on an XML handler --> + <!--xml-handler namespace="http://www.w3.org/2000/svg"> + <stroke-text>false</stroke-text> + </xml-handler--> </renderer> <renderer mime="application/postscript"> - <xmlHandler mime="image/svg+xml"> - </xmlHandler> + <!-- This option lets you specify additional options on an XML handler --> + <!--xml-handler namespace="http://www.w3.org/2000/svg"> + <stroke-text>false</stroke-text> + </xml-handler--> </renderer> <renderer mime="application/vnd.hp-PCL"> diff --git a/src/java/META-INF/services/org.apache.fop.render.XMLHandler b/src/java/META-INF/services/org.apache.fop.render.XMLHandler new file mode 100644 index 000000000..96c44118c --- /dev/null +++ b/src/java/META-INF/services/org.apache.fop.render.XMLHandler @@ -0,0 +1,3 @@ +org.apache.fop.render.pdf.PDFSVGHandler
+org.apache.fop.render.ps.PSSVGHandler
+org.apache.fop.render.java2d.Java2DSVGHandler
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 3192cce1d..bb84fde27 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -19,7 +19,6 @@ package org.apache.fop.render; // Java -import java.awt.Dimension; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.io.IOException; @@ -767,6 +766,39 @@ public abstract class AbstractRenderer } /** + * Returns the configuration subtree for a specific renderer. + * @param cfg the renderer configuration + * @param namespace the namespace (i.e. the XMLHandler) for which the configuration should + * be returned + * @return the requested configuration subtree, null if there's no configuration + */ + public static Configuration getHandlerConfig(Configuration cfg, String namespace) { + + if (cfg == null || namespace == null) { + return null; + } + + Configuration handlerConfig = null; + + Configuration[] children = cfg.getChildren("xml-handler"); + for (int i = 0; i < children.length; ++i) { + try { + if (children[i].getAttribute("namespace").equals(namespace)) { + handlerConfig = children[i]; + break; + } + } catch (ConfigurationException e) { + // silently pass over configurations without namespace + } + } + if (log.isDebugEnabled()) { + log.debug((handlerConfig == null ? "No" : "") + + "XML handler configuration found for namespace " + namespace); + } + return handlerConfig; + } + + /** * Render the xml document with the given xml namespace. * The Render Context is by the handle to render into the current * rendering target. @@ -776,11 +808,19 @@ public abstract class AbstractRenderer */ public void renderXML(RendererContext ctx, Document doc, String namespace) { - String mime = ctx.getMimeType(); XMLHandler handler = userAgent.getXMLHandlerRegistry().getXMLHandler( - mime, namespace); + this, namespace); if (handler != null) { try { + //Optional XML handler configuration + Configuration cfg = userAgent.getUserRendererConfig(getMimeType()); + if (cfg != null) { + cfg = getHandlerConfig(cfg, namespace); + if (cfg != null) { + ctx.setProperty(RendererContextConstants.HANDLER_CONFIGURATION, cfg); + } + } + handler.handleXML(ctx, doc, namespace); } catch (Throwable t) { // could not handle document diff --git a/src/java/org/apache/fop/render/RendererContextConstants.java b/src/java/org/apache/fop/render/RendererContextConstants.java new file mode 100644 index 000000000..1d219cab2 --- /dev/null +++ b/src/java/org/apache/fop/render/RendererContextConstants.java @@ -0,0 +1,44 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface RendererContextConstants { + + /** The output stream that the document is being sent to. */ + String OUTPUT_STREAM = "outputStream"; + + /** The target width of the image being painted. */ + String WIDTH = "width"; + + /** The target height of the image being painted. */ + String HEIGHT = "height"; + + /** The x position that this image is being drawn at. */ + String XPOS = "xpos"; + + /** The y position that this image is being drawn at. */ + String YPOS = "ypos"; + + /** The configuration for the XMLHandler. */ + String HANDLER_CONFIGURATION = "cfg"; + +} diff --git a/src/java/org/apache/fop/render/XMLHandler.java b/src/java/org/apache/fop/render/XMLHandler.java index 683479e93..f1740594a 100644 --- a/src/java/org/apache/fop/render/XMLHandler.java +++ b/src/java/org/apache/fop/render/XMLHandler.java @@ -49,9 +49,11 @@ public interface XMLHandler { Document doc, String ns) throws Exception; /** - * @return the MIME type for which this XMLHandler was written + * Checks if this XMLHandler supports handling an XML namespace for a particular renderer. + * @param renderer the renderer for which to check. + * @return true if this XML handler supports a particular renderer */ - String getMimeType(); + boolean supportsRenderer(Renderer renderer); /** * @return the XML namespace for the XML dialect this XMLHandler supports, diff --git a/src/java/org/apache/fop/render/XMLHandlerRegistry.java b/src/java/org/apache/fop/render/XMLHandlerRegistry.java index 5712ca3fa..e033c2d4e 100644 --- a/src/java/org/apache/fop/render/XMLHandlerRegistry.java +++ b/src/java/org/apache/fop/render/XMLHandlerRegistry.java @@ -19,6 +19,7 @@ package org.apache.fop.render;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
@@ -38,7 +39,6 @@ public class XMLHandlerRegistry { /** Map containing XML handlers for various document types */
private Map handlers = new java.util.HashMap();
-
/**
* Default constructor.
*/
@@ -47,13 +47,11 @@ public class XMLHandlerRegistry { }
/**
- * Set the default XML handler for the given MIME type.
- * @param mime MIME type
+ * Add a default XML handler which is able to handle any namespace.
* @param handler XMLHandler to use
*/
- private void setDefaultXMLHandler(String mime,
- XMLHandler handler) {
- addXMLHandler(mime, XMLHandler.HANDLE_ALL, handler);
+ private void setDefaultXMLHandler(XMLHandler handler) {
+ addXMLHandler(XMLHandler.HANDLE_ALL, handler);
}
/**
@@ -62,8 +60,7 @@ public class XMLHandlerRegistry { */
public void addXMLHandler(String classname) {
try {
- XMLHandler handlerInstance =
- (XMLHandler)Class.forName(classname).newInstance();
+ XMLHandler handlerInstance = (XMLHandler)Class.forName(classname).newInstance();
addXMLHandler(handlerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
@@ -86,58 +83,53 @@ public class XMLHandlerRegistry { * @param handler the XMLHandler instance
*/
public void addXMLHandler(XMLHandler handler) {
- String mime = handler.getMimeType();
String ns = handler.getNamespace();
if (ns == null) {
- setDefaultXMLHandler(mime, handler);
+ setDefaultXMLHandler(handler);
} else {
- addXMLHandler(mime, ns, handler);
+ addXMLHandler(ns, handler);
}
}
/**
* Add an XML handler for the given MIME type and XML namespace.
- * @param mime MIME type
* @param ns Namespace URI
* @param handler XMLHandler to use
*/
- private void addXMLHandler(String mime, String ns,
+ private void addXMLHandler(String ns,
XMLHandler handler) {
- Map mh = (Map)handlers.get(mime);
- if (mh == null) {
- mh = new java.util.HashMap();
- handlers.put(mime, mh);
+ List lst = (List)handlers.get(ns);
+ if (lst == null) {
+ lst = new java.util.ArrayList();
+ handlers.put(ns, lst);
}
- mh.put(ns, handler);
+ lst.add(handler);
}
/**
* Returns an XMLHandler which handles an XML dialect of the given namespace and for
* a specified output format defined by its MIME type.
- * @param mime the MIME type of the output format
+ * @param renderer the Renderer for which to retrieve a Renderer
* @param ns the XML namespace associated with the XML to be rendered
* @return the XMLHandler responsible for handling the XML or null if none is available
*/
- public XMLHandler getXMLHandler(String mime, String ns) {
- XMLHandler handler = null;
+ public XMLHandler getXMLHandler(Renderer renderer, String ns) {
+ XMLHandler handler;
- Map mh = (Map)handlers.get(mime);
- if (mh != null) {
- handler = (XMLHandler)mh.get(ns);
- if (handler == null) {
- handler = (XMLHandler)mh.get(XMLHandler.HANDLE_ALL);
- }
+ List lst = (List)handlers.get(ns);
+ if (lst == null) {
+ lst = (List)handlers.get(XMLHandler.HANDLE_ALL);
}
- if (handler == null) {
- mh = (Map)handlers.get(XMLHandler.HANDLE_ALL);
- if (mh != null) {
- handler = (XMLHandler)mh.get(ns);
- if (handler == null) {
- handler = (XMLHandler)mh.get(XMLHandler.HANDLE_ALL);
+ if (lst != null) {
+ for (int i = 0, c = lst.size(); i < c; i++) {
+ //TODO Maybe add priorities later
+ handler = (XMLHandler)lst.get(i);
+ if (handler.supportsRenderer(renderer)) {
+ return handler;
}
}
}
- return handler;
+ return null; //No handler found
}
@@ -147,8 +139,7 @@ public class XMLHandlerRegistry { */
private void discoverXMLHandlers() {
// add mappings from available services
- Iterator providers =
- Service.providers(XMLHandler.class);
+ Iterator providers = Service.providers(XMLHandler.class);
if (providers != null) {
while (providers.hasNext()) {
String str = (String)providers.next();
diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index b1fc3568d..9b0e76f33 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -155,8 +155,6 @@ public abstract class Java2DRenderer extends AbstractRenderer implements Printab */ public void setUserAgent(FOUserAgent foUserAgent) { super.setUserAgent(foUserAgent); - Java2DSVGHandler xmlHandler = new Java2DSVGHandler(getMimeType()); - userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler); userAgent.setRendererOverride(this); // for document regeneration } @@ -1148,14 +1146,14 @@ public abstract class Java2DRenderer extends AbstractRenderer implements Printab context = new RendererContext(this, getMimeType()); context.setUserAgent(userAgent); - context.setProperty(Java2DSVGHandler.JAVA2D_STATE, state); - context.setProperty(Java2DSVGHandler.JAVA2D_XPOS, + context.setProperty(Java2DRendererContextConstants.JAVA2D_STATE, state); + context.setProperty(Java2DRendererContextConstants.XPOS, new Integer(currentIPPosition + (int)pos.getX())); - context.setProperty(Java2DSVGHandler.JAVA2D_YPOS, + context.setProperty(Java2DRendererContextConstants.YPOS, new Integer(currentBPPosition + (int)pos.getY())); - context.setProperty(Java2DSVGHandler.JAVA2D_WIDTH, + context.setProperty(Java2DRendererContextConstants.WIDTH, new Integer((int)pos.getWidth())); - context.setProperty(Java2DSVGHandler.JAVA2D_HEIGHT, + context.setProperty(Java2DRendererContextConstants.HEIGHT, new Integer((int) pos.getHeight())); renderXML(context, doc, ns); diff --git a/src/java/org/apache/fop/render/java2d/Java2DRendererContextConstants.java b/src/java/org/apache/fop/render/java2d/Java2DRendererContextConstants.java new file mode 100644 index 000000000..9480c1520 --- /dev/null +++ b/src/java/org/apache/fop/render/java2d/Java2DRendererContextConstants.java @@ -0,0 +1,32 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.java2d; + +import org.apache.fop.render.RendererContextConstants; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface Java2DRendererContextConstants extends + RendererContextConstants { + + /** The current Java2DGraphicsState. */ + String JAVA2D_STATE = "state"; + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java index fbf8382eb..c7fc7e9d3 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java +++ b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java @@ -18,79 +18,50 @@ package org.apache.fop.render.java2d; +import java.awt.geom.AffineTransform; + +import org.w3c.dom.Document; + +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.Renderer; import org.apache.fop.render.XMLHandler; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.pdf.PDFRenderer; import org.apache.fop.svg.SVGUserAgent; // Commons-Logging import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -/* org.w3c.dom.Document is not imported to avoid conflict with - org.apache.fop.apps.Document */ - import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.gvt.GraphicsNode; -import java.awt.geom.AffineTransform; - /** * Java2D XML handler for SVG (uses Apache Batik). * This handler handles XML for foreign objects when rendering to Java2D. * The properties from the Java2D renderer are subject to change. */ -public class Java2DSVGHandler implements XMLHandler { - - /** - * logging instance - */ - private Log log = LogFactory.getLog(Java2DSVGHandler.class); - - /** - * The current Java2DGraphicsState. - */ - public static final String JAVA2D_STATE = "state"; - - /** - * The width of the svg image/document to render. - */ - public static final String JAVA2D_WIDTH = "width"; +public class Java2DSVGHandler implements XMLHandler, Java2DRendererContextConstants { - /** - * The height of the svg image/document to render. - */ - public static final String JAVA2D_HEIGHT = "height"; - - /** - * The x position that this is being drawn at. - */ - public static final String JAVA2D_XPOS = "xpos"; + /** logging instance */ + private static Log log = LogFactory.getLog(Java2DSVGHandler.class); /** - * The y position that this is being drawn at. + * Create a new Java2D XML handler for use by the Java2D renderer and its subclasses. */ - public static final String JAVA2D_YPOS = "ypos"; - - private String mimeType; - - /** - * Create a new Java2D XML handler for use by the Java2D renderer. - * @param mime MIME type that this handler is used for - */ - public Java2DSVGHandler(String mime) { - this.mimeType = mime; + public Java2DSVGHandler() { + //nop } /** @see org.apache.fop.render.XMLHandler */ public void handleXML(RendererContext context, - org.w3c.dom.Document doc, String ns) throws Exception { + Document doc, String ns) throws Exception { Java2DInfo pdfi = getJava2DInfo(context); if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { - SVGHandler svghandler = new SVGHandler(); - svghandler.renderSVGDocument(context, doc, pdfi); + renderSVGDocument(context, doc, pdfi); } } @@ -103,10 +74,10 @@ public class Java2DSVGHandler implements XMLHandler { public static Java2DInfo getJava2DInfo(RendererContext context) { Java2DInfo pdfi = new Java2DInfo(); pdfi.state = (Java2DGraphicsState)context.getProperty(JAVA2D_STATE); - pdfi.width = ((Integer)context.getProperty(JAVA2D_WIDTH)).intValue(); - pdfi.height = ((Integer)context.getProperty(JAVA2D_HEIGHT)).intValue(); - pdfi.currentXPosition = ((Integer)context.getProperty(JAVA2D_XPOS)).intValue(); - pdfi.currentYPosition = ((Integer)context.getProperty(JAVA2D_YPOS)).intValue(); + pdfi.width = ((Integer)context.getProperty(WIDTH)).intValue(); + pdfi.height = ((Integer)context.getProperty(HEIGHT)).intValue(); + pdfi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); + pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); return pdfi; } @@ -137,75 +108,69 @@ public class Java2DSVGHandler implements XMLHandler { } /** - * This method is placed in an inner class so that we don't get class - * loading errors if batik is not present. + * Render the svg document. + * @param context the renderer context + * @param doc the svg document + * @param info the pdf information of the current context */ - protected class SVGHandler { + protected void renderSVGDocument(RendererContext context, + Document doc, + Java2DInfo info) { + + log.debug("renderSVGDocument(" + context + ", " + doc + ", " + info + ")"); + + int x = info.currentXPosition; + int y = info.currentYPosition; + + float ptom = context.getUserAgent().getSourcePixelUnitToMillimeter(); + SVGUserAgent ua = new SVGUserAgent(ptom, new AffineTransform()); - /** - * Render the svg document. - * @param context the renderer context - * @param doc the svg document - * @param info the pdf information of the current context - */ - protected void renderSVGDocument(RendererContext context, - org.w3c.dom.Document doc, - Java2DInfo info) { - - log.debug("renderSVGDocument(" + context + ", " + doc + ", " + info + ")"); - - int x = info.currentXPosition; - int y = info.currentYPosition; - - float ptom = context.getUserAgent().getSourcePixelUnitToMillimeter(); - SVGUserAgent ua = new SVGUserAgent(ptom, new AffineTransform()); - - GVTBuilder builder = new GVTBuilder(); - BridgeContext ctx = new BridgeContext(ua); - - GraphicsNode root; - try { - root = builder.build(ctx, doc); - } catch (Exception e) { - log.error("SVG graphic could not be built: " + e.getMessage(), e); - return; - } - - // If no viewbox is defined in the svg file, a viewbox of 100x100 is - // assumed, as defined in SVGUserAgent.getViewportSize() - float iw = (float) ctx.getDocumentSize().getWidth() * 1000f; - float ih = (float) ctx.getDocumentSize().getHeight() * 1000f; - - float w = (float) info.width; - float h = (float) info.height; - - AffineTransform origTransform = info.state.getGraph().getTransform(); - - // correct integer roundoff - info.state.getGraph().translate(x / 1000f, y / 1000f); - - //SVGSVGElement svg = ((SVGDocument) doc).getRootElement(); - // Aspect ratio preserved by layout engine, not here - AffineTransform at = AffineTransform.getScaleInstance(w / iw, h / ih); - if (!at.isIdentity()) { - info.state.getGraph().transform(at); - } - - try { - root.paint(info.state.getGraph()); - } catch (Exception e) { - log.error("Error while painting SVG", e); - } - - info.state.getGraph().setTransform(origTransform); + GVTBuilder builder = new GVTBuilder(); + BridgeContext ctx = new BridgeContext(ua); + + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + log.error("SVG graphic could not be built: " + e.getMessage(), e); + return; } + + // If no viewbox is defined in the svg file, a viewbox of 100x100 is + // assumed, as defined in SVGUserAgent.getViewportSize() + float iw = (float) ctx.getDocumentSize().getWidth() * 1000f; + float ih = (float) ctx.getDocumentSize().getHeight() * 1000f; + + float w = (float) info.width; + float h = (float) info.height; + + AffineTransform origTransform = info.state.getGraph().getTransform(); + + // correct integer roundoff + info.state.getGraph().translate(x / 1000f, y / 1000f); + + //SVGSVGElement svg = ((SVGDocument) doc).getRootElement(); + // Aspect ratio preserved by layout engine, not here + AffineTransform at = AffineTransform.getScaleInstance(w / iw, h / ih); + if (!at.isIdentity()) { + info.state.getGraph().transform(at); + } + + try { + root.paint(info.state.getGraph()); + } catch (Exception e) { + log.error("Error while painting SVG", e); + } + + info.state.getGraph().setTransform(origTransform); } - /** @see org.apache.fop.render.XMLHandler#getMimeType() */ - public String getMimeType() { - return this.mimeType; + /** @see org.apache.fop.render.XMLHandler#supportsRenderer() */ + public boolean supportsRenderer(Renderer renderer) { + return (renderer instanceof Java2DRenderer); } + /** @see org.apache.fop.render.XMLHandler#getNamespace() */ public String getNamespace() { return SVGDOMImplementation.SVG_NAMESPACE_URI; diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index c2e31b0c5..66d46b7e2 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -234,8 +234,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); - PDFSVGHandler xmlHandler = new PDFSVGHandler(); - userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler); } /** @@ -1468,25 +1466,25 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { context = new RendererContext(this, MIME_TYPE); context.setUserAgent(userAgent); - context.setProperty(PDFSVGHandler.PDF_DOCUMENT, pdfDoc); - context.setProperty(PDFSVGHandler.OUTPUT_STREAM, ostream); - context.setProperty(PDFSVGHandler.PDF_STATE, currentState); - context.setProperty(PDFSVGHandler.PDF_PAGE, currentPage); - context.setProperty(PDFSVGHandler.PDF_CONTEXT, + context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc); + context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream); + context.setProperty(PDFRendererContextConstants.PDF_STATE, currentState); + context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage); + context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext == null ? currentPage : currentContext); - context.setProperty(PDFSVGHandler.PDF_CONTEXT, currentContext); - context.setProperty(PDFSVGHandler.PDF_STREAM, currentStream); - context.setProperty(PDFSVGHandler.PDF_XPOS, + context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext); + context.setProperty(PDFRendererContextConstants.PDF_STREAM, currentStream); + context.setProperty(PDFRendererContextConstants.XPOS, new Integer(currentIPPosition + (int) pos.getX())); - context.setProperty(PDFSVGHandler.PDF_YPOS, + context.setProperty(PDFRendererContextConstants.YPOS, new Integer(currentBPPosition + (int) pos.getY())); - context.setProperty(PDFSVGHandler.PDF_FONT_INFO, fontInfo); - context.setProperty(PDFSVGHandler.PDF_FONT_NAME, currentFontName); - context.setProperty(PDFSVGHandler.PDF_FONT_SIZE, + context.setProperty(PDFRendererContextConstants.PDF_FONT_INFO, fontInfo); + context.setProperty(PDFRendererContextConstants.PDF_FONT_NAME, currentFontName); + context.setProperty(PDFRendererContextConstants.PDF_FONT_SIZE, new Integer(currentFontSize)); - context.setProperty(PDFSVGHandler.PDF_WIDTH, + context.setProperty(PDFRendererContextConstants.WIDTH, new Integer((int) pos.getWidth())); - context.setProperty(PDFSVGHandler.PDF_HEIGHT, + context.setProperty(PDFRendererContextConstants.HEIGHT, new Integer((int) pos.getHeight())); renderXML(context, doc, ns); diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java new file mode 100644 index 000000000..f2144dfe3 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java @@ -0,0 +1,52 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.pdf; + +import org.apache.fop.render.RendererContextConstants; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface PDFRendererContextConstants extends RendererContextConstants { + + /** The PDF document that this image is being drawn into. */ + String PDF_DOCUMENT = "pdfDoc"; + + /** The current pdf state. */ + String PDF_STATE = "pdfState"; + + /** The current PDF page for page renference and as a resource context. */ + String PDF_PAGE = "pdfPage"; + + /** The current PDF page for page renference and as a resource context. */ + String PDF_CONTEXT = "pdfContext"; + + /** The current PDF stream to draw directly to. */ + String PDF_STREAM = "pdfStream"; + + /** The current font information for the pdf renderer. */ + String PDF_FONT_INFO = "fontInfo"; + + /** The current pdf font name. */ + String PDF_FONT_NAME = "fontName"; + + /** The current pdf font size. */ + String PDF_FONT_SIZE = "fontSize"; + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java index 673cd0cdb..af93477d5 100644 --- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java @@ -18,6 +18,15 @@ package org.apache.fop.render.pdf; +import java.io.OutputStream; +import java.awt.Color; +import java.awt.geom.AffineTransform; + +import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGSVGElement; + +import org.apache.fop.render.Renderer; import org.apache.fop.render.XMLHandler; import org.apache.fop.render.RendererContext; import org.apache.fop.pdf.PDFDocument; @@ -35,102 +44,25 @@ import org.apache.fop.fonts.FontInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -/* org.w3c.dom.Document is not imported to avoid conflict with - org.apache.fop.apps.Document */ - -import java.io.OutputStream; +import org.apache.avalon.framework.configuration.Configuration; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.ViewBox; import org.apache.batik.dom.svg.SVGDOMImplementation; - import org.apache.batik.gvt.GraphicsNode; -import org.w3c.dom.svg.SVGDocument; -import org.w3c.dom.svg.SVGSVGElement; - -import java.awt.Color; -import java.awt.geom.AffineTransform; - /** * PDF XML handler for SVG (uses Apache Batik). * This handler handles XML for foreign objects when rendering to PDF. * It renders SVG to the PDF document using the PDFGraphics2D. * The properties from the PDF renderer are subject to change. */ -public class PDFSVGHandler implements XMLHandler { +public class PDFSVGHandler implements XMLHandler, PDFRendererContextConstants { - /** - * logging instance - */ - private Log log = LogFactory.getLog(PDFSVGHandler.class); + /** logging instance */ + private static Log log = LogFactory.getLog(PDFSVGHandler.class); - /** - * The PDF document that is being drawn into. - */ - public static final String PDF_DOCUMENT = "pdfDoc"; - - /** - * The output stream that the document is being sent to. - */ - public static final String OUTPUT_STREAM = "outputStream"; - - /** - * The current pdf state. - */ - public static final String PDF_STATE = "pdfState"; - - /** - * The current PDF page for page renference and as a resource context. - */ - public static final String PDF_PAGE = "pdfPage"; - - /** - * The current PDF page for page renference and as a resource context. - */ - public static final String PDF_CONTEXT = "pdfContext"; - - /** - * The current PDF stream to draw directly to. - */ - public static final String PDF_STREAM = "pdfStream"; - - /** - * The width of the current pdf page. - */ - public static final String PDF_WIDTH = "width"; - - /** - * The height of the current pdf page. - */ - public static final String PDF_HEIGHT = "height"; - - /** - * The current font information for the pdf renderer. - */ - public static final String PDF_FONT_INFO = "fontInfo"; - - /** - * The current pdf font name. - */ - public static final String PDF_FONT_NAME = "fontName"; - - /** - * The current pdf font size. - */ - public static final String PDF_FONT_SIZE = "fontSize"; - - /** - * The x position that this is being drawn at. - */ - public static final String PDF_XPOS = "xpos"; - - /** - * The y position that this is being drawn at. - */ - public static final String PDF_YPOS = "ypos"; /** * Create a new PDF XML handler for use by the PDF renderer. @@ -140,13 +72,12 @@ public class PDFSVGHandler implements XMLHandler { /** @see org.apache.fop.render.XMLHandler */ public void handleXML(RendererContext context, - org.w3c.dom.Document doc, String ns) throws Exception { + Document doc, String ns) throws Exception { PDFInfo pdfi = getPDFInfo(context); String svg = "http://www.w3.org/2000/svg"; if (svg.equals(ns)) { - SVGHandler svghandler = new SVGHandler(); - svghandler.renderSVGDocument(context, doc, pdfi); + renderSVGDocument(context, doc, pdfi); } } @@ -164,13 +95,14 @@ public class PDFSVGHandler implements XMLHandler { pdfi.pdfPage = (PDFPage)context.getProperty(PDF_PAGE); pdfi.pdfContext = (PDFResourceContext)context.getProperty(PDF_CONTEXT); pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM); - pdfi.width = ((Integer)context.getProperty(PDF_WIDTH)).intValue(); - pdfi.height = ((Integer)context.getProperty(PDF_HEIGHT)).intValue(); - pdfi.fi = (FontInfo) context.getProperty(PDF_FONT_INFO); + pdfi.width = ((Integer)context.getProperty(WIDTH)).intValue(); + pdfi.height = ((Integer)context.getProperty(HEIGHT)).intValue(); + pdfi.fi = (FontInfo)context.getProperty(PDF_FONT_INFO); pdfi.currentFontName = (String)context.getProperty(PDF_FONT_NAME); pdfi.currentFontSize = ((Integer)context.getProperty(PDF_FONT_SIZE)).intValue(); - pdfi.currentXPosition = ((Integer)context.getProperty(PDF_XPOS)).intValue(); - pdfi.currentYPosition = ((Integer)context.getProperty(PDF_YPOS)).intValue(); + pdfi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); + pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); + pdfi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION); return pdfi; } @@ -204,134 +136,135 @@ public class PDFSVGHandler implements XMLHandler { public int currentXPosition; /** see PDF_YPOS */ public int currentYPosition; + /** see PDF_HANDLER_CONFIGURATION */ + public Configuration cfg; } /** - * This method is placed in an inner class so that we don't get class - * loading errors if batik is not present. + * Render the svg document. + * @param context the renderer context + * @param doc the svg document + * @param pdfInfo the pdf information of the current context */ - protected class SVGHandler { - /** - * Render the svg document. - * @param context the renderer context - * @param doc the svg document - * @param pdfInfo the pdf information of the current context - */ - protected void renderSVGDocument(RendererContext context, - org.w3c.dom.Document doc, PDFInfo pdfInfo) { - int xOffset = pdfInfo.currentXPosition; - int yOffset = pdfInfo.currentYPosition; - - log.debug("Generating SVG at " - + context.getUserAgent().getTargetResolution() - + "dpi."); - final float deviceResolution = context.getUserAgent().getTargetResolution(); - - final float uaResolution = context.getUserAgent().getSourceResolution(); - SVGUserAgent ua = new SVGUserAgent(25.4f / uaResolution, new AffineTransform()); - - GVTBuilder builder = new GVTBuilder(); - - //TODO This AffineTransform here has to be fixed!!! - AffineTransform linkTransform = pdfInfo.pdfState.getTransform(); - linkTransform.translate(xOffset / 1000f, yOffset / 1000f); - - final boolean strokeText = false; - BridgeContext ctx = new PDFBridgeContext(ua, - (strokeText ? null : pdfInfo.fi), - linkTransform); - - GraphicsNode root; - try { - root = builder.build(ctx, doc); - } catch (Exception e) { - log.error("svg graphic could not be built: " - + e.getMessage(), e); - return; - } - // get the 'width' and 'height' attributes of the SVG document - float w = (float)ctx.getDocumentSize().getWidth() * 1000f; - float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - - float sx = pdfInfo.width / (float)w; - float sy = pdfInfo.height / (float)h; - - ctx = null; - builder = null; - - /* - * Clip to the svg area. - * Note: To have the svg overlay (under) a text area then use - * an fo:block-container - */ - PDFRenderer renderer = (PDFRenderer)context.getRenderer(); - renderer.saveGraphicsState(); - renderer.setColor(Color.black, false, null); - renderer.setColor(Color.black, true, null); - // transform so that the coordinates (0,0) is from the top left - // and positive is down and to the right. (0,0) is where the - // viewBox puts it. - pdfInfo.currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " " - + yOffset / 1000f + " cm\n"); - - SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); - //AffineTransform at = ViewBox.getPreserveAspectRatioTransform( - // svg, w / 1000f, h / 1000f); - AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, - pdfInfo.width / 1000f, pdfInfo.height / 1000f); - /* - if (!at.isIdentity()) { - double[] vals = new double[6]; - at.getMatrix(vals); - pdfInfo.currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n"); - }*/ + protected void renderSVGDocument(RendererContext context, + Document doc, PDFInfo pdfInfo) { + int xOffset = pdfInfo.currentXPosition; + int yOffset = pdfInfo.currentYPosition; + + log.debug("Generating SVG at " + + context.getUserAgent().getTargetResolution() + + "dpi."); + final float deviceResolution = context.getUserAgent().getTargetResolution(); + + final float uaResolution = context.getUserAgent().getSourceResolution(); + SVGUserAgent ua = new SVGUserAgent(25.4f / uaResolution, new AffineTransform()); + + GVTBuilder builder = new GVTBuilder(); + + //TODO This AffineTransform here has to be fixed!!! + AffineTransform linkTransform = pdfInfo.pdfState.getTransform(); + linkTransform.translate(xOffset / 1000f, yOffset / 1000f); + + //Controls whether text painted by Batik is generated using text or path operations + boolean strokeText = false; + Configuration cfg = pdfInfo.cfg; + if (cfg != null) { + strokeText = cfg.getChild("stroke-text", true).getValueAsBoolean(strokeText); + } + + BridgeContext ctx = new PDFBridgeContext(ua, + (strokeText ? null : pdfInfo.fi), + linkTransform); + + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + log.error("svg graphic could not be built: " + + e.getMessage(), e); + return; + } + // get the 'width' and 'height' attributes of the SVG document + float w = (float)ctx.getDocumentSize().getWidth() * 1000f; + float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - if (pdfInfo.pdfContext == null) { - pdfInfo.pdfContext = pdfInfo.pdfPage; - } - PDFGraphics2D graphics = new PDFGraphics2D(true, pdfInfo.fi, pdfInfo.pdfDoc, - pdfInfo.pdfContext, pdfInfo.pdfPage.referencePDF(), - pdfInfo.currentFontName, - pdfInfo.currentFontSize); - graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); - pdfInfo.pdfState.push(); - AffineTransform transform = new AffineTransform(); - // scale to viewbox - transform.translate(xOffset / 1000f, yOffset / 1000f); + float sx = pdfInfo.width / (float)w; + float sy = pdfInfo.height / (float)h; - if (deviceResolution != uaResolution) { - //Scale for higher resolution on-the-fly images from Batik - double s = uaResolution / deviceResolution; - at.scale(s, s); - pdfInfo.currentStream.add("" + PDFNumber.doubleOut(s) + " 0 0 " - + PDFNumber.doubleOut(s) + " 0 0 cm\n"); - graphics.scale(1 / s, 1 / s); - } + ctx = null; + builder = null; - pdfInfo.pdfState.setTransform(transform); - graphics.setPDFState(pdfInfo.pdfState); - graphics.setOutputStream(pdfInfo.outputStream); - try { - root.paint(graphics); - pdfInfo.currentStream.add(graphics.getString()); - } catch (Exception e) { - log.error("svg graphic could not be rendered: " - + e.getMessage(), e); - } + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + PDFRenderer renderer = (PDFRenderer)context.getRenderer(); + renderer.saveGraphicsState(); + renderer.setColor(Color.black, false, null); + renderer.setColor(Color.black, true, null); + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right. (0,0) is where the + // viewBox puts it. + pdfInfo.currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " " + + yOffset / 1000f + " cm\n"); + + SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); + //AffineTransform at = ViewBox.getPreserveAspectRatioTransform( + // svg, w / 1000f, h / 1000f); + AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, + pdfInfo.width / 1000f, pdfInfo.height / 1000f); + /* + if (!at.isIdentity()) { + double[] vals = new double[6]; + at.getMatrix(vals); + pdfInfo.currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n"); + }*/ + + if (pdfInfo.pdfContext == null) { + pdfInfo.pdfContext = pdfInfo.pdfPage; + } + PDFGraphics2D graphics = new PDFGraphics2D(true, pdfInfo.fi, + pdfInfo.pdfDoc, + pdfInfo.pdfContext, pdfInfo.pdfPage.referencePDF(), + pdfInfo.currentFontName, pdfInfo.currentFontSize); + graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); + pdfInfo.pdfState.push(); + AffineTransform transform = new AffineTransform(); + // scale to viewbox + transform.translate(xOffset / 1000f, yOffset / 1000f); + + if (deviceResolution != uaResolution) { + //Scale for higher resolution on-the-fly images from Batik + double s = uaResolution / deviceResolution; + at.scale(s, s); + pdfInfo.currentStream.add("" + PDFNumber.doubleOut(s) + " 0 0 " + + PDFNumber.doubleOut(s) + " 0 0 cm\n"); + graphics.scale(1 / s, 1 / s); + } - renderer.restoreGraphicsState(); - pdfInfo.pdfState.pop(); + pdfInfo.pdfState.setTransform(transform); + graphics.setPDFState(pdfInfo.pdfState); + graphics.setOutputStream(pdfInfo.outputStream); + try { + root.paint(graphics); + pdfInfo.currentStream.add(graphics.getString()); + } catch (Exception e) { + log.error("svg graphic could not be rendered: " + + e.getMessage(), e); } + + renderer.restoreGraphicsState(); + pdfInfo.pdfState.pop(); } - /** @see org.apache.fop.render.XMLHandler#getMimeType() */ - public String getMimeType() { - return PDFRenderer.MIME_TYPE; + /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */ + public boolean supportsRenderer(Renderer renderer) { + return (renderer instanceof PDFRenderer); } - /** @see org.apache.fop.render.XMLHandler#getNamespace() */ public String getNamespace() { return SVGDOMImplementation.SVG_NAMESPACE_URI; } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 824ff9e5c..39ce0c9b7 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -132,8 +132,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer { */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); - PSSVGHandler xmlHandler = new PSSVGHandler(); - userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler); } /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */ @@ -1070,17 +1068,16 @@ public class PSRenderer extends AbstractPathOrientedRenderer { context = new RendererContext(this, MIME_TYPE); context.setUserAgent(userAgent); - context.setProperty(PSSVGHandler.PS_GENERATOR, this.gen); - context.setProperty(PSSVGHandler.PS_FONT_INFO, fontInfo); - context.setProperty(PSSVGHandler.PS_WIDTH, + context.setProperty(PSRendererContextConstants.PS_GENERATOR, this.gen); + context.setProperty(PSRendererContextConstants.PS_FONT_INFO, fontInfo); + context.setProperty(PSRendererContextConstants.WIDTH, new Integer((int) pos.getWidth())); - context.setProperty(PSSVGHandler.PS_HEIGHT, + context.setProperty(PSRendererContextConstants.HEIGHT, new Integer((int) pos.getHeight())); - context.setProperty(PSSVGHandler.PS_XPOS, + context.setProperty(PSRendererContextConstants.XPOS, new Integer(currentIPPosition + (int) pos.getX())); - context.setProperty(PSSVGHandler.PS_YPOS, + context.setProperty(PSRendererContextConstants.YPOS, new Integer(currentBPPosition + (int) pos.getY())); - //context.setProperty("strokeSVGText", options.get("strokeSVGText")); renderXML(context, doc, ns); } diff --git a/src/java/org/apache/fop/render/ps/PSRendererContextConstants.java b/src/java/org/apache/fop/render/ps/PSRendererContextConstants.java new file mode 100644 index 000000000..210c1b9a1 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSRendererContextConstants.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.ps; + +import org.apache.fop.render.RendererContextConstants; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface PSRendererContextConstants extends RendererContextConstants { + + /** The PostScript generator that is being used to drawn into. */ + public static final String PS_GENERATOR = "psGenerator"; + + /** The font information for the PostScript renderer. */ + public static final String PS_FONT_INFO = "psFontInfo"; + + +} diff --git a/src/java/org/apache/fop/render/ps/PSSVGHandler.java b/src/java/org/apache/fop/render/ps/PSSVGHandler.java index b39ed8f83..28bfa0bf4 100644 --- a/src/java/org/apache/fop/render/ps/PSSVGHandler.java +++ b/src/java/org/apache/fop/render/ps/PSSVGHandler.java @@ -23,12 +23,12 @@ import java.awt.geom.AffineTransform; import java.io.IOException; // DOM -/* org.w3c.dom.Document is not imported to avoid conflict with - org.apache.fop.control.Document */ +import org.w3c.dom.Document; import org.w3c.dom.svg.SVGDocument; import org.w3c.dom.svg.SVGSVGElement; // Batik +import org.apache.avalon.framework.configuration.Configuration; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.ViewBox; @@ -37,6 +37,7 @@ import org.apache.batik.gvt.GraphicsNode; // FOP import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.Renderer; import org.apache.fop.render.XMLHandler; import org.apache.fop.render.RendererContext; import org.apache.fop.svg.SVGUserAgent; @@ -51,45 +52,12 @@ import org.apache.commons.logging.LogFactory; * It renders SVG to the PostScript document using the PSGraphics2D. * The properties from the PostScript renderer are subject to change. * - * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> * @version $Id$ */ -public class PSSVGHandler implements XMLHandler { +public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { - /** - * logging instance - */ - private Log log = LogFactory.getLog(PSSVGHandler.class); - - /** - * The PostScript generator that is being used to drawn into. - */ - public static final String PS_GENERATOR = "psGenerator"; - - /** - * The font information for the PostScript renderer. - */ - public static final String PS_FONT_INFO = "psFontInfo"; - - /** - * The width of the SVG graphic. - */ - public static final String PS_WIDTH = "width"; - - /** - * The height of the SVG graphic. - */ - public static final String PS_HEIGHT = "height"; - - /** - * The x position that this is being drawn at. - */ - public static final String PS_XPOS = "xpos"; - - /** - * The y position that this is being drawn at. - */ - public static final String PS_YPOS = "ypos"; + /** logging instance */ + private static Log log = LogFactory.getLog(PSSVGHandler.class); /** * Create a new PostScript XML handler for use by the PostScript renderer. @@ -99,14 +67,11 @@ public class PSSVGHandler implements XMLHandler { /** @see org.apache.fop.render.XMLHandler */ public void handleXML(RendererContext context, - org.w3c.dom.Document doc, String ns) throws Exception { + Document doc, String ns) throws Exception { PSInfo psi = getPSInfo(context); if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { - SVGHandler svghandler = new SVGHandler(); - svghandler.renderSVGDocument(context, doc, psi); - } else { - //nop + renderSVGDocument(context, doc, psi); } } @@ -120,10 +85,11 @@ public class PSSVGHandler implements XMLHandler { PSInfo psi = new PSInfo(); psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR); psi.fontInfo = (org.apache.fop.fonts.FontInfo) context.getProperty(PS_FONT_INFO); - psi.width = ((Integer)context.getProperty(PS_WIDTH)).intValue(); - psi.height = ((Integer)context.getProperty(PS_HEIGHT)).intValue(); - psi.currentXPosition = ((Integer)context.getProperty(PS_XPOS)).intValue(); - psi.currentYPosition = ((Integer)context.getProperty(PS_YPOS)).intValue(); + psi.width = ((Integer)context.getProperty(WIDTH)).intValue(); + psi.height = ((Integer)context.getProperty(HEIGHT)).intValue(); + psi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); + psi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); + psi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION); return psi; } @@ -136,14 +102,17 @@ public class PSSVGHandler implements XMLHandler { private PSGenerator psGenerator; /** see PS_FONT_INFO */ private org.apache.fop.fonts.FontInfo fontInfo; - /** see PS_PAGE_WIDTH */ + /** see WIDTH */ private int width; - /** see PS_PAGE_HEIGHT */ + /** see HEIGHT */ private int height; - /** see PS_XPOS */ + /** see XPOS */ private int currentXPosition; - /** see PS_YPOS */ + /** see YPOS */ private int currentYPosition; + /** see HANDLER_CONFIGURATION */ + private Configuration cfg; + /** * Returns the PSGenerator. * @return PSGenerator @@ -240,122 +209,134 @@ public class PSSVGHandler implements XMLHandler { this.height = height; } + /** + * Returns the height. + * @return int + */ + public Configuration getHandlerConfiguration() { + return this.cfg; + } + + /** + * Sets the handler configuration. + * @param cfg the configuration object + */ + public void setHeight(Configuration cfg) { + this.cfg = cfg; + } + } /** - * This method is placed in an inner class so that we don't get class - * loading errors if batik is not present. + * Render the svg document. + * @param context the renderer context + * @param doc the svg document + * @param psInfo the pdf information of the current context */ - protected class SVGHandler { - /** - * Render the svg document. - * @param context the renderer context - * @param doc the svg document - * @param psInfo the pdf information of the current context - */ - protected void renderSVGDocument(RendererContext context, - org.w3c.dom.Document doc, PSInfo psInfo) { - int xOffset = psInfo.currentXPosition; - int yOffset = psInfo.currentYPosition; - PSGenerator gen = psInfo.psGenerator; - - SVGUserAgent ua - = new SVGUserAgent( - context.getUserAgent().getSourcePixelUnitToMillimeter(), - new AffineTransform()); - - GVTBuilder builder = new GVTBuilder(); - BridgeContext ctx = new BridgeContext(ua); + protected void renderSVGDocument(RendererContext context, + Document doc, PSInfo psInfo) { + int xOffset = psInfo.currentXPosition; + int yOffset = psInfo.currentYPosition; + PSGenerator gen = psInfo.psGenerator; + + //Controls whether text painted by Batik is generated using text or path operations + boolean strokeText = false; + Configuration cfg = psInfo.getHandlerConfiguration(); + if (cfg != null) { + strokeText = cfg.getChild("stroke-text", true).getValueAsBoolean(strokeText); + } + + SVGUserAgent ua + = new SVGUserAgent( + context.getUserAgent().getSourcePixelUnitToMillimeter(), + new AffineTransform()); + + GVTBuilder builder = new GVTBuilder(); + BridgeContext ctx = new BridgeContext(ua); + if (!strokeText) { PSTextPainter textPainter = new PSTextPainter(psInfo.getFontInfo()); ctx.setTextPainter(textPainter); PSTextElementBridge tBridge = new PSTextElementBridge(textPainter); ctx.putBridge(tBridge); + } - //PSAElementBridge aBridge = new PSAElementBridge(); - // to get the correct transform we need to use the PDFState - AffineTransform transform = gen.getCurrentState().getTransform(); - transform.translate(xOffset / 1000f, yOffset / 1000f); - //aBridge.setCurrentTransform(transform); - //ctx.putBridge(aBridge); - - GraphicsNode root; + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + log.error("SVG graphic could not be built: " + + e.getMessage(), e); + return; + } + // get the 'width' and 'height' attributes of the SVG document + float w = (float)ctx.getDocumentSize().getWidth() * 1000f; + float h = (float)ctx.getDocumentSize().getHeight() * 1000f; + + float sx = psInfo.getWidth() / (float)w; + float sy = psInfo.getHeight() / (float)h; + + ctx = null; + builder = null; + + try { + gen.commentln("%FOPBeginSVG"); + gen.saveGraphicsState(); + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + gen.writeln("newpath"); + gen.defineRect(xOffset / 1000f, yOffset / 1000f, + psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f); + gen.writeln("clip"); + + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right. (0,0) is where the + // viewBox puts it. + gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f); + + SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); + AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, + psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f); + /* + if (!at.isIdentity()) { + double[] vals = new double[6]; + at.getMatrix(vals); + gen.concatMatrix(vals); + }*/ + + final boolean textAsShapes = false; + PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen); + graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); + AffineTransform transform = new AffineTransform(); + // scale to viewbox + transform.translate(xOffset, yOffset); + gen.getCurrentState().concatMatrix(transform); try { - root = builder.build(ctx, doc); + root.paint(graphics); } catch (Exception e) { - log.error("SVG graphic could not be built: " + log.error("SVG graphic could not be rendered: " + e.getMessage(), e); - return; } - // get the 'width' and 'height' attributes of the SVG document - float w = (float)ctx.getDocumentSize().getWidth() * 1000f; - float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - float sx = psInfo.getWidth() / (float)w; - float sy = psInfo.getHeight() / (float)h; - - ctx = null; - builder = null; - - try { - gen.commentln("%FOPBeginSVG"); - gen.saveGraphicsState(); - /* - * Clip to the svg area. - * Note: To have the svg overlay (under) a text area then use - * an fo:block-container - */ - gen.writeln("newpath"); - gen.defineRect(xOffset / 1000f, yOffset / 1000f, - psInfo.getWidth() / 1000f, psInfo.getWidth() / 1000f); - //TODO Is the above correct? Twice getWidth?????????????? - gen.writeln("clip"); - - // transform so that the coordinates (0,0) is from the top left - // and positive is down and to the right. (0,0) is where the - // viewBox puts it. - gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f); - - SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); - AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, - psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f); - if (false && !at.isIdentity()) { - double[] vals = new double[6]; - at.getMatrix(vals); - gen.concatMatrix(vals); - } - - final boolean textAsShapes = false; - PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen); - graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); - transform = new AffineTransform(); - // scale to viewbox - transform.translate(xOffset, yOffset); - gen.getCurrentState().concatMatrix(transform); - try { - root.paint(graphics); - } catch (Exception e) { - log.error("SVG graphic could not be rendered: " - + e.getMessage(), e); - } - - gen.restoreGraphicsState(); - gen.commentln("%FOPEndSVG"); - } catch (IOException ioe) { - log.error("SVG graphic could not be rendered: " - + ioe.getMessage(), ioe); - } + gen.restoreGraphicsState(); + gen.commentln("%FOPEndSVG"); + } catch (IOException ioe) { + log.error("SVG graphic could not be rendered: " + + ioe.getMessage(), ioe); } } - /** @see org.apache.fop.render.XMLHandler#getMimeType() */ - public String getMimeType() { - return PSRenderer.MIME_TYPE; + /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */ + public boolean supportsRenderer(Renderer renderer) { + return (renderer instanceof PSRenderer); } - + /** @see org.apache.fop.render.XMLHandler#getNamespace() */ public String getNamespace() { return SVGDOMImplementation.SVG_NAMESPACE_URI; } - + } diff --git a/src/java/org/apache/fop/render/xml/XMLXMLHandler.java b/src/java/org/apache/fop/render/xml/XMLXMLHandler.java index b441322d6..9d1185903 100644 --- a/src/java/org/apache/fop/render/xml/XMLXMLHandler.java +++ b/src/java/org/apache/fop/render/xml/XMLXMLHandler.java @@ -20,6 +20,7 @@ package org.apache.fop.render.xml; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.render.Renderer; import org.apache.fop.render.XMLHandler; import org.apache.fop.render.RendererContext; @@ -132,9 +133,9 @@ public class XMLXMLHandler implements XMLHandler { } } - /** @see org.apache.fop.render.XMLHandler#getMimeType() */ - public String getMimeType() { - return XMLRenderer.XML_MIME_TYPE; + /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */ + public boolean supportsRenderer(Renderer renderer) { + return (renderer instanceof XMLRenderer); } /** @see org.apache.fop.render.XMLHandler#getNamespace() */ diff --git a/src/sandbox/org/apache/fop/render/svg/SVGRenderer.java b/src/sandbox/org/apache/fop/render/svg/SVGRenderer.java index 7a2b182d7..0b5d93f3d 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGRenderer.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGRenderer.java @@ -29,21 +29,17 @@ import org.apache.fop.svg.SVGUtilities; import org.apache.fop.fonts.FontInfo; import org.apache.fop.apps.FOUserAgent; -import org.w3c.dom.Node; -import org.w3c.dom.svg.SVGSVGElement; -import org.w3c.dom.svg.SVGDocument; /* org.w3c.dom.Document is not imported to avoid conflict with org.apache.fop.control.Document */ import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; import org.apache.batik.dom.svg.SVGDOMImplementation; -import org.apache.batik.dom.util.XMLSupport; import org.apache.batik.transcoder.svg2svg.SVGTranscoder; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.TranscoderException; -import org.apache.batik.dom.util.DOMUtilities; import java.awt.Color; import java.awt.image.BufferedImage; @@ -60,7 +56,7 @@ import org.apache.fop.render.RendererContext; /** * This is the SVG renderer. */ -public class SVGRenderer extends AbstractRenderer implements XMLHandler { +public class SVGRenderer extends AbstractRenderer { /** SVG MIME type */ public static final String SVG_MIME_TYPE = "image/svg+xml"; @@ -81,8 +77,6 @@ public class SVGRenderer extends AbstractRenderer implements XMLHandler { // first sequence title private LineArea docTitle = null; - private RendererContext context; - private OutputStream ostream; private float totalWidth = 0; @@ -119,7 +113,6 @@ public class SVGRenderer extends AbstractRenderer implements XMLHandler { * Creates a new SVG renderer. */ public SVGRenderer() { - context = new RendererContext(this, SVG_MIME_TYPE); } /** @@ -127,7 +120,15 @@ public class SVGRenderer extends AbstractRenderer implements XMLHandler { */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); - userAgent.getXMLHandlerRegistry().addXMLHandler(this); + + //Note: This is done here as having two service lookup files in the same IDE project + //will end up with one overwriting the other when all sources are compiled in to the + //same target directory. Remove this code and add an entry in the XMLHandler resource + //file when this renderer exits the sandbox. + XMLHandler handler = agent.getXMLHandlerRegistry().getXMLHandler(this, SVG_NAMESPACE); + if (handler == null) { + agent.getXMLHandlerRegistry().addXMLHandler("org.apache.fop.render.svg.SVGSVGHandler"); + } } /** @@ -319,36 +320,33 @@ public class SVGRenderer extends AbstractRenderer implements XMLHandler { public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { org.w3c.dom.Document doc = fo.getDocument(); String ns = fo.getNameSpace(); - renderXML(context, doc, ns); + renderDocument(doc, ns, pos); } - /** @see org.apache.fop.render.XMLHandler */ - public void handleXML(RendererContext context, - org.w3c.dom.Document doc, String ns) throws Exception { - if (SVG_NAMESPACE.equals(ns)) { - if (!(doc instanceof SVGDocument)) { - DOMImplementation impl = - SVGDOMImplementation.getDOMImplementation(); - doc = DOMUtilities.deepCloneDocument(doc, impl); - } - SVGSVGElement svg = ((SVGDocument) doc).getRootElement(); - Element view = svgDocument.createElementNS(SVG_NAMESPACE, "svg"); - Node newsvg = svgDocument.importNode(svg, true); - //view.setAttributeNS(null, "viewBox", "0 0 "); - view.setAttributeNS(null, "x", "" + currentIPPosition / 1000f); - view.setAttributeNS(null, "y", "" + currentBPPosition / 1000f); - - // this fixes a problem where the xmlns is repeated sometimes - Element ele = (Element) newsvg; - ele.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns", - SVG_NAMESPACE); - if (ele.hasAttributeNS(null, "xmlns")) { - ele.removeAttributeNS(null, "xmlns"); - } - - view.appendChild(newsvg); - currentPageG.appendChild(view); - } + /** + * Renders an XML document (SVG for example). + * + * @param doc DOM document representing the XML document + * @param ns Namespace for the document + * @param pos Position on the page + */ + public void renderDocument(Document doc, String ns, Rectangle2D pos) { + RendererContext context; + context = new RendererContext(this, getMimeType()); + context.setUserAgent(userAgent); + + context.setProperty(SVGRendererContextConstants.SVG_DOCUMENT, svgDocument); + context.setProperty(SVGRendererContextConstants.SVG_PAGE_G, currentPageG); + context.setProperty(SVGRendererContextConstants.XPOS, + new Integer(currentIPPosition + (int)pos.getX())); + context.setProperty(SVGRendererContextConstants.YPOS, + new Integer(currentBPPosition + (int)pos.getY())); + context.setProperty(SVGRendererContextConstants.WIDTH, + new Integer((int)pos.getWidth())); + context.setProperty(SVGRendererContextConstants.HEIGHT, + new Integer((int) pos.getHeight())); + + renderXML(context, doc, ns); } /** @@ -419,11 +417,6 @@ public class SVGRenderer extends AbstractRenderer implements XMLHandler { return SVG_MIME_TYPE; } - /** @see org.apache.fop.render.XMLHandler#getNamespace() */ - public String getNamespace() { - return SVG_NAMESPACE; - } - /** * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D) */ diff --git a/src/sandbox/org/apache/fop/render/svg/SVGRendererContextConstants.java b/src/sandbox/org/apache/fop/render/svg/SVGRendererContextConstants.java new file mode 100644 index 000000000..c86afb9ff --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/SVGRendererContextConstants.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.svg; + +import org.apache.fop.render.RendererContextConstants; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface SVGRendererContextConstants extends RendererContextConstants { + + /** The SVG document that this image is being drawn into. */ + String SVG_DOCUMENT = "svgDoc"; + + /** The current SVG page g element. */ + String SVG_PAGE_G = "svgPageG"; + +} diff --git a/src/sandbox/org/apache/fop/render/svg/SVGSVGHandler.java b/src/sandbox/org/apache/fop/render/svg/SVGSVGHandler.java new file mode 100644 index 000000000..47e1b8767 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/SVGSVGHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.svg; + +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.dom.util.DOMUtilities; +import org.apache.batik.dom.util.XMLSupport; +import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererContext; +import org.apache.fop.render.XMLHandler; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGElement; +import org.w3c.dom.svg.SVGSVGElement; + +public class SVGSVGHandler implements XMLHandler, SVGRendererContextConstants { + + /** @see org.apache.fop.render.XMLHandler */ + public void handleXML(RendererContext context, + org.w3c.dom.Document doc, String ns) throws Exception { + if (getNamespace().equals(ns)) { + if (!(doc instanceof SVGDocument)) { + DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); + doc = DOMUtilities.deepCloneDocument(doc, impl); + } + SVGSVGElement svg = ((SVGDocument) doc).getRootElement(); + SVGDocument targetDoc = (SVGDocument)context.getProperty(SVG_DOCUMENT); + SVGElement currentPageG = (SVGElement)context.getProperty(SVG_PAGE_G); + Element view = targetDoc.createElementNS(getNamespace(), "svg"); + Node newsvg = targetDoc.importNode(svg, true); + //view.setAttributeNS(null, "viewBox", "0 0 "); + int xpos = ((Integer)context.getProperty(XPOS)).intValue(); + int ypos = ((Integer)context.getProperty(YPOS)).intValue(); + view.setAttributeNS(null, "x", "" + xpos / 1000f); + view.setAttributeNS(null, "y", "" + ypos / 1000f); + + // this fixes a problem where the xmlns is repeated sometimes + Element ele = (Element) newsvg; + ele.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns", + getNamespace()); + if (ele.hasAttributeNS(null, "xmlns")) { + ele.removeAttributeNS(null, "xmlns"); + } + + view.appendChild(newsvg); + currentPageG.appendChild(view); + } + } + + + /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */ + public boolean supportsRenderer(Renderer renderer) { + return (renderer instanceof SVGRenderer); + } + + /** @see org.apache.fop.render.XMLHandler#getNamespace() */ + public String getNamespace() { + return SVGRenderer.SVG_NAMESPACE; + } + + +} diff --git a/status.xml b/status.xml index f0ccaa307..9f0b2ffc8 100644 --- a/status.xml +++ b/status.xml @@ -27,6 +27,14 @@ <changes> <release version="FOP Trunk"> + <action context="Code" dev="JM" type="update"> + Changed the XMLHandler interface so it doesn't report the MIME type it + supports but instead can report whether it supports a particular Renderer + implementation. XMLHandlers are now configurable. + </action> + <action context="Code" dev="JM" type="fix"> + Fixed a bug where SVG content could be clipped when rendered to PostScript. + </action> <action context="Code" dev="JM" type="fix"> Changed the way resolutions are handled. The single resolution in the user agent got split up into source and target resolutions. For more info, see |