KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > AbstractGraphicsNodeBridge


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.Shape JavaDoc;
21 import java.awt.geom.AffineTransform JavaDoc;
22 import java.awt.geom.Rectangle2D JavaDoc;
23 import java.lang.ref.SoftReference JavaDoc;
24
25 import org.apache.batik.css.engine.CSSEngineEvent;
26 import org.apache.batik.css.engine.SVGCSSEngine;
27 import org.apache.batik.dom.svg.SVGContext;
28 import org.apache.batik.dom.svg.SVGOMElement;
29 import org.apache.batik.ext.awt.geom.SegmentList;
30 import org.apache.batik.gvt.CanvasGraphicsNode;
31 import org.apache.batik.gvt.CompositeGraphicsNode;
32 import org.apache.batik.gvt.GraphicsNode;
33
34 import org.w3c.dom.Element JavaDoc;
35 import org.w3c.dom.Node JavaDoc;
36 import org.w3c.dom.events.MutationEvent JavaDoc;
37 import org.w3c.dom.svg.SVGFitToViewBox;
38
39 /**
40  * The base bridge class for SVG graphics node. By default, the namespace URI is
41  * the SVG namespace. Override the <tt>getNamespaceURI</tt> if you want to add
42  * custom <tt>GraphicsNode</tt> with a custom namespace.
43  *
44  * <p>This class handles various attributes that are defined on most
45  * of the SVG graphic elements as described in the SVG
46  * specification.</p>
47  *
48  * <ul>
49  * <li>clip-path</li>
50  * <li>filter</li>
51  * <li>mask</li>
52  * <li>opacity</li>
53  * <li>transform</li>
54  * <li>visibility</li>
55  * </ul>
56  *
57  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
58  * @version $Id: AbstractGraphicsNodeBridge.java,v 1.40 2005/02/27 02:08:51 deweese Exp $
59  */

60 public abstract class AbstractGraphicsNodeBridge extends AbstractSVGBridge
61     implements SVGContext,
62                BridgeUpdateHandler,
63                GraphicsNodeBridge,
64                ErrorConstants {
65     
66     /**
67      * The element that has been handled by this bridge.
68      */

69     protected Element e;
70
71     /**
72      * The graphics node constructed by this bridge.
73      */

74     protected GraphicsNode node;
75
76     /**
77      * The bridge context to use for dynamic updates.
78      */

79     protected BridgeContext ctx;
80
81     /**
82      * Constructs a new abstract bridge.
83      */

84     protected AbstractGraphicsNodeBridge() {}
85
86     /**
87      * Creates a <tt>GraphicsNode</tt> according to the specified parameters.
88      *
89      * @param ctx the bridge context to use
90      * @param e the element that describes the graphics node to build
91      * @return a graphics node that represents the specified element
92      */

93     public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
94         // 'requiredFeatures', 'requiredExtensions' and 'systemLanguage'
95
if (!SVGUtilities.matchUserAgent(e, ctx.getUserAgent())) {
96             return null;
97         }
98
99         GraphicsNode node = instantiateGraphicsNode();
100         // 'transform'
101
String JavaDoc s = e.getAttributeNS(null, SVG_TRANSFORM_ATTRIBUTE);
102         if (s.length() != 0) {
103             node.setTransform
104                 (SVGUtilities.convertTransform(e, SVG_TRANSFORM_ATTRIBUTE, s));
105         }
106         // 'visibility'
107
node.setVisible(CSSUtilities.convertVisibility(e));
108         return node;
109     }
110
111     /**
112      * Creates the GraphicsNode depending on the GraphicsNodeBridge
113      * implementation.
114      */

115     protected abstract GraphicsNode instantiateGraphicsNode();
116
117     /**
118      * Builds using the specified BridgeContext and element, the
119      * specified graphics node.
120      *
121      * @param ctx the bridge context to use
122      * @param e the element that describes the graphics node to build
123      * @param node the graphics node to build
124      */

125     public void buildGraphicsNode(BridgeContext ctx,
126                                   Element e,
127                                   GraphicsNode node) {
128         // 'opacity'
129
node.setComposite(CSSUtilities.convertOpacity(e));
130         // 'filter'
131
node.setFilter(CSSUtilities.convertFilter(e, node, ctx));
132         // 'mask'
133
node.setMask(CSSUtilities.convertMask(e, node, ctx));
134         // 'clip-path'
135
node.setClip(CSSUtilities.convertClipPath(e, node, ctx));
136         // 'pointer-events'
137
node.setPointerEventType(CSSUtilities.convertPointerEvents(e));
138
139         initializeDynamicSupport(ctx, e, node);
140     }
141
142     /**
143      * Returns true if the graphics node has to be displayed, false
144      * otherwise.
145      */

