Browse Source

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
tags/fop-0_91-beta
Jeremias Maerki 18 years ago
parent
commit
cd600b952b

+ 6
- 1
build.xml View File

@@ -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}])"/>

+ 8
- 4
conf/fop.xconf View File

@@ -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">

+ 3
- 0
src/java/META-INF/services/org.apache.fop.render.XMLHandler View File

@@ -0,0 +1,3 @@
org.apache.fop.render.pdf.PDFSVGHandler
org.apache.fop.render.ps.PSSVGHandler
org.apache.fop.render.java2d.Java2DSVGHandler

+ 43
- 3
src/java/org/apache/fop/render/AbstractRenderer.java View File

@@ -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

+ 44
- 0
src/java/org/apache/fop/render/RendererContextConstants.java View File

@@ -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";
}

+ 4
- 2
src/java/org/apache/fop/render/XMLHandler.java View File

@@ -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,

+ 27
- 36
src/java/org/apache/fop/render/XMLHandlerRegistry.java View File

@@ -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();

+ 5
- 7
src/java/org/apache/fop/render/java2d/Java2DRenderer.java View File

@@ -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);

+ 32
- 0
src/java/org/apache/fop/render/java2d/Java2DRendererContextConstants.java View File

@@ -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";
}

+ 75
- 110
src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java View File

@@ -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;

+ 14
- 16
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -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);


+ 52
- 0
src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java View File

@@ -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";
}

+ 136
- 203
src/java/org/apache/fop/render/pdf/PDFSVGHandler.java View File

@@ -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;
}
}
}

+ 6
- 9
src/java/org/apache/fop/render/ps/PSRenderer.java View File

@@ -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);
}

+ 35
- 0
src/java/org/apache/fop/render/ps/PSRendererContextConstants.java View File

@@ -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";

}

+ 127
- 146
src/java/org/apache/fop/render/ps/PSSVGHandler.java View File

@@ -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;
}

}


+ 4
- 3
src/java/org/apache/fop/render/xml/XMLXMLHandler.java View File

@@ -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() */

+ 36
- 43
src/sandbox/org/apache/fop/render/svg/SVGRenderer.java View File

@@ -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)
*/

+ 34
- 0
src/sandbox/org/apache/fop/render/svg/SVGRendererContextConstants.java View File

@@ -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";

}

+ 80
- 0
src/sandbox/org/apache/fop/render/svg/SVGSVGHandler.java View File

@@ -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;
}


}

+ 8
- 0
status.xml View File

@@ -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

Loading…
Cancel
Save