blob: 08f16853fb5169b5c65d927f89f0092458150246 [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.
*/
package org.apache.batik.bridge;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.RootGraphicsNode;
import org.apache.batik.util.HaltingThread;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* This class is responsible for creating a GVT tree using an SVG DOM tree.
*
* @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
* @version $Id$
*/
public class GVTBuilder implements SVGConstants {
/**
* Constructs a new builder.
*/
public GVTBuilder() { }
/**
* Builds using the specified bridge context the specified SVG document.
*
* @param ctx the bridge context
* @param document the SVG document to build
* @exception BridgeException if an error occured while constructing
* the GVT tree
*/
public GraphicsNode build(BridgeContext ctx, Document document) {
// the bridge context is now associated to one document
ctx.setDocument(document);
ctx.initializeDocument(document);
// inform the bridge context the builder to use
ctx.setGVTBuilder(this);
// build the GVT tree
DocumentBridge dBridge = ctx.getDocumentBridge();
RootGraphicsNode rootNode = null;
try {
// create the root node
rootNode = dBridge.createGraphicsNode(ctx, document);
Element svgElement = document.getDocumentElement();
GraphicsNode topNode = null;
// get the appropriate bridge according to the specified element
Bridge bridge = ctx.getBridge(svgElement);
if (bridge == null || !(bridge instanceof GraphicsNodeBridge)) {
return null;
}
// create the associated composite graphics node
GraphicsNodeBridge gnBridge = (GraphicsNodeBridge)bridge;
topNode = gnBridge.createGraphicsNode(ctx, svgElement);
if (topNode == null) {
return null;
}
rootNode.getChildren().add(topNode);
buildComposite(ctx, svgElement, (CompositeGraphicsNode)topNode);
gnBridge.buildGraphicsNode(ctx, svgElement, topNode);
// finally, build the root node
dBridge.buildGraphicsNode(ctx, document, rootNode);
} catch (BridgeException ex) {
// update the exception with the missing parameters
ex.setGraphicsNode(rootNode);
//ex.printStackTrace();
throw ex; // re-throw the udpated exception
}
// For cursor handling
if (ctx.isInteractive()) {
ctx.addUIEventListeners(document);
// register GVT listeners for AWT event support
ctx.addGVTListener(document);
}
// <!> FIXME: TO BE REMOVED
if (ctx.isDynamic()) {
// register DOM listeners for dynamic support
ctx.addDOMListeners();
}
return rootNode;
}
/**
* Builds using the specified bridge context the specified Element.
*
* @param ctx the bridge context
* @param e the element to build
* @exception BridgeException if an error occured while constructing
* the GVT tree
*/
public GraphicsNode build(BridgeContext ctx, Element e) {
// get the appropriate bridge according to the specified element
Bridge bridge = ctx.getBridge(e);
if (bridge instanceof GenericBridge) {
// If it is a GenericBridge just handle it and any GenericBridge
// descendents and return.
((GenericBridge) bridge).handleElement(ctx, e);
handleGenericBridges(ctx, e);
return null;
} else if (bridge == null || !(bridge instanceof GraphicsNodeBridge)) {
handleGenericBridges(ctx, e);
return null;
}
// create the associated graphics node
GraphicsNodeBridge gnBridge = (GraphicsNodeBridge)bridge;
// check the display property
if (!gnBridge.getDisplay(e)) {
handleGenericBridges(ctx, e);
return null;
}
GraphicsNode gn = gnBridge.createGraphicsNode(ctx, e);
if (gn != null) {
if (gnBridge.isComposite()) {
buildComposite(ctx, e, (CompositeGraphicsNode)gn);
} else {
handleGenericBridges(ctx, e);
}
gnBridge.buildGraphicsNode(ctx, e, gn);
}
// <!> FIXME: see build(BridgeContext, Element)
// + may load the script twice (for example
// outside 'use' is ok versus local 'use' maybe wrong).
if (ctx.isDynamic()) {
//BridgeEventSupport.loadScripts(ctx, e);
}
return gn;
}
/**
* Builds a composite Element.
*
* @param ctx the bridge context
* @param e the element to build
* @param parentNode the composite graphics node, parent of the
* graphics node to build
* @exception BridgeException if an error occured while constructing
* the GVT tree
*/
protected void buildComposite(BridgeContext ctx,
Element e,
CompositeGraphicsNode parentNode) {
for (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) {
if (n.getNodeType() == Node.ELEMENT_NODE) {
buildGraphicsNode(ctx, (Element)n, parentNode);
}
}
}
/**
* Builds a 'leaf' Element.
*
* @param ctx the bridge context
* @param e the element to build
* @param parentNode the composite graphics node, parent of the
* graphics node to build
* @exception BridgeException if an error occured while constructing
* the GVT tree
*/
protected void buildGraphicsNode(BridgeContext ctx,
Element e,
CompositeGraphicsNode parentNode) {
// Check If we should halt early.
if (HaltingThread.hasBeenHalted()) {
throw new InterruptedBridgeException();
}
// get the appropriate bridge according to the specified element
Bridge bridge = ctx.getBridge(e);
if (bridge instanceof GenericBridge) {
// If it is a GenericBridge just handle it and any GenericBridge
// descendents and return.
((GenericBridge) bridge).handleElement(ctx, e);
handleGenericBridges(ctx, e);
return;
} else if (bridge == null || !(bridge instanceof GraphicsNodeBridge)) {
handleGenericBridges(ctx, e);
return;
}
// check the display property
if (!CSSUtilities.convertDisplay(e)) {
handleGenericBridges(ctx, e);
return;
}
GraphicsNodeBridge gnBridge = (GraphicsNodeBridge)bridge;
try {
// create the associated graphics node
GraphicsNode gn = gnBridge.createGraphicsNode(ctx, e);
if (gn != null) {
// attach the graphics node to the GVT tree now !
parentNode.getChildren().add(gn);
// check if the element has children to build
if (gnBridge.isComposite()) {
buildComposite(ctx, e, (CompositeGraphicsNode)gn);
} else {
// if not then still handle the GenericBridges
handleGenericBridges(ctx, e);
}
gnBridge.buildGraphicsNode(ctx, e, gn);
} else {
handleGenericBridges(ctx, e);
}
} catch (BridgeException ex) {
// some bridge may decide that the node in error can be
// displayed (e.g. polyline, path...)
// In this case, the exception contains the GraphicsNode
GraphicsNode errNode = ex.getGraphicsNode();
if (errNode != null) {
parentNode.getChildren().add(errNode);
gnBridge.buildGraphicsNode(ctx, e, errNode);
ex.setGraphicsNode(null);
}
//ex.printStackTrace();
throw ex;
}
}
/**
* Handles any GenericBridge elements which are children of the
* specified element.
* @param ctx the bridge context
* @param e the element whose child elements should be handled
*/
protected void handleGenericBridges(BridgeContext ctx, Element e) {
for (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) {
if (n instanceof Element) {
Element e2 = (Element) n;
Bridge b = ctx.getBridge(e2);
if (b instanceof GenericBridge) {
((GenericBridge) b).handleElement(ctx, e2);
}
handleGenericBridges(ctx, e2);
}
}
}
}