146     public boolean getDisplay(Element e) {
147         return CSSUtilities.convertDisplay(e);
148     }
149
150     /**
151      * This method is invoked during the build phase if the document
152      * is dynamic. The responsability of this method is to ensure that
153      * any dynamic modifications of the element this bridge is
154      * dedicated to, happen on its associated GVT product.
155      */

156     protected void initializeDynamicSupport(BridgeContext ctx,
157                                             Element e,
158                                             GraphicsNode node) {
159         if (!ctx.isInteractive())
160             return;
161
162         // Bind the nodes for interactive and dynamic
163
ctx.bind(e, node);
164
165         if (ctx.isDynamic()) {
166             // only set context for dynamic documents not interactive.
167
this.e = e;
168             this.node = node;
169             this.ctx = ctx;
170             ((SVGOMElement)e).setSVGContext(this);
171         }
172     }
173
174     // BridgeUpdateHandler implementation //////////////////////////////////
175

176     /**
177      * Invoked when an MutationEvent of type 'DOMAttrModified' is fired.
178      */

179     public void handleDOMAttrModifiedEvent(MutationEvent JavaDoc evt) {
180         String JavaDoc attrName = evt.getAttrName();
181         if (attrName.equals(SVG_TRANSFORM_ATTRIBUTE)) {
182             String JavaDoc s = evt.getNewValue();
183             AffineTransform JavaDoc at = GraphicsNode.IDENTITY;
184             if (s.length() != 0) {
185                 at = SVGUtilities.convertTransform
186                     (e, SVG_TRANSFORM_ATTRIBUTE, s);
187             }
188             node.setTransform(at);
189             handleGeometryChanged();
190         }
191     }
192
193     /**
194      * Invoked when the geometry of an graphical element has changed.
195      */

196     protected void handleGeometryChanged() {
197         node.setFilter(CSSUtilities.convertFilter(e, node, ctx));
198         node.setMask(CSSUtilities.convertMask(e, node, ctx));
199         node.setClip(CSSUtilities.convertClipPath(e, node, ctx));
200     }
201
202     /**
203      * Invoked when an MutationEvent of type 'DOMNodeInserted' is fired.
204      */

205     public void handleDOMNodeInsertedEvent(MutationEvent JavaDoc evt) {
206         if ( evt.getTarget() instanceof Element ){
207             // Handle "generic" bridges.
208
Element e2 = (Element)evt.getTarget();
209             Bridge b = ctx.getBridge(e2);
210             if (b instanceof GenericBridge) {
211                 ((GenericBridge) b).handleElement(ctx, e2);
212             }
213         }
214     }
215
216     /**
217      * Invoked when an MutationEvent of type 'DOMNodeRemoved' is fired.
218      */

219     public void handleDOMNodeRemovedEvent(MutationEvent JavaDoc evt) {
220         CompositeGraphicsNode gn = node.getParent();
221         gn.remove(node);
222         disposeTree(e);
223     }
224
225     /**
226      * Invoked when an MutationEvent of type 'DOMCharacterDataModified'
227      * is fired.
228      */

229     public void handleDOMCharacterDataModified(MutationEvent JavaDoc evt) {
230     }
231
232     /**
233      * Disposes this BridgeUpdateHandler and releases all resources.
234      */

235     public void dispose() {
236         SVGOMElement elt = (SVGOMElement)e;
237         elt.setSVGContext(null);
238         ctx.unbind(e);
239     }
240
241
242     /**
243      * Disposes all resources related to the specified node and its subtree
244      */

245     static void disposeTree(Node node) {
246         if (node instanceof SVGOMElement) {
247             SVGOMElement elt = (SVGOMElement)node;
248             BridgeUpdateHandler h = (BridgeUpdateHandler)elt.getSVGContext();
249             if (h != null)
250                 h.dispose();
251         }
252         for (Node n = node.getFirstChild(); n!=null; n = n.getNextSibling()) {
253             disposeTree(n);
254         }
255     }
256
257     /**
258      * Invoked when an CSSEngineEvent is fired.
259      */

260     public void handleCSSEngineEvent(CSSEngineEvent evt) {
261         try {
262             int [] properties = evt.getProperties();
263             for (int i=0; i < properties.length; ++i) {
264                 handleCSSPropertyChanged(properties[i]);
265             }
266         } catch (Exception JavaDoc ex) {
267             ctx.getUserAgent().displayError(ex);
268         }
269     }
270
271     /**
272      * Invoked for each CSS property that has changed.
273      */

