From cd600b952b6326195b1670e6a17af75d51f46b57 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 16 Dec 2005 14:40:20 +0000 Subject: XMLHandler interface changed so it reports whether it supports a particular Renderer instead of reporting the MIME type. One MIME type could be implemented by multiple Renderer implementations so conflicts could occur. Almost all XMLHandler implementations will have a dependency on a particular Renderer implementation. XMLHandlers are now configurable. Standard XMLHandlers now get registered through service lookup. Simplification: XMLHandlers don't need nested classes for the handling functionality anymore. If Batik, for example, is not in the classpath it will already be detected while registering the XMLHandlers. The RendererContextConstants interface now standardizes some of the keys used in the RendererContext and helps with actually decoupling the XMLHandler implementations from the renderers. This is one step towards making Batik an optional dependency and making it possible to move the SVG functionality to a separate place later. Extracted the SVG XMLHandler functionality from the sandbox SVGRenderer into a separate class following the example of the other renderers. Bugfix in PSSVGHandler: Fixed a copy/paste error which could lead to wrong clipping of an SVG image for PostScript output. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@357166 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 7 +- conf/fop.xconf | 12 +- .../services/org.apache.fop.render.XMLHandler | 3 + .../org/apache/fop/render/AbstractRenderer.java | 46 ++- .../fop/render/RendererContextConstants.java | 44 +++ src/java/org/apache/fop/render/XMLHandler.java | 6 +- .../org/apache/fop/render/XMLHandlerRegistry.java | 63 ++-- .../apache/fop/render/java2d/Java2DRenderer.java | 12 +- .../java2d/Java2DRendererContextConstants.java | 32 ++ .../apache/fop/render/java2d/Java2DSVGHandler.java | 185 +++++------ .../org/apache/fop/render/pdf/PDFRenderer.java | 30 +- .../render/pdf/PDFRendererContextConstants.java | 52 ++++ .../org/apache/fop/render/pdf/PDFSVGHandler.java | 339 +++++++++------------ src/java/org/apache/fop/render/ps/PSRenderer.java | 15 +- .../fop/render/ps/PSRendererContextConstants.java | 35 +++ .../org/apache/fop/render/ps/PSSVGHandler.java | 273 ++++++++--------- .../org/apache/fop/render/xml/XMLXMLHandler.java | 7 +- .../org/apache/fop/render/svg/SVGRenderer.java | 79 +++-- .../render/svg/SVGRendererContextConstants.java | 34 +++ .../org/apache/fop/render/svg/SVGSVGHandler.java | 80 +++++ status.xml | 8 + 21 files changed, 779 insertions(+), 583 deletions(-) create mode 100644 src/java/META-INF/services/org.apache.fop.render.XMLHandler create mode 100644 src/java/org/apache/fop/render/RendererContextConstants.java create mode 100644 src/java/org/apache/fop/render/java2d/Java2DRendererContextConstants.java create mode 100644 src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java create mode 100644 src/java/org/apache/fop/render/ps/PSRendererContextConstants.java create mode 100644 src/sandbox/org/apache/fop/render/svg/SVGRendererContextConstants.java create mode 100644 src/sandbox/org/apache/fop/render/svg/SVGSVGHandler.java diff --git a/build.xml b/build.xml index da75a8911..6f22ae3c9 100644 --- a/build.xml +++ b/build.xml @@ -376,6 +376,11 @@ list of possible build targets. + + + + + @@ -451,7 +456,7 @@ list of possible build targets. - + 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. --> - - + + - - + + 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; @@ -766,6 +765,39 @@ public abstract class AbstractRenderer // Some renderers (ex. Text) don't support foreign objects. } + /** + * 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 @@ -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 Apache XML FOP Development Team * @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 @@ + + 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. + + + Fixed a bug where SVG content could be clipped when rendered to PostScript. + 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 -- cgit v1.2.3