blob: e329765db81a113d43dd3248637dcb2c579d8a53 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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;
// Java
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import org.w3c.dom.Document;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DefaultFontFamilyResolver;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.dom.AbstractDocument;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
import org.apache.fop.svg.SVGEventProducer;
import org.apache.fop.svg.SVGUserAgent;
/**
* Generic XML handler for SVG. Uses Apache Batik for SVG processing and simply paints to
* a Graphics2DAdapter and thus ultimatively to Graphics2D interface that is presented.
* <p>
* To use this class, subclass it and implement the missing methods (supportsRenderer, for example).
*/
public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererContextConstants {
/** {@inheritDoc} */
public void handleXML(RendererContext context,
Document doc, String ns) throws Exception {
if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) {
renderSVGDocument(context, doc);
}
}
/**
* Creates a graphics 2D image painter implementation
*
* @param root the batik graphics node root
* @param ctx the batik bridge context
* @param imageSize the image size
* @return a new graphics 2D image painter implementation
*/
protected Graphics2DImagePainter createGraphics2DImagePainter(
GraphicsNode root, BridgeContext ctx, Dimension imageSize) {
return new Graphics2DImagePainterImpl(root, ctx, imageSize);
}
/**
* Builds the GVT root.
*
* @param userAgent the user agent
* @param ctx the batik bridge context
* @param doc the document
* @return a built GVT root tree
*/
protected GraphicsNode buildGraphicsNode(
FOUserAgent userAgent, BridgeContext ctx, Document doc) {
GVTBuilder builder = new GVTBuilder();
final GraphicsNode root;
try {
root = builder.build(ctx, doc);
} catch (Exception e) {
EventBroadcaster eventBroadcaster
= userAgent.getEventBroadcaster();
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(eventBroadcaster);
final String uri = getDocumentURI(doc);
eventProducer.svgNotBuilt(this, e, uri);
return null;
}
return root;
}
/**
* Returns the image size
* @param wrappedContext renderer context wrapper
*
* @return the image size
*/
protected Dimension getImageSize(RendererContextWrapper wrappedContext) {
final int width = wrappedContext.getWidth();
final int height = wrappedContext.getHeight();
return new Dimension(width, height);
}
/**
* Render the SVG document.
*
* @param rendererContext the renderer context
* @param doc the SVG document
* @throws IOException In case of an I/O error while painting the image
*/
protected void renderSVGDocument(final RendererContext rendererContext,
final Document doc) throws IOException {
updateRendererContext(rendererContext);
//Prepare
FOUserAgent userAgent = rendererContext.getUserAgent();
SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, DefaultFontFamilyResolver.SINGLETON,
new AffineTransform());
//Create Batik BridgeContext
final BridgeContext bridgeContext = new BridgeContext(svgUserAgent);
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
//to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(doc);
//Build the GVT tree
final GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc);
// Create Graphics2DImagePainter
final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(
rendererContext);
Dimension imageSize = getImageSize(wrappedContext);
final Graphics2DImagePainter painter = createGraphics2DImagePainter(
root, bridgeContext, imageSize);
//Let the painter paint the SVG on the Graphics2D instance
Graphics2DAdapter g2dAdapter = rendererContext.getRenderer().getGraphics2DAdapter();
//Paint the image
final int x = wrappedContext.getCurrentXPosition();
final int y = wrappedContext.getCurrentYPosition();
final int width = wrappedContext.getWidth();
final int height = wrappedContext.getHeight();
g2dAdapter.paintImage(painter, rendererContext, x, y, width, height);
}
/**
* Gets the document URI from a Document instance if possible.
*
* @param doc the Document
* @return the URI or null
*/
protected String getDocumentURI(Document doc) {
String docURI = null;
if (doc instanceof AbstractDocument) {
AbstractDocument level3Doc = (AbstractDocument)doc;
docURI = level3Doc.getDocumentURI();
}
return docURI;
}
/**
* Override this method to update the renderer context if it needs special settings for
* certain conditions.
*
* @param context the renderer context
*/
protected void updateRendererContext(RendererContext context) {
//nop
}
/** {@inheritDoc} */
public String getNamespace() {
return SVGDOMImplementation.SVG_NAMESPACE_URI;
}
}