Very rudimentary support for XHTML in <foreignObject>.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/batik/branches/foreignObject@658527 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build.xml b/build.xml
index 75e6f3a..ca30e42 100644
--- a/build.xml
+++ b/build.xml
@@ -158,6 +158,9 @@
<available property="jacl.present" classname="tcl.lang.Interp">
<classpath refid="libs-classpath"/>
</available>
+ <available property="xhtmlrenderer.present" classname="org.xhtmlrenderer.Version">
+ <classpath refid="libs-classpath"/>
+ </available>
<available property="jdk14.present" classname="java.lang.CharSequence"/>
<!-- When compiling Batik under GNU Classpath, the Sun codecs are not available. -->
@@ -1017,6 +1020,8 @@
unless="sun-codecs.present"/>
<exclude name="${package-prefix}/ext/awt/image/codec/tiff/*"
unless="sun-codecs.present"/>
+ <exclude name="${package-prefix}/bridge/XHTMLForeignObjectHandler.java"
+ unless="xhtmlrenderer.present"/>
</javac>
<property name="compile.done" value="true"/>
</target>
@@ -1530,6 +1535,7 @@
<fileset dir="${resources}" excludes="**/.svn/">
<include name="${package-prefix}/bridge/BrokenLink.svg"/>
<include name="${package-prefix}/bridge/**/resources/*"/>
+ <include name="META-INF/services/org.apache.batik.bridge.ForeignObjectHandlerFactory"/>
</fileset>
</jar>
</target>
diff --git a/resources/META-INF/services/org.apache.batik.bridge.ForeignObjectHandlerFactory b/resources/META-INF/services/org.apache.batik.bridge.ForeignObjectHandlerFactory
new file mode 100644
index 0000000..6db62f1
--- /dev/null
+++ b/resources/META-INF/services/org.apache.batik.bridge.ForeignObjectHandlerFactory
@@ -0,0 +1,26 @@
+# -----------------------------------------------------------------------------
+#
+# 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.
+#
+# This file registers factories for handlers of <foreignObject>
+# element content.
+#
+# $Id: org.apache.batik.dom.DomExtension 498556 2007-01-22 08:16:03Z cam $
+# -----------------------------------------------------------------------------
+
+# XHTML content, using the Flying Saucer XHTML renderer
+# (https://xhtmlrenderer.dev.java.net/)
+org.apache.batik.bridge.XHTMLForeignObjectHandlerFactory
diff --git a/sources/org/apache/batik/bridge/BridgeContext.java b/sources/org/apache/batik/bridge/BridgeContext.java
index 655e043..e28bcdc 100644
--- a/sources/org/apache/batik/bridge/BridgeContext.java
+++ b/sources/org/apache/batik/bridge/BridgeContext.java
@@ -193,6 +193,11 @@
protected InterpreterPool interpreterPool;
/**
+ * The pool of ForeignObjectHandler factories.
+ */
+ protected ForeignObjectHandlerPool foreignObjectHandlerPool;
+
+ /**
* The document loader used to load/create Document.
*/
protected DocumentLoader documentLoader;
@@ -277,6 +282,12 @@
private static InterpreterPool sharedPool = new InterpreterPool();
/**
+ * By default we share a unique instance of ForeignObjectHandlerPool.
+ */
+ private static ForeignObjectHandlerPool sharedFOHPool =
+ new ForeignObjectHandlerPool();
+
+ /**
* Constructs a new empty bridge context.
*/
protected BridgeContext() {}
@@ -298,21 +309,48 @@
*/
public BridgeContext(UserAgent userAgent,
DocumentLoader loader) {
- this(userAgent, sharedPool, loader);
+ this(userAgent, sharedPool, sharedFOHPool, loader);
}
/**
* Constructs a new bridge context.
* @param userAgent the user agent
* @param interpreterPool the interpreter pool
+ * @param loader document loader
+ */
+ public BridgeContext(UserAgent userAgent,
+ InterpreterPool interpreterPool,
+ DocumentLoader loader) {
+ this(userAgent, interpreterPool, sharedFOHPool, loader);
+ }
+
+ /**
+ * Constructs a new bridge context.
+ * @param userAgent the user agent
+ * @param fohPool the pool of ForeignObjectHandler factories
+ * @param loader document loader
+ */
+ public BridgeContext(UserAgent userAgent,
+ ForeignObjectHandlerPool fohPool,
+ DocumentLoader loader) {
+ this(userAgent, sharedPool, fohPool, loader);
+ }
+
+ /**
+ * Constructs a new bridge context.
+ * @param userAgent the user agent
+ * @param interpreterPool the interpreter pool
+ * @param fohPool the pool of ForeignObjectHandler factories
* @param documentLoader document loader
*/
public BridgeContext(UserAgent userAgent,
InterpreterPool interpreterPool,
+ ForeignObjectHandlerPool fohPool,
DocumentLoader documentLoader) {
this.userAgent = userAgent;
this.viewportMap.put(userAgent, new UserAgentViewport(userAgent));
this.interpreterPool = interpreterPool;
+ this.foreignObjectHandlerPool = fohPool;
this.documentLoader = documentLoader;
}
@@ -526,6 +564,13 @@
}
/**
+ * Returns the ForeignObjectHandlerFactory pool.
+ */
+ public ForeignObjectHandlerPool getForeignObjectHandlerPool() {
+ return foreignObjectHandlerPool;
+ }
+
+ /**
* Returns the focus manager.
*/
public FocusManager getFocusManager() {
@@ -580,6 +625,22 @@
}
/**
+ * Returns a ForeignObjectHandler for the given namespace URI.
+ * @param ns the namespace URI of the element to be handled as
+ * foreign object content
+ */
+ public ForeignObjectHandler createForeignObjectHandler(String ns) {
+ try {
+ return foreignObjectHandlerPool.createForeignObjectHandler(ns);
+ } catch (Exception e) {
+ if (userAgent != null) {
+ userAgent.displayError(e);
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the document loader used to load external documents.
*/
public DocumentLoader getDocumentLoader() {
diff --git a/sources/org/apache/batik/bridge/ForeignObjectHandler.java b/sources/org/apache/batik/bridge/ForeignObjectHandler.java
new file mode 100644
index 0000000..a7331a9
--- /dev/null
+++ b/sources/org/apache/batik/bridge/ForeignObjectHandler.java
@@ -0,0 +1,40 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.w3c.dom.Element;
+
+/**
+ * An interface for classes that can handle content inside a 'foreignObject'
+ * element.
+ *
+ * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
+ * @version $Id$
+ */
+public interface ForeignObjectHandler {
+
+ /**
+ * Returns a new GraphicsNode that represents the foreign object content
+ * in the given element.
+ */
+ GraphicsNode createGraphicsNode(BridgeContext ctx, Element e,
+ float w, float h);
+}
diff --git a/sources/org/apache/batik/bridge/ForeignObjectHandlerFactory.java b/sources/org/apache/batik/bridge/ForeignObjectHandlerFactory.java
new file mode 100644
index 0000000..d04f3f2
--- /dev/null
+++ b/sources/org/apache/batik/bridge/ForeignObjectHandlerFactory.java
@@ -0,0 +1,39 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+/**
+ * An interface for factory classes that can create ForeignObjectHandlers.
+ *
+ * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
+ * @version $Id$
+ */
+public interface ForeignObjectHandlerFactory {
+
+ /**
+ * Returns the namespace URI of the elements ForeignObjectHandlers created
+ * by this factory can handle.
+ */
+ String getNamespaceURI();
+
+ /**
+ * Creates a new ForeignObjectHandler.
+ */
+ ForeignObjectHandler createHandler();
+}
diff --git a/sources/org/apache/batik/bridge/ForeignObjectHandlerPool.java b/sources/org/apache/batik/bridge/ForeignObjectHandlerPool.java
new file mode 100644
index 0000000..8b85242
--- /dev/null
+++ b/sources/org/apache/batik/bridge/ForeignObjectHandlerPool.java
@@ -0,0 +1,92 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.batik.util.Service;
+
+/**
+ * A class that can construct {@link ForeignObjectHandler}s for a given
+ * namespace URI.
+ *
+ * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
+ * @version $Id$
+ */
+public class ForeignObjectHandlerPool {
+
+ /**
+ * The default ForeignObjectHandlerFactory map.
+ */
+ protected static Map defaultFactories = new HashMap(3);
+
+ /**
+ * The ForeignObjectHandlerFactory map.
+ */
+ protected Map factories = new HashMap(3);
+
+ static {
+ Iterator it = Service.providers(ForeignObjectHandlerFactory.class);
+ while (it.hasNext()) {
+ ForeignObjectHandlerFactory factory =
+ (ForeignObjectHandlerFactory) it.next();
+ defaultFactories.put(factory.getNamespaceURI(), factory);
+ }
+ }
+
+ /**
+ * Creates a new ForeignObjectHandlerPool.
+ */
+ public ForeignObjectHandlerPool() {
+ factories.putAll(defaultFactories);
+ }
+
+ /**
+ * Creates a new ForeignObjectHandler for the given namespace URI.
+ * @param ns the namespace URI of the elements the returned
+ * ForeignObjectHandler should be able to handle
+ */
+ public ForeignObjectHandler createForeignObjectHandler(String ns) {
+ ForeignObjectHandlerFactory factory =
+ (ForeignObjectHandlerFactory) factories.get(ns);
+ if (factory == null) {
+ return null;
+ }
+ return factory.createHandler();
+ }
+
+ /**
+ * Adds for the specified namespace URI, the specified
+ * ForeignObjectHandlerFactory.
+ */
+ public void putForeignObjectHandlerFactory
+ (String ns, ForeignObjectHandlerFactory factory) {
+ factories.put(ns, factory);
+ }
+
+ /**
+ * Removes the ForeignObjectHandlerFactory associated with the specified
+ * namespace URI.
+ */
+ public void removeForeignObjectHandlerFactory(String ns) {
+ factories.remove(ns);
+ }
+}
diff --git a/sources/org/apache/batik/bridge/SVGBridgeExtension.java b/sources/org/apache/batik/bridge/SVGBridgeExtension.java
index 84011d9..eab6512 100644
--- a/sources/org/apache/batik/bridge/SVGBridgeExtension.java
+++ b/sources/org/apache/batik/bridge/SVGBridgeExtension.java
@@ -127,6 +127,7 @@
ctx.putBridge(new SVGFeTurbulenceElementBridge());
ctx.putBridge(new SVGFontElementBridge());
ctx.putBridge(new SVGFontFaceElementBridge());
+ ctx.putBridge(new SVGForeignObjectElementBridge());
ctx.putBridge(new SVGFilterElementBridge());
ctx.putBridge(new SVGGElementBridge());
ctx.putBridge(new SVGGlyphElementBridge());
diff --git a/sources/org/apache/batik/bridge/SVGForeignObjectElementBridge.java b/sources/org/apache/batik/bridge/SVGForeignObjectElementBridge.java
new file mode 100644
index 0000000..08f4341
--- /dev/null
+++ b/sources/org/apache/batik/bridge/SVGForeignObjectElementBridge.java
@@ -0,0 +1,268 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+import java.awt.geom.AffineTransform;
+
+import org.apache.batik.dom.svg.SVGOMElement;
+import org.apache.batik.gvt.CompositeGraphicsNode;
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.events.MutationEvent;
+
+/**
+ * Bridge class for the <foreignObject> element.
+ *
+ * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
+ * @version $Id$
+ */
+public class SVGForeignObjectElementBridge extends AbstractGraphicsNodeBridge {
+
+ /**
+ * The ForeignObjectHandler object that will construct the GVT
+ * representation of the foreign content.
+ */
+ protected ForeignObjectHandler handler;
+
+ /**
+ * The foreign content.
+ */
+ protected Element foreignContent;
+
+ /**
+ * Constructs a new bridge for a <foreignObject> element.
+ */
+ public SVGForeignObjectElementBridge() {
+ }
+
+ /**
+ * Returns 'foreignObject'.
+ */
+ public String getLocalName() {
+ return SVG_FOREIGN_OBJECT_TAG;
+ }
+
+ /**
+ * Returns a new instance of this bridge.
+ */
+ public Bridge getInstance() {
+ return new SVGForeignObjectElementBridge();
+ }
+
+ /**
+ * Creates a graphics node using the specified BridgeContext and for the
+ * specified element.
+ *
+ * @param ctx the bridge context to use
+ * @param e the element that describes the graphics node to build
+ * @return a graphics node that represents the specified element
+ */
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
+ Node n = e.getFirstChild();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE) {
+ n = n.getNextSibling();
+ }
+ if (n == null) {
+ return null;
+ }
+
+ Element elt = (Element) n;
+
+ CompositeGraphicsNode cgn =
+ (CompositeGraphicsNode) super.createGraphicsNode(ctx, e);
+ if (cgn == null) {
+ return null;
+ }
+
+ ForeignObjectHandler handler =
+ ctx.createForeignObjectHandler(elt.getNamespaceURI());
+
+ if (handler == null) {
+ return null;
+ }
+
+ buildForeignObjectNode(ctx, e, elt, cgn, handler);
+
+ if (ctx.isDynamic()) {
+ this.handler = handler;
+ this.foreignContent = elt;
+ }
+
+ return cgn;
+ }
+
+ /**
+ * Builds the graphics node according to the ForeignObjectHandler.
+ */
+ public void buildForeignObjectNode(BridgeContext ctx,
+ Element e,
+ Element foreignContent,
+ CompositeGraphicsNode cgn,
+ ForeignObjectHandler handler) {
+
+ while (!cgn.isEmpty()) {
+ cgn.remove(cgn.size() - 1);
+ }
+
+ UnitProcessor.Context uctx = updatePosition(ctx, e, cgn);
+ String s;
+
+ // 'width' attribute - required
+ s = e.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
+ float w;
+ if (s.length() != 0) {
+ w = UnitProcessor.svgHorizontalLengthToUserSpace
+ (s, SVG_WIDTH_ATTRIBUTE, uctx);
+ } else {
+ throw new BridgeException(ctx, e, ERR_ATTRIBUTE_MISSING,
+ new Object[] {SVG_WIDTH_ATTRIBUTE, s});
+ }
+
+ // 'height' attribute - required
+ s = e.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
+ float h;
+ if (s.length() != 0) {
+ h = UnitProcessor.svgVerticalLengthToUserSpace
+ (s, SVG_HEIGHT_ATTRIBUTE, uctx);
+ } else {
+ throw new BridgeException(ctx, e, ERR_ATTRIBUTE_MISSING,
+ new Object[] {SVG_HEIGHT_ATTRIBUTE, s});
+ }
+
+ if (w == 0 || h == 0) {
+ return;
+ }
+
+ GraphicsNode gn = handler.createGraphicsNode(ctx, foreignContent, w, h);
+
+ if (gn != null) {
+ cgn.add(gn);
+ }
+ }
+
+ /**
+ * Updates the transform on the graphics node to reflect the 'x' and 'y'
+ * attributes on the element.
+ */
+ protected UnitProcessor.Context updatePosition
+ (BridgeContext ctx,
+ Element e,
+ CompositeGraphicsNode cgn) {
+
+ UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);
+ String s;
+
+ // 'x' attribute - default is 0
+ s = e.getAttributeNS(null, SVG_X_ATTRIBUTE);
+ float x = 0;
+ if (s.length() != 0) {
+ x = UnitProcessor.svgHorizontalCoordinateToUserSpace
+ (s, SVG_X_ATTRIBUTE, uctx);
+ }
+
+ // 'y' attribute - default is 0
+ s = e.getAttributeNS(null, SVG_Y_ATTRIBUTE);
+ float y = 0;
+ if (s.length() != 0) {
+ y = UnitProcessor.svgVerticalCoordinateToUserSpace
+ (s, SVG_Y_ATTRIBUTE, uctx);
+ }
+
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+ cgn.setTransform(at);
+
+ return uctx;
+ }
+
+ /**
+ * Creates a {@link CompositeGraphicsNode}.
+ */
+ protected GraphicsNode instantiateGraphicsNode() {
+ return new CompositeGraphicsNode();
+ }
+
+ /**
+ * Returns false as 'foreignObject' elements do not have SVG content.
+ */
+ public boolean isComposite() {
+ return false;
+ }
+
+ /**
+ * This method is invoked during the build phase if the document
+ * is dynamic. The responsability of this method is to ensure that
+ * any dynamic modifications of the element this bridge is
+ * dedicated to, happen on its associated GVT product.
+ */
+ protected void initializeDynamicSupport(BridgeContext ctx,
+ Element e,
+ GraphicsNode node) {
+ if (!ctx.isInteractive()) {
+ return;
+ }
+
+ if (ctx.isDynamic()) {
+ // Only do this for dynamic not interactive.
+ this.e = e;
+ this.node = node;
+ this.ctx = ctx;
+ ((SVGOMElement) e).setSVGContext(this);
+ }
+ }
+
+ // BridgeUpdateHandler implementation ////////////////////////////////////
+
+ /**
+ * Invoked when an MutationEvent of type 'DOMAttrModified' is fired.
+ */
+ public void handleDOMAttrModifiedEvent(MutationEvent evt) {
+ String attrName = evt.getAttrName();
+ Node evtNode = evt.getRelatedNode();
+
+ if (attrName.equals(SVG_X_ATTRIBUTE)
+ || attrName.equals(SVG_Y_ATTRIBUTE)) {
+ updatePosition(ctx, e, (CompositeGraphicsNode) node);
+ } else if (attrName.equals(SVG_WIDTH_ATTRIBUTE)
+ || attrName.equals(SVG_HEIGHT_ATTRIBUTE)) {
+ float oldV = 0, newV = 0;
+ String s = evt.getPrevValue();
+ UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);
+
+ if (s.length() != 0) {
+ oldV = UnitProcessor.svgHorizontalCoordinateToUserSpace
+ (s, attrName, uctx);
+ }
+ s = evt.getNewValue();
+ if (s.length() != 0) {
+ newV = UnitProcessor.svgHorizontalCoordinateToUserSpace
+ (s, attrName, uctx);
+ }
+ if (oldV == newV) {
+ return;
+ }
+
+ buildForeignObjectNode
+ (ctx, e, foreignContent, (CompositeGraphicsNode) node, handler);
+ } else {
+ super.handleDOMAttrModifiedEvent(evt);
+ }
+ }
+}
diff --git a/sources/org/apache/batik/bridge/TestForeignObjectHandlerFactory.java b/sources/org/apache/batik/bridge/TestForeignObjectHandlerFactory.java
new file mode 100644
index 0000000..fe6feaf
--- /dev/null
+++ b/sources/org/apache/batik/bridge/TestForeignObjectHandlerFactory.java
@@ -0,0 +1,65 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+import java.awt.Color;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.batik.gvt.FillShapePainter;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.ShapeNode;
+import org.apache.batik.gvt.ShapePainter;
+
+import org.w3c.dom.Element;
+
+/**
+ * A test <foreignObject> handler factory. The factory creates a simple
+ * <foreignObject> handler that just displays a yellow rectangle.
+ *
+ * @author <a href='mailto:cam%40mcc%2eid%2eau'>Cameron McCormack</a>
+ * @version $Id$
+ */
+public class TestForeignObjectHandlerFactory implements ForeignObjectHandlerFactory {
+
+ /**
+ * Returns the namespace URI of the elements ForeignObjectHandlers created
+ * by this factory can handle.
+ */
+ public String getNamespaceURI() {
+ return "http://example.org/foreign";
+ }
+
+ /**
+ * Creates a new ForeignObjectHandler.
+ */
+ public ForeignObjectHandler createHandler() {
+ return new ForeignObjectHandler() {
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e,
+ float w, float h) {
+ Rectangle2D r = new Rectangle2D.Float(0, 0, w, h);
+ ShapeNode n = new ShapeNode();
+ n.setShape(r);
+ FillShapePainter p = new FillShapePainter(r);
+ p.setPaint(Color.YELLOW);
+ n.setShapePainter(p);
+ return n;
+ }
+ };
+ }
+}
diff --git a/sources/org/apache/batik/bridge/XHTMLForeignObjectHandlerFactory.java b/sources/org/apache/batik/bridge/XHTMLForeignObjectHandlerFactory.java
new file mode 100644
index 0000000..b51435c
--- /dev/null
+++ b/sources/org/apache/batik/bridge/XHTMLForeignObjectHandlerFactory.java
@@ -0,0 +1,146 @@
+/*
+
+ 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.
+
+ */
+package org.apache.batik.bridge;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.batik.dom.AbstractDocument;
+import org.apache.batik.dom.GenericDOMImplementation;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.gvt.CompositeGraphicsNode;
+import org.apache.batik.gvt.FillShapePainter;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.RootGraphicsNode;
+import org.apache.batik.gvt.ShapeNode;
+import org.apache.batik.gvt.ShapePainter;
+import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.util.SVGConstants;
+
+import org.xhtmlrenderer.extend.FontContext;
+import org.xhtmlrenderer.extend.OutputDevice;
+import org.xhtmlrenderer.layout.SharedContext;
+import org.xhtmlrenderer.simple.Graphics2DRenderer;
+import org.xhtmlrenderer.swing.Java2DOutputDevice;
+import org.xhtmlrenderer.swing.Java2DTextRenderer;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * A factory class for the XHTML foreign object handler.
+ *
+ * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
+ * @version $Id$
+ */
+public class XHTMLForeignObjectHandlerFactory
+ implements ForeignObjectHandlerFactory {
+
+ /**
+ * Returns the XHTML namespace URI.
+ */
+ public String getNamespaceURI() {
+ return "http://www.w3.org/1999/xhtml";
+ }
+
+ /**
+ * Creates a new ForeignObjectHandler.
+ */
+ public ForeignObjectHandler createHandler() {
+ return new Handler();
+ }
+
+ /**
+ * The handler class for XHTML foreign object content.
+ */
+ protected static class Handler implements ForeignObjectHandler {
+
+ /**
+ * Creates a new Handler.
+ */
+ public Handler() {
+ DOMImplementation impl =
+ SVGDOMImplementation.getDOMImplementation();
+ }
+
+ /**
+ * Returns a new GraphicsNode that represents the foreign object content
+ * in the given element.
+ */
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e,
+ float w, float h) {
+ if (!e.getLocalName().equals("html")) {
+ return null;
+ }
+
+ DOMImplementation impl =
+ GenericDOMImplementation.getDOMImplementation();
+ Document htmlDoc = impl.createDocument
+ ("http://www.w3.org/1999/xhtml", "html", null);
+ htmlDoc.replaceChild
+ (htmlDoc.importNode(e, true), htmlDoc.getDocumentElement());
+
+ impl = SVGDOMImplementation.getDOMImplementation();
+ Document svgDoc = impl.createDocument
+ (SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_SVG_TAG, null);
+
+ SVGGraphics2D g2d = new SVGGraphics2D(svgDoc);
+
+ Graphics2DRenderer renderer = new Graphics2DRenderer();
+ renderer.getPanel().setOpaque(false);
+ SharedContext sc = renderer.getSharedContext();
+ sc.setTextRenderer(new TextRenderer());
+ renderer.setDocument(htmlDoc, AbstractDocument.getBaseURI(ctx.getDocument()));
+ renderer.layout(g2d, new Dimension(Math.round(w), Math.round(h)));
+ renderer.render(g2d);
+
+// try {
+// g2d.stream(new java.io.OutputStreamWriter(System.out), false);
+// } catch (Exception ex) {
+// }
+
+ g2d.getRoot(svgDoc.getDocumentElement());
+
+ BridgeContext cx = new BridgeContext(ctx.getUserAgent());
+ GVTBuilder builder = new GVTBuilder();
+ RootGraphicsNode rgn = (RootGraphicsNode) builder.build(cx, svgDoc);
+ Object[] nodes = rgn.toArray();
+ CompositeGraphicsNode cgn = new CompositeGraphicsNode();
+ for (int i = 0; i < nodes.length; i++) {
+ cgn.add(nodes[i]);
+ ((GraphicsNode) nodes[i]).setClip(null);
+ }
+ return cgn;
+ }
+ }
+
+ protected static class TextRenderer extends Java2DTextRenderer {
+
+ public void drawString(OutputDevice outputDevice, String string, float x, float y) {
+ Graphics2D graphics = ((Java2DOutputDevice) outputDevice).getGraphics();
+ graphics.drawString(string, x, y);
+ }
+
+ public void setup(FontContext fontContext) {
+ }
+ }
+}
diff --git a/sources/org/apache/batik/svggen/SVGGraphics2D.java b/sources/org/apache/batik/svggen/SVGGraphics2D.java
index 66053a4..a372281 100644
--- a/sources/org/apache/batik/svggen/SVGGraphics2D.java
+++ b/sources/org/apache/batik/svggen/SVGGraphics2D.java
@@ -27,8 +27,10 @@
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
import java.awt.Image;
import java.awt.Paint;
+import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.GlyphVector;
@@ -38,8 +40,10 @@
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
+import java.awt.image.VolatileImage;
import java.awt.image.renderable.RenderableImage;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -143,6 +147,11 @@
protected Dimension svgCanvasSize;
/**
+ * The GraphicsConfiguration that describes this Graphics2D.
+ */
+ protected GraphicsConfiguration config;
+
+ /**
* Used to create proper font metrics
*/
protected Graphics2D fmg;
@@ -1484,8 +1493,10 @@
* <code>Graphics2D</code>.
*/
public GraphicsConfiguration getDeviceConfiguration(){
- // TO BE DONE.
- return null;
+ if (config == null) {
+ config = new Config();
+ }
+ return config;
}
/* This is the list of attributes that can't currently be
@@ -1536,4 +1547,49 @@
return false;
}
+ /**
+ * Implementation of GraphicsConfiguration that describes this Graphics2D.
+ */
+ public class Config extends GraphicsConfiguration {
+
+ public BufferedImage createCompatibleImage(int w, int h) {
+ return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ public BufferedImage createCompatibleImage(int w, int h, int tr) {
+ return null;
+ }
+
+ public VolatileImage createCompatibleVolatileImage(int w, int h) {
+ return null;
+ }
+
+ public VolatileImage createCompatibleVolatileImage(int w, int h, int transparency) {
+ return null;
+ }
+
+ public Rectangle getBounds() {
+ return null;
+ }
+
+ public ColorModel getColorModel() {
+ return null;
+ }
+
+ public ColorModel getColorModel(int transparency) {
+ return null;
+ }
+
+ public AffineTransform getDefaultTransform() {
+ return new AffineTransform();
+ }
+
+ public GraphicsDevice getDevice() {
+ return null;
+ }
+
+ public AffineTransform getNormalizingTransform() {
+ return new AffineTransform();
+ }
+ }
}