274     protected void handleCSSPropertyChanged(int property) {
275         switch(property) {
276         case SVGCSSEngine.VISIBILITY_INDEX:
277             node.setVisible(CSSUtilities.convertVisibility(e));
278             break;
279         case SVGCSSEngine.OPACITY_INDEX:
280             node.setComposite(CSSUtilities.convertOpacity(e));
281             break;
282         case SVGCSSEngine.FILTER_INDEX:
283             node.setFilter(CSSUtilities.convertFilter(e, node, ctx));
284             break;
285         case SVGCSSEngine.MASK_INDEX:
286             node.setMask(CSSUtilities.convertMask(e, node, ctx));
287             break;
288         case SVGCSSEngine.CLIP_PATH_INDEX:
289             node.setClip(CSSUtilities.convertClipPath(e, node, ctx));
290             break;
291         case SVGCSSEngine.POINTER_EVENTS_INDEX:
292             node.setPointerEventType(CSSUtilities.convertPointerEvents(e));
293             break;
294         case SVGCSSEngine.DISPLAY_INDEX:
295             if (!getDisplay(e)) {
296                 // Remove the subtree.
297
CompositeGraphicsNode parent = node.getParent();
298                 int idx = parent.indexOf(node);
299                 parent.remove(node);
300                 disposeTree(e);
301             }
302             break;
303         }
304     }
305
306     // SVGContext implementation ///////////////////////////////////////////
307

308     /**
309      * Returns the size of a px CSS unit in millimeters.
310      */

311     public float getPixelUnitToMillimeter() {
312         return ctx.getUserAgent().getPixelUnitToMillimeter();
313     }
314
315     /**
316      * Returns the size of a px CSS unit in millimeters.
317      * This will be removed after next release.
318      * @see #getPixelUnitToMillimeter()
319      */

320     public float getPixelToMM() {
321         return getPixelUnitToMillimeter();
322             
323     }
324
325     protected SoftReference JavaDoc bboxShape = null;
326     protected Rectangle2D JavaDoc bbox = null;
327
328     /**
329      * Returns the tight bounding box in current user space (i.e.,
330      * after application of the transform attribute, if any) on the
331      * geometry of all contained graphics elements, exclusive of
332      * stroke-width and filter effects).
333      */

334     public Rectangle2D JavaDoc getBBox() {
335         Shape JavaDoc s = node.getOutline();
336         
337         if ((bboxShape != null) && (s == bboxShape.get())) return bbox;
338         bboxShape = new SoftReference JavaDoc(s); // don't keep this live.
339
bbox = null;
340         if (s == null) return bbox;
341
342         // SegmentList.getBounds2D gives tight BBox.
343
SegmentList sl = new SegmentList(s);
344         bbox = sl.getBounds2D();
345         return bbox;
346     }
347
348     /**
349      * Returns the transformation matrix from current user units
350      * (i.e., after application of the transform attribute, if any) to
351      * the viewport coordinate system for the nearestViewportElement.
352      */

353     public AffineTransform JavaDoc getCTM() {
354         GraphicsNode gn = node;
355         AffineTransform JavaDoc ctm = new AffineTransform JavaDoc();
356         Element elt = e;
357         while (elt != null) {
358             if (elt instanceof SVGFitToViewBox) {
359                 AffineTransform JavaDoc at;
360                 if (gn instanceof CanvasGraphicsNode) {
361                     at = ((CanvasGraphicsNode)gn).getViewingTransform();
362                 } else {
363                     at = gn.getTransform();
364                 }
365                 if (at != null) {
366                     ctm.preConcatenate(at);
367                 }
368                 break;
369             }
370
371             AffineTransform JavaDoc at = gn.getTransform();
372             if (at != null)
373                 ctm.preConcatenate(at);
374
375             elt = SVGCSSEngine.getParentCSSStylableElement(elt);
376             gn = gn.getParent();
377         }
378         return ctm;
379     }
380
381     /**
382      * Returns the display transform.
383      */

384     public AffineTransform JavaDoc getScreenTransform() {
385         return ctx.getUserAgent().getTransform();
386     }
387
388     /**
389      * Sets the display transform.
390      */

391     public void setScreenTransform(AffineTransform JavaDoc at) {
392         ctx.getUserAgent().setTransform(at);
393     }
394
395     /**
396      * Returns the global transformation matrix from the current
397      * element to the root.
398      */

399     public AffineTransform JavaDoc getGlobalTransform() {
400         return node.getGlobalTransform();
401     }
402
403     /**
404      * Returns the width of the viewport which directly contains the
405      * given element.
406      */

407     public float getViewportWidth() {
408         return ctx.getBlockWidth(e);
409     }
410
411     /**
412      * Returns the height of the viewport which directly contains the
413      * given element.
414      */

415     public float getViewportHeight() {
416         return ctx.getBlockHeight(e);
417     }
418
419     /**
420      * Returns the font-size on the associated element.
421      */

422     public float getFontSize() {
423         return CSSUtilities.getComputedStyle
424             (e, SVGCSSEngine.FONT_SIZE_INDEX).getFloatValue();
425     }
426 }
427
Popular Tags