001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.bridge;
020:
021: import java.awt.RenderingHints;
022:
023: import org.apache.batik.css.engine.CSSEngineEvent;
024: import org.apache.batik.css.engine.SVGCSSEngine;
025: import org.apache.batik.gvt.GraphicsNode;
026: import org.apache.batik.gvt.ShapeNode;
027: import org.apache.batik.gvt.ShapePainter;
028: import org.w3c.dom.Element;
029:
030: /**
031: * The base bridge class for shapes. Subclasses bridge <tt>ShapeNode</tt>.
032: *
033: * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
034: * @version $Id: SVGShapeElementBridge.java 475477 2006-11-15 22:44:28Z cam $
035: */
036: public abstract class SVGShapeElementBridge extends
037: AbstractGraphicsNodeBridge {
038:
039: /**
040: * Constructs a new bridge for SVG shapes.
041: */
042: protected SVGShapeElementBridge() {
043: }
044:
045: /**
046: * Creates a graphics node using the specified BridgeContext and
047: * for the specified element.
048: *
049: * @param ctx the bridge context to use
050: * @param e the element that describes the graphics node to build
051: * @return a graphics node that represents the specified element
052: */
053: public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
054: ShapeNode shapeNode = (ShapeNode) super .createGraphicsNode(ctx,
055: e);
056: if (shapeNode == null) {
057: return null;
058: }
059:
060: associateSVGContext(ctx, e, shapeNode);
061:
062: // delegates to subclasses the shape construction
063: buildShape(ctx, e, shapeNode);
064:
065: // 'shape-rendering' and 'color-rendering'
066: RenderingHints hints = null;
067: hints = CSSUtilities.convertColorRendering(e, hints);
068: hints = CSSUtilities.convertShapeRendering(e, hints);
069: if (hints != null)
070: shapeNode.setRenderingHints(hints);
071:
072: return shapeNode;
073: }
074:
075: /**
076: * Creates a <tt>ShapeNode</tt>.
077: */
078: protected GraphicsNode instantiateGraphicsNode() {
079: return new ShapeNode();
080: }
081:
082: /**
083: * Builds using the specified BridgeContext and element, the
084: * specified graphics node.
085: *
086: * @param ctx the bridge context to use
087: * @param e the element that describes the graphics node to build
088: * @param node the graphics node to build
089: */
090: public void buildGraphicsNode(BridgeContext ctx, Element e,
091: GraphicsNode node) {
092: ShapeNode shapeNode = (ShapeNode) node;
093: shapeNode
094: .setShapePainter(createShapePainter(ctx, e, shapeNode));
095: super .buildGraphicsNode(ctx, e, node);
096: }
097:
098: /**
099: * Creates the shape painter associated to the specified element.
100: * This implementation creates a shape painter considering the
101: * various fill and stroke properties.
102: *
103: * @param ctx the bridge context to use
104: * @param e the element that describes the shape painter to use
105: * @param shapeNode the shape node that is interested in its shape painter
106: */
107: protected ShapePainter createShapePainter(BridgeContext ctx,
108: Element e, ShapeNode shapeNode) {
109: // 'fill'
110: // 'fill-opacity'
111: // 'stroke'
112: // 'stroke-opacity',
113: // 'stroke-width'
114: // 'stroke-linecap'
115: // 'stroke-linejoin'
116: // 'stroke-miterlimit'
117: // 'stroke-dasharray'
118: // 'stroke-dashoffset'
119: return PaintServer.convertFillAndStroke(e, shapeNode, ctx);
120: }
121:
122: /**
123: * Initializes the specified ShapeNode's shape defined by the
124: * specified Element and using the specified bridge context.
125: *
126: * @param ctx the bridge context to use
127: * @param e the element that describes the shape node to build
128: * @param node the shape node to initialize
129: */
130: protected abstract void buildShape(BridgeContext ctx, Element e,
131: ShapeNode node);
132:
133: /**
134: * Returns false as shapes are not a container.
135: */
136: public boolean isComposite() {
137: return false;
138: }
139:
140: // BridgeUpdateHandler implementation //////////////////////////////////
141:
142: /**
143: * Invoked when the geometry of an graphical element has changed.
144: */
145: protected void handleGeometryChanged() {
146: super .handleGeometryChanged();
147: ShapeNode shapeNode = (ShapeNode) node;
148: shapeNode
149: .setShapePainter(createShapePainter(ctx, e, shapeNode));
150: }
151:
152: /**
153: * This flag bit indicates if a new shape painter has already been created.
154: * Avoid creating one ShapePainter per CSS property change
155: */
156: protected boolean hasNewShapePainter;
157:
158: /**
159: * Invoked when CSS properties have changed on an element.
160: *
161: * @param evt the CSSEngine event that describes the update
162: */
163: public void handleCSSEngineEvent(CSSEngineEvent evt) {
164: hasNewShapePainter = false;
165: super .handleCSSEngineEvent(evt);
166: }
167:
168: /**
169: * Invoked for each CSS property that has changed.
170: */
171: protected void handleCSSPropertyChanged(int property) {
172: switch (property) {
173: case SVGCSSEngine.FILL_INDEX:
174: case SVGCSSEngine.FILL_OPACITY_INDEX:
175: case SVGCSSEngine.STROKE_INDEX:
176: case SVGCSSEngine.STROKE_OPACITY_INDEX:
177: // Opportunity to just 'update' the existing shape painters...
178: case SVGCSSEngine.STROKE_WIDTH_INDEX:
179: case SVGCSSEngine.STROKE_LINECAP_INDEX:
180: case SVGCSSEngine.STROKE_LINEJOIN_INDEX:
181: case SVGCSSEngine.STROKE_MITERLIMIT_INDEX:
182: case SVGCSSEngine.STROKE_DASHARRAY_INDEX:
183: case SVGCSSEngine.STROKE_DASHOFFSET_INDEX: {
184: if (!hasNewShapePainter) {
185: hasNewShapePainter = true;
186: ShapeNode shapeNode = (ShapeNode) node;
187: shapeNode.setShapePainter(createShapePainter(ctx, e,
188: shapeNode));
189: }
190: break;
191: }
192: case SVGCSSEngine.SHAPE_RENDERING_INDEX: {
193: RenderingHints hints = node.getRenderingHints();
194: hints = CSSUtilities.convertShapeRendering(e, hints);
195: if (hints != null) {
196: node.setRenderingHints(hints);
197: }
198: break;
199: }
200: case SVGCSSEngine.COLOR_RENDERING_INDEX: {
201: RenderingHints hints = node.getRenderingHints();
202: hints = CSSUtilities.convertColorRendering(e, hints);
203: if (hints != null) {
204: node.setRenderingHints(hints);
205: }
206: break;
207: }
208: default:
209: super.handleCSSPropertyChanged(property);
210: }
211: }
212: }
|