KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Copyright 2000-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.Cursor JavaDoc;
21 import java.awt.geom.Dimension2D JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InterruptedIOException JavaDoc;
24 import java.lang.ref.SoftReference JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedList JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.ListIterator JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36
37 import org.apache.batik.bridge.svg12.SVG12BridgeExtension;
38 import org.apache.batik.css.engine.CSSContext;
39 import org.apache.batik.css.engine.CSSEngine;
40 import org.apache.batik.css.engine.CSSEngineEvent;
41 import org.apache.batik.css.engine.CSSEngineListener;
42 import org.apache.batik.css.engine.CSSEngineUserAgent;
43 import org.apache.batik.css.engine.SVGCSSEngine;
44 import org.apache.batik.css.engine.SystemColorSupport;
45 import org.apache.batik.css.engine.value.Value;
46 import org.apache.batik.dom.svg.SVGContext;
47 import org.apache.batik.dom.svg.SVGDOMImplementation;
48 import org.apache.batik.dom.svg.SVGOMDocument;
49 import org.apache.batik.dom.svg.SVGOMElement;
50 import org.apache.batik.dom.svg.SVGStylableElement;
51 import org.apache.batik.gvt.CompositeGraphicsNode;
52 import org.apache.batik.gvt.GraphicsNode;
53 import org.apache.batik.gvt.TextPainter;
54 import org.apache.batik.script.Interpreter;
55 import org.apache.batik.script.InterpreterPool;
56 import org.apache.batik.util.CSSConstants;
57 import org.apache.batik.util.CleanerThread;
58 import org.apache.batik.util.ParsedURL;
59 import org.apache.batik.util.SVGConstants;
60 import org.apache.batik.util.Service;
61
62 import org.w3c.dom.Document JavaDoc;
63 import org.w3c.dom.Element JavaDoc;
64 import org.w3c.dom.Node JavaDoc;
65 import org.w3c.dom.events.Event JavaDoc;
66 import org.w3c.dom.events.EventListener JavaDoc;
67 import org.w3c.dom.events.EventTarget JavaDoc;
68 import org.w3c.dom.events.MouseEvent JavaDoc;
69 import org.w3c.dom.events.MutationEvent JavaDoc;
70 import org.w3c.dom.svg.SVGDocument;
71
72 /**
73  * This class represents a context used by the various bridges and the
74  * builder. A bridge context is associated to a particular document
75  * and cannot be reused.
76  *
77  * The context encapsulates the dynamic bindings between DOM elements
78  * and GVT nodes, graphic contexts such as a <tt>GraphicsNodeRenderContext</tt>,
79  * and the different objects required by the GVT builder to interpret
80  * a SVG DOM tree such as the current viewport or the user agent.
81  *
82  * @author <a HREF="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
83  * @version $Id: BridgeContext.java,v 1.83 2005/03/29 10:48:02 deweese Exp $
84  */

85 public class BridgeContext implements ErrorConstants, CSSContext {
86
87     /**
88      * The document is bridge context is dedicated to.
89      */

90     protected Document document;
91
92     /**
93      * The GVT builder that might be used to create a GVT subtree.
94      */

95     protected GVTBuilder gvtBuilder;
96
97     /**
98      * The interpreter cache per document.
99      * key is the language -
100      * value is a Interpreter
101      */

102     protected Map JavaDoc interpreterMap = new HashMap JavaDoc(7);
103
104     /**
105      * A Map of all the font families already matched. This is
106      * to reduce the number of instances of GVTFontFamilies and to
107      * hopefully reduce the time taken to search for a matching SVG font.
108      */

109     private Map JavaDoc fontFamilyMap;
110
111     /**
112      * The viewports.
113      * key is an Element -
114      * value is a Viewport
115      */

116     protected Map JavaDoc viewportMap = new WeakHashMap JavaDoc();
117
118     /**
119      * The viewport stack. Used in building time.
120      */

121     protected List JavaDoc viewportStack = new LinkedList JavaDoc();
122
123     /**
124      * The user agent.
125      */

126     protected UserAgent userAgent;
127
128     /**
129      * Binding Map:
130      * key is an SVG Element -
131      * value is a GraphicsNode
132      */

133     protected Map JavaDoc elementNodeMap;
134
135     /**
136      * Binding Map:
137      * key is GraphicsNode -
138      * value is a SVG Element.
139      */

140     protected Map JavaDoc nodeElementMap;
141
142     /**
143      * Bridge Map:
144      * Keys are namespace URI - values are HashMap (with keys are local
145      * name and values are a Bridge instance).
146      */

147     protected Map JavaDoc namespaceURIMap;
148
149     /**
150      * Element Data Map:
151      * This is a general location for elements to 'cache'
152      * data. Such as the graphics tree for a pattern or
153      * the Gradient arrays.
154      *
155      * This is a weak hash map and the data is referenced
156      * by SoftReference so both must be referenced elsewhere
157      * to stay live.
158      */

159     protected Map JavaDoc elementDataMap;
160
161
162     /**
163      * The interpreter pool used to handle scripts.
164      */

165     protected InterpreterPool interpreterPool;
166
167     /**
168      * The document loader used to load/create Document.
169      */

170     protected DocumentLoader documentLoader;
171
172     /**
173      * The size of the document.
174      */

175     protected Dimension2D JavaDoc documentSize;
176
177     /**
178      * The text painter to use. Typically, you can specify the text painter that
179      * will be used be text nodes.
180      */

181     protected TextPainter textPainter;
182
183     /**
184      * Indicates that no DOM listeners should be registered. In this
185      * case the generated GVT tree should be totally independent of
186      * the DOM tree (in practice text holds references to the source
187      * text elements for font resolution).
188      */

189     public final static int STATIC = 0;
190     /**
191      * Indicates that DOM listeners should be registered to support,
192      * 'interactivity' this includes anchors and cursors, but does not
193      * include support for DOM modifications.
194      */

195     public final static int INTERACTIVE = 1;
196
197     /**
198      * Indicates that all DOM listeners should be registered. This supports
199      * 'interactivity' (anchors and cursors), as well as DOM modifications
200      * listeners to update the GVT rendering tree.
201      */

202     public final static int DYNAMIC = 2;
203
204     /**
205      * Whether the bridge should support dynamic, or interactive features.
206      */

207     protected int dynamicStatus = STATIC;
208
209     /**
210      * The update manager.
211      */

212     protected UpdateManager updateManager;
213
214     /**
215      * Constructs a new empty bridge context.
216      */

217     protected BridgeContext() {}
218
219     /**
220      * By default we share a unique instance of InterpreterPool.
221      */

222     private static InterpreterPool sharedPool = new InterpreterPool();
223
224     /**
225      * Constructs a new bridge context.
226      * @param userAgent the user agent
227      */

228     public BridgeContext(UserAgent userAgent) {
229         this(userAgent,
230              sharedPool,
231              new DocumentLoader(userAgent));
232     }
233
234     /**
235      * Constructs a new bridge context.
236      * @param userAgent the user agent
237      * @param loader document loader
238      */

239     public BridgeContext(UserAgent userAgent,
240                          DocumentLoader loader) {
241         this(userAgent, sharedPool, loader);
242     }
243
244     /**
245      * Constructs a new bridge context.
246      * @param userAgent the user agent
247      * @param interpreterPool the interpreter pool
248      * @param documentLoader document loader
249      */

250     public BridgeContext(UserAgent userAgent,
251                          InterpreterPool interpreterPool,
252                          DocumentLoader documentLoader) {
253         this.userAgent = userAgent;
254         this.viewportMap.put(userAgent, new UserAgentViewport(userAgent));
255         this.interpreterPool = interpreterPool;
256         this.documentLoader = documentLoader;
257     }
258
259     /**
260      * Initializes the given document.
261      */

262     protected void initializeDocument(Document document) {
263         SVGOMDocument doc = (SVGOMDocument)document;
264         CSSEngine eng = doc.getCSSEngine();
265         if (eng == null) {
266             SVGDOMImplementation impl;
267             impl = (SVGDOMImplementation)doc.getImplementation();
268             eng = impl.createCSSEngine(doc, this);
269             eng.setCSSEngineUserAgent(new CSSEngineUserAgentWrapper(userAgent));
270             doc.setCSSEngine(eng);
271             eng.setMedia(userAgent.getMedia());
272             String JavaDoc uri = userAgent.getUserStyleSheetURI();
273             if (uri != null) {
274                 try {
275                     URL JavaDoc url = new URL JavaDoc(uri);
276                     eng.setUserAgentStyleSheet
277                         (eng.parseStyleSheet(url, "all"));
278                 } catch (MalformedURLException JavaDoc e) {
279                     userAgent.displayError(e);
280                 }
281             }
282             eng.setAlternateStyleSheet(userAgent.getAlternateStyleSheet());
283         }
284     }
285
286     /**
287      * Returns the CSS engine associated with given element.
288      */

289     public CSSEngine getCSSEngineForElement(Element e) {
290         SVGOMDocument doc = (SVGOMDocument)e.getOwnerDocument();
291         return doc.getCSSEngine();
292     }
293
294     // properties ////////////////////////////////////////////////////////////
295

296     /**
297      * Sets the text painter that will be used by text nodes. This attributes
298      * might be used by bridges (especially SVGTextElementBridge) to set the
299      * text painter of each TextNode.
300      *
301      * @param textPainter the text painter for text nodes
302      */

303     public void setTextPainter(TextPainter textPainter) {
304     this.textPainter = textPainter;
305     }
306
307     /**
308      * Returns the text painter that will be used be text nodes.
309      */

310     public TextPainter getTextPainter() {
311     return textPainter;
312     }
313
314     /**
315      * Returns the document this bridge context is dedicated to.
316      */

317     public Document getDocument() {
318         return document;
319     }
320
321     /**
322      * Sets the document this bridge context is dedicated to, to the
323      * specified document.
324      * @param document the document
325      */

326     protected void setDocument(Document document) {
327         if (this.document != document){
328             fontFamilyMap = null;
329         }
330         this.document = document;
331         registerSVGBridges();
332     }
333
334     /**
335      * Returns the map of font families
336      */

337     public Map JavaDoc getFontFamilyMap(){
338         if (fontFamilyMap == null){
339             fontFamilyMap = new HashMap JavaDoc();
340         }
341         return fontFamilyMap;
342     }
343
344     /**
345      * Sets the map of font families to the specified value.
346      *
347      *@param fontFamilyMap the map of font families
348      */

349     protected void setFontFamilyMap(Map JavaDoc fontFamilyMap) {
350         this.fontFamilyMap = fontFamilyMap;
351     }
352
353     /**
354      * Set Element Data.
355      * Associates data object with element so it can be
356      * retrieved later.
357      */

358     public void setElementData(Node n, Object JavaDoc data) {
359         if (elementDataMap == null)
360             elementDataMap = new WeakHashMap JavaDoc();
361         elementDataMap.put(n, new SoftReference JavaDoc(data));
362     }
363
364     /**
365      * Set Element Data.
366      * Associates data object with element so it can be
367      * retrieved later.
368      */

369     public Object JavaDoc getElementData(Node n) {
370         if (elementDataMap == null)
371             return null;
372         Object JavaDoc o = elementDataMap.get(n);
373         if (o == null) return null;
374         SoftReference JavaDoc sr = (SoftReference JavaDoc)o;
375         o = sr.get();
376         if (o == null) {
377             elementDataMap.remove(n);
378         }
379         return o;
380     }
381
382     /**
383      * Returns the user agent of this bridge context.
384      */

385     public UserAgent getUserAgent() {
386         return userAgent;
387     }
388
389     /**
390      * Sets the user agent to the specified user agent.
391      * @param userAgent the user agent
392      */

393     protected void setUserAgent(UserAgent userAgent) {
394         this.userAgent = userAgent;
395     }
396
397     /**
398      * Returns the GVT builder that is currently used to build the GVT tree.
399      */

400     public GVTBuilder getGVTBuilder() {
401         return gvtBuilder;
402     }
403
404     /**
405      * Sets the GVT builder that uses this context.
406      */

407     protected void setGVTBuilder(GVTBuilder gvtBuilder) {
408         this.gvtBuilder = gvtBuilder;
409     }
410
411     /**
412      * Returns the interpreter pool used to handle scripts.
413      */

414     public InterpreterPool getInterpreterPool() {
415         return interpreterPool;
416     }
417
418     /**
419      * Returns the focus manager.
420      */

421     public FocusManager getFocusManager() {
422         return focusManager;
423     }
424
425     /**
426      * Returns the cursor manager
427      */

428     public CursorManager getCursorManager() {
429         return cursorManager;
430     }
431
432     /**
433      * Sets the interpreter pool used to handle scripts to the
434      * specified interpreter pool.
435      * @param interpreterPool the interpreter pool
436      */

437     protected void setInterpreterPool(InterpreterPool interpreterPool) {
438         this.interpreterPool = interpreterPool;
439     }
440
441     /**
442      * Returns a Interpreter for the specified language.
443      *
444      * @param language the scripting language
445      */

446     public Interpreter getInterpreter(String JavaDoc language) {
447         if (document == null) {
448             throw new RuntimeException JavaDoc("Unknown document");
449         }
450         Interpreter interpreter = (Interpreter)interpreterMap.get(language);
451         if (interpreter == null) {
452             try {
453                 interpreter = interpreterPool.createInterpreter(document, language);
454                 interpreterMap.put(language, interpreter);
455             } catch (Exception JavaDoc e) {
456                 if (userAgent != null) {
457                     userAgent.displayError(e);
458                     return null;
459                 }
460             }
461         }
462
463         if (interpreter == null) {
464             if (userAgent != null) {
465                 userAgent.displayError(new Exception JavaDoc("Unknown language: " + language));
466             }
467         }
468
469         return interpreter;
470     }
471
472     /**
473      * Returns the document loader used to load external documents.
474      */

475     public DocumentLoader getDocumentLoader() {
476         return documentLoader;
477     }
478
479     /**
480      * Sets the document loader used to load external documents.
481      * @param newDocumentLoader the new document loader
482      */

483     protected void setDocumentLoader(DocumentLoader newDocumentLoader) {
484         this.documentLoader = newDocumentLoader;
485     }
486
487     /**
488      * Returns the actual size of the document or null if the document
489      * has not been built yet.
490      */

491     public Dimension2D JavaDoc getDocumentSize() {
492         return documentSize;
493     }
494
495     /**
496      * Sets the size of the document to the specified dimension.
497      *
498      * @param d the actual size of the SVG document
499      */

500     protected void setDocumentSize(Dimension2D JavaDoc d) {
501         this.documentSize = d;
502     }
503
504     /**
505      * Returns true if the document is dynamic, false otherwise.
506      */

507     public boolean isDynamic() {
508         return (dynamicStatus == DYNAMIC);
509     }
510
511     /**
512      * Returns true if the document is interactive, false otherwise.
513      */

514     public boolean isInteractive() {
515         return (dynamicStatus != STATIC);
516     }
517
518     /**
519      * Sets the document as a STATIC, INTERACTIVE or DYNAMIC document.
520      * Call this method before the build phase
521      * (ie. before <tt>gvtBuilder.build(...)</tt>)
522      * otherwise, that will have no effect.
523      *
524      *@param status the document dynamicStatus
525      */

526     public void setDynamicState(int status) {
527         dynamicStatus = status;
528     }
529
530     /**
531      * Sets the document as DYNAMIC if <tt>dynamic</tt> is true
532      * STATIC otherwise.
533      */

534     public void setDynamic(boolean dynamic) {
535         if (dynamic)
536             setDynamicState(DYNAMIC);
537         else
538             setDynamicState(STATIC);
539     }
540
541     /**
542      * Sets the document as INTERACTIVE if <tt>interactive</tt> is
543      * true STATIC otherwise.
544      */

545     public void setInteractive(boolean interactive) {
546         if (interactive)
547             setDynamicState(INTERACTIVE);
548         else
549             setDynamicState(STATIC);
550     }
551
552
553     /**
554      * Returns the update manager, if the bridge supports dynamic features.
555      */

556     public UpdateManager getUpdateManager() {
557         return updateManager;
558     }
559
560     /**
561      * Sets the update manager.
562      */

563     protected void setUpdateManager(UpdateManager um) {
564         updateManager = um;
565     }
566
567     // reference management //////////////////////////////////////////////////
568

569     /**
570      * Returns the element referenced by the specified element by the
571      * specified uri. The referenced element can not be a Document.
572      *
573      * @param e the element referencing
574      * @param uri the uri of the referenced element
575      */

576     public Element getReferencedElement(Element e, String JavaDoc uri) {
577         try {
578             SVGDocument document = (SVGDocument)e.getOwnerDocument();
579             URIResolver ur = new URIResolver(document, documentLoader);
580             Element ref = ur.getElement(uri, e);
581             if (ref == null) {
582                 throw new BridgeException(e, ERR_URI_BAD_TARGET,
583                                           new Object JavaDoc[] {uri});
584             } else {
585                 SVGOMDocument refDoc = (SVGOMDocument)ref.getOwnerDocument();
586                 // This is new rather than attaching this BridgeContext
587
// with the new document we now create a whole new
588
// BridgeContext to go with the new document.
589
// This means that the new document has it's own
590
// world of stuff and it should avoid memory leaks
591
// since the new document isn't 'tied into' this
592
// bridge context.
593
if (refDoc != document) {
594                     CSSEngine eng = refDoc.getCSSEngine();
595                     if (eng == null) {
596                         BridgeContext subCtx;
597                         subCtx = new BridgeContext(getUserAgent(),
598                                                    getDocumentLoader());
599                         subCtx.setGVTBuilder(getGVTBuilder());
600                         subCtx.setDocument(refDoc);
601                         subCtx.initializeDocument(refDoc);
602                     }
603                 }
604                 return ref;
605             }
606         } catch (MalformedURLException JavaDoc ex) {
607             throw new BridgeException(e, ERR_URI_MALFORMED,
608                                       new Object JavaDoc[] {uri});
609         } catch (InterruptedIOException JavaDoc ex) {
610             throw new InterruptedBridgeException();
611         } catch (IOException JavaDoc ex) {
612             throw new BridgeException(e, ERR_URI_IO,
613                                       new Object JavaDoc[] {uri});
614         } catch (IllegalArgumentException JavaDoc ex) {
615             throw new BridgeException(e, ERR_URI_REFERENCE_A_DOCUMENT,
616                                       new Object JavaDoc[] {uri});
617         } catch (SecurityException JavaDoc ex) {
618             throw new BridgeException(e, ERR_URI_UNSECURE,
619                                       new Object JavaDoc[] {uri});
620         }
621     }
622
623     // Viewport //////////////////////////////////////////////////////////////
624

625     /**
626      * Returns the viewport of the specified element.
627      *
628      * @param e the element interested in its viewport
629      */

630     public Viewport getViewport(Element e) {
631         if (viewportStack != null) {
632             // building time
633
if (viewportStack.size() == 0) {
634                 // outermost svg element
635
return (Viewport)viewportMap.get(userAgent);
636             } else {
637                 // current viewport
638
return (Viewport)viewportStack.get(0);
639             }
640         } else {
641             // search the first parent which has defined a viewport
642
e = SVGUtilities.getParentElement(e);
643             while (e != null) {
644                 Viewport viewport = (Viewport)viewportMap.get(e);
645                 if (viewport != null) {
646                     return viewport;
647                 }
648                 e = SVGUtilities.getParentElement(e);
649             }
650             return (Viewport)viewportMap.get(userAgent);
651         }
652     }
653
654     /**
655      * Starts a new viewport from the specified element.
656      *
657      * @param e the element that defines a new viewport
658      * @param viewport the viewport of the element
659      */

660     public void openViewport(Element e, Viewport viewport) {
661         viewportMap.put(e, viewport);
662         if (viewportStack == null) {
663             viewportStack = new LinkedList JavaDoc();
664         }
665         viewportStack.add(0, viewport);
666     }
667
668     public void removeViewport(Element e) {
669         viewportMap.remove(e);
670     }
671
672     /**
673      * Closes the viewport associated to the specified element.
674      * @param e the element that closes its viewport
675      */

676     public void closeViewport(Element e) {
677         //viewportMap.remove(e); FIXME: potential memory leak
678
viewportStack.remove(0);
679         if (viewportStack.size() == 0) {
680             viewportStack = null;
681         }
682     }
683
684     // Bindings //////////////////////////////////////////////////////////////
685

686     /**
687      * Binds the specified GraphicsNode to the specified Element. This method
688      * automatically bind the graphics node to the element and the element to
689      * the graphics node.
690      *
691      * @param element the element to bind to the specified graphics node
692      * @param node the graphics node to bind to the specified element
693      */

694     public void bind(Element element, GraphicsNode node) {
695         if (elementNodeMap == null) {
696             elementNodeMap = new WeakHashMap JavaDoc();
697             nodeElementMap = new WeakHashMap JavaDoc();
698         }
699         elementNodeMap.put(element, new SoftReference JavaDoc(node));
700         nodeElementMap.put(node, new SoftReference JavaDoc(element));
701     }
702
703     /**
704      * Removes the binding of the specified Element.
705      *
706      * @param element the element to unbind
707      */

708     public void unbind(Element element) {
709         if (elementNodeMap == null) {
710             return;
711         }
712         GraphicsNode node = null;
713         SoftReference JavaDoc sr = (SoftReference JavaDoc)elementNodeMap.get(element);
714         if (sr != null)
715             node = (GraphicsNode)sr.get();
716         elementNodeMap.remove(element);
717         if (node != null)
718             nodeElementMap.remove(node);
719     }
720
721     /**
722      * Returns the GraphicsNode associated to the specified Element or
723      * null if any.
724      *
725      * @param element the element associated to the graphics node to return
726      */

727     public GraphicsNode getGraphicsNode(Element element) {
728         if (elementNodeMap != null) {
729             SoftReference JavaDoc sr = (SoftReference JavaDoc)elementNodeMap.get(element);
730             if (sr != null)
731                 return (GraphicsNode)sr.get();
732         }
733         return null;
734     }
735
736     /**
737      * Returns the Element associated to the specified GraphicsNode or
738      * null if any.
739      *
740      * @param node the graphics node associated to the element to return
741      */

742     public Element getElement(GraphicsNode node) {
743         if (nodeElementMap != null) {
744             SoftReference JavaDoc sr = (SoftReference JavaDoc)nodeElementMap.get(node);
745             if (sr != null)
746                 return (Element)sr.get();
747         }
748         return null;
749     }
750
751     // Bridge management /////////////////////////////////////////////////////
752

753     /**
754      * Returns true if the specified element has a GraphicsNodeBridge
755      * associated to it, false otherwise.
756      *
757      * @param element the element
758      */

759     public boolean hasGraphicsNodeBridge(Element element) {
760         if (namespaceURIMap == null || element == null) {
761             return false;
762         }
763         String JavaDoc localName = element.getLocalName();
764         String JavaDoc namespaceURI = element.getNamespaceURI();
765         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
766         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
767         if (localNameMap == null) {
768             return false;
769         }
770         return (localNameMap.get(localName) instanceof GraphicsNodeBridge);
771     }
772
773     /**
774      * Returns the bridge associated with the specified element.
775      *
776      * @param element the element
777      */

778     public Bridge getBridge(Element element) {
779         if (namespaceURIMap == null || element == null) {
780             return null;
781         }
782         String JavaDoc localName = element.getLocalName();
783         String JavaDoc namespaceURI = element.getNamespaceURI();
784         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
785         return getBridge(namespaceURI, localName);
786     }
787
788     /**
789      * Returns the bridge associated with the element type
790      *
791      * @param namespaceURI namespace of the requested element
792      * @param localName element's local name
793      *
794      */

795     public Bridge getBridge(String JavaDoc namespaceURI, String JavaDoc localName) {
796         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
797         if (localNameMap == null) {
798             return null;
799         }
800         Bridge bridge = (Bridge)localNameMap.get(localName);
801         if (isDynamic()) {
802             return bridge == null ? null : bridge.getInstance();
803         } else {
804             return bridge;
805         }
806     }
807
808     /**
809      * Associates the specified <tt>Bridge</tt> object with the specified
810      * namespace URI and local name.
811      * @param namespaceURI the namespace URI
812      * @param localName the local name
813      * @param bridge the bridge that manages the element
814      */

815     public void putBridge(String JavaDoc namespaceURI, String JavaDoc localName, Bridge bridge) {
816         // start assert
817
if (!(namespaceURI.equals(bridge.getNamespaceURI())
818               && localName.equals(bridge.getLocalName()))) {
819             throw new Error JavaDoc("Invalid Bridge: "+
820                             namespaceURI+"/"+bridge.getNamespaceURI()+" "+
821                             localName+"/"+bridge.getLocalName()+" "+
822                             bridge.getClass());
823         }
824         // end assert
825
if (namespaceURIMap == null) {
826             namespaceURIMap = new HashMap JavaDoc();
827         }
828         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
829         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
830         if (localNameMap == null) {
831             localNameMap = new HashMap JavaDoc();
832             namespaceURIMap.put(namespaceURI, localNameMap);
833         }
834         localNameMap.put(localName, bridge);
835     }
836
837     /**
838      * Associates the specified <tt>Bridge</tt> object with it's
839      * namespace URI and local name.
840      *
841      * @param bridge the bridge that manages the element
842      */

843     public void putBridge(Bridge bridge) {
844         putBridge(bridge.getNamespaceURI(), bridge.getLocalName(), bridge);
845     }
846
847     /**
848      * Removes the <tt>Bridge</tt> object associated to the specified
849      * namespace URI and local name.
850      *
851      * @param namespaceURI the namespace URI
852      * @param localName the local name
853      */

854     public void removeBridge(String JavaDoc namespaceURI, String JavaDoc localName) {
855         if (namespaceURIMap == null) {
856             return;
857         }
858         namespaceURI = ((namespaceURI == null)? "" : namespaceURI);
859         HashMap JavaDoc localNameMap = (HashMap JavaDoc) namespaceURIMap.get(namespaceURI);
860         if (localNameMap != null) {
861             localNameMap.remove(localName);
862             if (localNameMap.isEmpty()) {
863                 namespaceURIMap.remove(namespaceURI);
864                 if (namespaceURIMap.isEmpty()) {
865                     namespaceURIMap = null;
866                 }
867             }
868         }
869     }
870
871     // dynamic support ////////////////////////////////////////////////////////
872

873     /**
874      * The list of all EventListener attached by bridges that need to
875      * be removed on a dispose() call.
876      */

877     protected Set JavaDoc eventListenerSet = new HashSet JavaDoc();
878
879     /**
880      * The DOM EventListener to receive 'DOMCharacterDataModified' event.
881      */

882     protected EventListener JavaDoc domCharacterDataModifiedListener;
883
884     /**
885      * The DOM EventListener to receive 'DOMAttrModified' event.
886      */

887     protected EventListener JavaDoc domAttrModifiedEventListener;
888
889     /**
890      * The DOM EventListener to receive 'DOMNodeInserted' event.
891      */

892     protected EventListener JavaDoc domNodeInsertedEventListener;
893
894     /**
895      * The DOM EventListener to receive 'DOMNodeRemoved' event.
896      */

897     protected EventListener JavaDoc domNodeRemovedEventListener;
898
899     /**
900      * The CSSEngine listener to receive CSSEngineEvent.
901      */

902     protected CSSEngineListener cssPropertiesChangedListener;
903
904     /**
905      * The EventListener that is responsible of managing DOM focus event.
906      */

907     protected FocusManager focusManager;
908
909     /**
910      * Manages cursors and performs caching when appropriate
911      */

912     protected CursorManager cursorManager = new CursorManager(this);
913
914     /**
915      * Adds EventListeners to the input document to handle the cursor
916      * property.
917      * This is not done in the addDOMListeners method because
918      * addDOMListeners is only used for dynamic content whereas
919      * cursor support is provided for all content.
920      * Also note that it is very important that the listeners be
921      * registered for the capture phase as the 'default' behavior
922      * for cursors is handled by the BridgeContext during the
923      * capture phase and the 'custom' behavior (handling of 'auto'
924      * on anchors, for example), is handled during the bubling phase.
925      */

926     public void addUIEventListeners(Document doc) {
927         EventTarget JavaDoc evtTarget = (EventTarget JavaDoc)doc.getDocumentElement();
928
929         DOMMouseOverEventListener domMouseOverListener =
930             new DOMMouseOverEventListener();
931         evtTarget.addEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
932                                    domMouseOverListener,
933                                    true);
934         storeEventListener(evtTarget, SVGConstants.SVG_EVENT_MOUSEOVER,
935                            domMouseOverListener, true);
936
937         DOMMouseOutEventListener domMouseOutListener =
938             new DOMMouseOutEventListener();
939         evtTarget.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
940                                    domMouseOutListener,
941                                    true);
942         storeEventListener(evtTarget, SVGConstants.SVG_EVENT_MOUSEOUT,
943                            domMouseOutListener, true);
944
945     }
946
947
948     public void removeUIEventListeners(Document doc) {
949         EventTarget JavaDoc evtTarget = (EventTarget JavaDoc)doc.getDocumentElement();
950         synchronized (eventListenerSet) {
951             Iterator JavaDoc i = eventListenerSet.iterator();
952             while (i.hasNext()) {
953                 EventListenerMememto elm = (EventListenerMememto)i.next();
954                 EventTarget JavaDoc et = elm.getTarget();
955                 if (et == evtTarget) {
956                     EventListener JavaDoc el = elm.getListener();
957                     boolean uc = elm.getUseCapture();
958                     String JavaDoc t = elm.getEventType();
959                     if ((et == null) || (el == null) || (t == null))
960                         continue;
961                     et.removeEventListener(t, el, uc);
962                 }
963             }
964         }
965         
966     }
967
968     /**
969      * Adds EventListeners to the DOM and CSSEngineListener to the
970      * CSSEngine to handle any modifications on the DOM tree or style
971      * properties and update the GVT tree in response.
972      */

973     public void addDOMListeners() {
974         EventTarget JavaDoc evtTarget = (EventTarget JavaDoc)document;
975
976         domAttrModifiedEventListener = new DOMAttrModifiedEventListener();
977         evtTarget.addEventListener("DOMAttrModified",
978                                    domAttrModifiedEventListener,
979                                    true);
980
981         domNodeInsertedEventListener = new DOMNodeInsertedEventListener();
982         evtTarget.addEventListener("DOMNodeInserted",
983                                    domNodeInsertedEventListener,
984                                    true);
985
986         domNodeRemovedEventListener = new DOMNodeRemovedEventListener();
987         evtTarget.addEventListener("DOMNodeRemoved",
988                                    domNodeRemovedEventListener,
989                                    true);
990
991         domCharacterDataModifiedListener =
992             new DOMCharacterDataModifiedListener();
993         evtTarget.addEventListener("DOMCharacterDataModified",
994                                    domCharacterDataModifiedListener,
995                                    true);
996
997
998         focusManager = new FocusManager(document);
999
1000        SVGOMDocument svgDocument = (SVGOMDocument)document;
1001        CSSEngine cssEngine = svgDocument.getCSSEngine();
1002        cssPropertiesChangedListener = new CSSPropertiesChangedListener();
1003        cssEngine.addCSSEngineListener(cssPropertiesChangedListener);
1004    }
1005
1006    /**
1007     * Adds to the eventListenerSet the specified event listener
1008     * registration.
1009     */

1010    protected void storeEventListener(EventTarget JavaDoc t,
1011                                      String JavaDoc s,
1012                                      EventListener JavaDoc l,
1013                                      boolean b) {
1014        synchronized (eventListenerSet) {
1015            eventListenerSet.add(new EventListenerMememto(t, s, l, b, this));
1016        }
1017    }
1018
1019    public static class SoftReferenceMememto
1020        extends CleanerThread.SoftReferenceCleared {
1021        Object JavaDoc mememto;
1022        Set JavaDoc set;
1023        // String refStr;
1024
SoftReferenceMememto(Object JavaDoc ref, Object JavaDoc mememto, Set JavaDoc set) {
1025            super(ref);
1026            // refStr = ref.toString();
1027
this.mememto = mememto;
1028            this.set = set;
1029        }
1030
1031        public void cleared() {
1032            synchronized (set) {
1033                // System.err.println("SRClear: " + refStr);
1034
set.remove(mememto);
1035                mememto = null;
1036                set = null;
1037            }
1038        }
1039    }
1040
1041    /**
1042     * A class used to store an EventListener added to the DOM.
1043     */

1044    protected static class EventListenerMememto {
1045
1046        public SoftReference JavaDoc target; // Soft ref to EventTarget
1047
public SoftReference JavaDoc listener; // Soft ref to EventListener
1048
public boolean useCapture;
1049        public String JavaDoc eventType;
1050
1051        public EventListenerMememto(EventTarget JavaDoc t,
1052                                    String JavaDoc s,
1053                                    EventListener JavaDoc l,
1054                                    boolean b,
1055                                    BridgeContext ctx) {
1056            Set JavaDoc set = ctx.eventListenerSet;
1057            target = new SoftReferenceMememto(t, this, set);
1058            listener = new SoftReferenceMememto(l, this, set);
1059            eventType = s;
1060            useCapture = b;
1061        }
1062
1063        public EventListener JavaDoc getListener() {
1064            return (EventListener JavaDoc)listener.get();
1065        }
1066        public EventTarget JavaDoc getTarget() {
1067            return (EventTarget JavaDoc)target.get();
1068        }
1069        public boolean getUseCapture() {
1070            return useCapture;
1071        }
1072        public String JavaDoc getEventType() {
1073            return eventType;
1074        }
1075    }
1076
1077
1078    /**
1079     * Disposes this BridgeContext.
1080     */

1081    public void dispose() {
1082
1083        synchronized (eventListenerSet) {
1084        // remove all listeners added by Bridges
1085
Iterator JavaDoc iter = eventListenerSet.iterator();
1086        while (iter.hasNext()) {
1087            EventListenerMememto m = (EventListenerMememto)iter.next();
1088            EventTarget JavaDoc et = m.getTarget();
1089            EventListener JavaDoc el = m.getListener();
1090            boolean uc = m.getUseCapture();
1091            String JavaDoc t = m.getEventType();
1092            if ((et == null) || (el == null) || (t == null))
1093                continue;
1094            et.removeEventListener(t, el, uc);
1095            }
1096        }
1097
1098        if (document != null) {
1099            EventTarget JavaDoc evtTarget = (EventTarget JavaDoc)document;
1100
1101            evtTarget.removeEventListener("DOMAttrModified",
1102                                          domAttrModifiedEventListener,
1103                                          true);
1104            evtTarget.removeEventListener("DOMNodeInserted",
1105                                          domNodeInsertedEventListener,
1106                                          true);
1107            evtTarget.removeEventListener("DOMNodeRemoved",
1108                                          domNodeRemovedEventListener,
1109                                          true);
1110            evtTarget.removeEventListener("DOMCharacterDataModified",
1111                                          domCharacterDataModifiedListener,
1112                                          true);
1113            
1114            SVGOMDocument svgDocument = (SVGOMDocument)document;
1115            CSSEngine cssEngine = svgDocument.getCSSEngine();
1116            if (cssEngine != null) {
1117                cssEngine.removeCSSEngineListener
1118                    (cssPropertiesChangedListener);
1119                cssEngine.dispose();
1120                svgDocument.setCSSEngine(null);
1121            }
1122        }
1123        Iterator JavaDoc iter = interpreterMap.values().iterator();
1124        while (iter.hasNext()) {
1125            Interpreter interpreter = (Interpreter)iter.next();
1126            if (interpreter != null)
1127                interpreter.dispose();
1128        }
1129        interpreterMap.clear();
1130
1131        if (focusManager != null) {
1132            focusManager.dispose();
1133        }
1134    }
1135
1136    /**
1137     * Returns the SVGContext associated to the specified Node or null if any.
1138     */

1139    protected static SVGContext getSVGContext(Node node) {
1140        if (node instanceof SVGOMElement) {
1141            return ((SVGOMElement)node).getSVGContext();
1142        } else {
1143            return null;
1144        }
1145    }
1146
1147    /**
1148     * Returns the SVGContext associated to the specified Node or null if any.
1149     */

1150    protected static BridgeUpdateHandler getBridgeUpdateHandler(Node node) {
1151        SVGContext ctx = getSVGContext(node);
1152        return (ctx == null) ? null : (BridgeUpdateHandler)ctx;
1153    }
1154
1155    /**
1156     * The DOM EventListener invoked when an attribute is modified.
1157     */

1158    protected class DOMAttrModifiedEventListener implements EventListener JavaDoc {
1159
1160        /**
1161         * Handles 'DOMAttrModified' event type.
1162         */

1163        public void handleEvent(Event evt) {
1164            Node node = (Node)evt.getTarget();
1165            BridgeUpdateHandler h = getBridgeUpdateHandler(node);
1166            if (h != null) {
1167                try {
1168                    h.handleDOMAttrModifiedEvent((MutationEvent JavaDoc)evt);
1169                } catch (Exception JavaDoc e) {
1170                    userAgent.displayError(e);
1171                }
1172            }
1173        }
1174    }
1175
1176    /**
1177     * The DOM EventListener invoked when the mouse exits an element
1178     */

1179    protected class DOMMouseOutEventListener implements EventListener JavaDoc {
1180        public void handleEvent(Event evt) {
1181            MouseEvent JavaDoc me = (MouseEvent JavaDoc)evt;
1182            Element newTarget = (Element)me.getRelatedTarget();
1183            Cursor JavaDoc cursor = CursorManager.DEFAULT_CURSOR;
1184            if (newTarget != null)
1185                cursor = CSSUtilities.convertCursor
1186                    (newTarget, BridgeContext.this);
1187            if (cursor == null)
1188                cursor = CursorManager.DEFAULT_CURSOR;
1189
1190            userAgent.setSVGCursor(cursor);
1191        }
1192    }
1193
1194
1195    /**
1196     * The DOM EventListener invoked when the mouse mouves over a new
1197     * element.
1198     *
1199     * Here is how cursors are handled:
1200     *
1201     */

1202    protected class DOMMouseOverEventListener implements EventListener JavaDoc {
1203        /**
1204         * Handles 'mouseover' MouseEvent event type.
1205         */

1206        public void handleEvent(Event evt) {
1207            Element target = (Element)evt.getTarget();
1208            Cursor JavaDoc cursor = CSSUtilities.convertCursor(target, BridgeContext.this);
1209            
1210            if (cursor != null) {
1211                userAgent.setSVGCursor(cursor);
1212            }
1213        }
1214    }
1215    
1216    /**
1217     * The DOM EventListener invoked when a node is added.
1218     */

1219    protected class DOMNodeInsertedEventListener implements EventListener JavaDoc {
1220
1221        /**
1222         * Handles 'DOMNodeInserted' event type.
1223         */

1224        public void handleEvent(Event evt) {
1225            MutationEvent JavaDoc me = (MutationEvent JavaDoc)evt;
1226            BridgeUpdateHandler h =
1227                getBridgeUpdateHandler(me.getRelatedNode());
1228            if (h != null) {
1229                try {
1230                    h.handleDOMNodeInsertedEvent(me);
1231                } catch (InterruptedBridgeException ibe) {
1232                    /* do nothing */
1233                } catch (Exception JavaDoc e) {
1234                    userAgent.displayError(e);
1235                }
1236            }
1237        }
1238    }
1239
1240    /**
1241     * The DOM EventListener invoked when a node is removed.
1242     */

1243    protected class DOMNodeRemovedEventListener implements EventListener JavaDoc {
1244
1245        /**
1246         * Handles 'DOMNodeRemoved' event type.
1247         */

1248        public void handleEvent(Event evt) {
1249            Node node = (Node)evt.getTarget();
1250            BridgeUpdateHandler h = getBridgeUpdateHandler(node);
1251            if (h != null) {
1252                try {
1253                    h.handleDOMNodeRemovedEvent((MutationEvent JavaDoc)evt);
1254                } catch (Exception JavaDoc e) {
1255                    userAgent.displayError(e);
1256                }
1257            }
1258        }
1259    }
1260
1261    /**
1262     * The DOM EventListener invoked when a character data is changed.
1263     */

1264    protected class DOMCharacterDataModifiedListener implements EventListener JavaDoc {
1265
1266        /**
1267         * Handles 'DOMNodeRemoved' event type.
1268         */

1269        public void handleEvent(Event evt) {
1270            Node node = (Node)evt.getTarget();
1271            while (node != null && !(node instanceof SVGOMElement)) {
1272                node = node.getParentNode();
1273            }
1274            BridgeUpdateHandler h = getBridgeUpdateHandler(node);
1275            if (h != null) {
1276                try {
1277                    h.handleDOMCharacterDataModified((MutationEvent JavaDoc)evt);
1278                } catch (Exception JavaDoc e) {
1279                    userAgent.displayError(e);
1280                }
1281            }
1282        }
1283    }
1284
1285    /**
1286     * The CSSEngineListener invoked when CSS properties are modified
1287     * on a particular element.
1288     */

1289    protected class CSSPropertiesChangedListener implements CSSEngineListener {
1290
1291        /**
1292         * Handles CSSEngineEvent that describes the CSS properties
1293         * that have changed on a particular element.
1294         */

1295        public void propertiesChanged(CSSEngineEvent evt) {
1296            Element elem = evt.getElement();
1297            SVGContext ctx = getSVGContext(elem);
1298            if (ctx == null) {
1299                GraphicsNode pgn = getGraphicsNode
1300                    ((Element)elem.getParentNode());
1301                if ((pgn == null) || !(pgn instanceof CompositeGraphicsNode)) {
1302                    // Something changed in this element but we really don't
1303
// care since it's parent isn't displayed either.
1304
return;
1305                }
1306                CompositeGraphicsNode parent = (CompositeGraphicsNode)pgn;
1307                // Check if 'display' changed on this element.
1308

1309                int [] properties = evt.getProperties();
1310                for (int i=0; i < properties.length; ++i) {
1311                    if (properties[i] == SVGCSSEngine.DISPLAY_INDEX) {
1312                        if (!CSSUtilities.convertDisplay(elem)) {
1313                            // (Still) Not displayed
1314
break;
1315                        }
1316                        // build the graphics node
1317
GVTBuilder builder = getGVTBuilder();
1318                        GraphicsNode childNode = builder.build
1319                            (BridgeContext.this, elem);
1320                        if (childNode == null) {
1321                            // the added element is not a graphic element?
1322
break;
1323                        }
1324                        int idx = -1;
1325                        for(Node ps = elem.getPreviousSibling(); ps != null;
1326                            ps = ps.getPreviousSibling()) {
1327                            if (ps.getNodeType() != Node.ELEMENT_NODE)
1328                                continue;
1329                            Element pse = (Element)ps;
1330                            GraphicsNode gn = getGraphicsNode(pse);
1331                            if (gn == null)
1332                                continue;
1333                            idx = parent.indexOf(gn);
1334                            if (idx == -1)
1335                                continue;
1336                            break;
1337                        }
1338                        // insert after prevSibling, if
1339
// it was -1 this becomes 0 (first slot)
1340
idx++;
1341                        parent.add(idx, childNode);
1342                        break;
1343                    }
1344                }
1345            } if (ctx != null && (ctx instanceof BridgeUpdateHandler)) {
1346                ((BridgeUpdateHandler)ctx).handleCSSEngineEvent(evt);
1347            }
1348        }
1349    }
1350
1351    // CSS context ////////////////////////////////////////////////////////////
1352

1353    /**
1354     * Returns the Value corresponding to the given system color.
1355     */

1356    public Value getSystemColor(String JavaDoc ident) {
1357        return SystemColorSupport.getSystemColor(ident);
1358    }
1359
1360    /**
1361     * Returns the value corresponding to the default font.
1362     */

1363    public Value getDefaultFontFamily() {
1364        // No cache needed since the default font family is asked only
1365
// one time on the root element (only if it does not have its
1366
// own font-family).
1367
SVGOMDocument doc = (SVGOMDocument)document;
1368        SVGStylableElement root = (SVGStylableElement)doc.getRootElement();
1369        String JavaDoc str = userAgent.getDefaultFontFamily();
1370        return doc.getCSSEngine().parsePropertyValue
1371            (root,SVGConstants.CSS_FONT_FAMILY_PROPERTY, str);
1372    }
1373
1374    /**
1375     * Returns a lighter font-weight.
1376     */

1377    public float getLighterFontWeight(float f) {
1378        return userAgent.getLighterFontWeight(f);
1379    }
1380
1381    /**
1382     * Returns a bolder font-weight.
1383     */

1384    public float getBolderFontWeight(float f) {
1385        return userAgent.getBolderFontWeight(f);
1386    }
1387
1388    /**
1389     * Returns the size of a px CSS unit in millimeters.
1390     */

1391    public float getPixelUnitToMillimeter() {
1392        return userAgent.getPixelUnitToMillimeter();
1393    }
1394
1395    /**
1396     * Returns the size of a px CSS unit in millimeters.
1397     * This will be removed after next release.
1398     * @see #getPixelUnitToMillimeter()
1399     */

1400    public float getPixelToMillimeter() {
1401        return getPixelUnitToMillimeter();
1402            
1403    }
1404
1405    /**
1406     * Returns the medium font size.
1407     */

1408    public float getMediumFontSize() {
1409        return userAgent.getMediumFontSize();
1410    }
1411
1412    /**
1413     * Returns the width of the block which directly contains the
1414     * given element.
1415     */

1416    public float getBlockWidth(Element elt) {
1417        return getViewport(elt).getWidth();
1418    }
1419
1420    /**
1421     * Returns the height of the block which directly contains the
1422     * given element.
1423     */

1424    public float getBlockHeight(Element elt) {
1425        return getViewport(elt).getHeight();
1426    }
1427
1428    /**
1429     * This method throws a SecurityException if the resource
1430     * found at url and referenced from docURL
1431     * should not be loaded.
1432     *
1433     * This is a convenience method to call checkLoadExternalResource
1434     * on the ExternalResourceSecurity strategy returned by
1435     * getExternalResourceSecurity.
1436     *
1437     * @param resourceURL url for the script, as defined in
1438     * the resource's xlink:href attribute. If that
1439     * attribute was empty, then this parameter should
1440     * be null
1441     * @param docURL url for the document into which the
1442     * resource was found.
1443     */

1444    public void
1445        checkLoadExternalResource(ParsedURL resourceURL,
1446                                  ParsedURL docURL) throws SecurityException JavaDoc {
1447        userAgent.checkLoadExternalResource(resourceURL,
1448                                            docURL);
1449    }
1450
1451
1452    /**
1453     * Tells whether the given SVG document is dynamic.
1454     */

1455    public boolean isDynamicDocument(Document doc) {
1456        return BaseScriptingEnvironment.isDynamicDocument(this, doc);
1457    }
1458    
1459    /**
1460     * Tells whether the given SVG document is Interactive.
1461     * We say it is, if it has any &lt;title>, &lt;desc>, or &lt;a> elements,
1462     * of if the 'cursor' property is anything but Auto on any element.
1463     */

1464    public boolean isInteractiveDocument(Document doc) {
1465        
1466        Element root = ((SVGDocument)doc).getRootElement();
1467        if (!SVGConstants.SVG_NAMESPACE_URI.equals(root.getNamespaceURI()))
1468            return false;
1469
1470        return checkInteractiveElement(root);
1471    }
1472
1473    /**
1474     * used by isInteractiveDocument to check if document
1475     * contains any 'interactive' elements.
1476     */

1477    public boolean checkInteractiveElement(Element e) {
1478        return checkInteractiveElement
1479            ((SVGDocument)e.getOwnerDocument(), e);
1480    }
1481
1482    /**
1483     * used by isInteractiveDocument to check if document
1484     * contains any 'interactive' elements.
1485     */

1486    public boolean checkInteractiveElement(SVGDocument doc,
1487                                           Element e) {
1488        String JavaDoc tag = e.getLocalName();
1489        
1490        // Check if it's one of our important element.
1491
if (SVGConstants.SVG_A_TAG.equals(tag))
1492            return true;
1493
1494        // This is a bit of a hack but don't count
1495
// title and desc as children of root SVG since
1496
// we don't show tool tips for them anyways.
1497
if (SVGConstants.SVG_TITLE_TAG.equals(tag)) {
1498            return (e.getParentNode() != doc.getRootElement());
1499        }
1500        if (SVGConstants.SVG_DESC_TAG.equals(tag)) {
1501            return (e.getParentNode() != doc.getRootElement());
1502        }
1503        if (SVGConstants.SVG_CURSOR_TAG.equals(tag))
1504            return true;
1505
1506        // I am well aware that this is not 100% accurate but it's
1507
// the best I can do w/o booting the CSSEngine.
1508
if (e.getAttribute(CSSConstants.CSS_CURSOR_PROPERTY).length() >0)
1509            return true;
1510
1511        /* We would like to do this but the CSS Engine isn't setup when
1512           we want to do this.
1513           
1514        // Check if cursor property is set to something other than 'auto'.
1515        Value cursorValue = CSSUtilities.getComputedStyle
1516            (e, SVGCSSEngine.CURSOR_INDEX);
1517        if ((cursorValue != null) &&
1518            (cursorValue.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) &&
1519            (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) &&
1520            (SVGConstants.SVG_AUTO_VALUE.equals(cursorValue.getStringValue())))
1521            return true;
1522        */

1523
1524        // Check all the child elements for any of the above.
1525
final String JavaDoc svg_ns = SVGConstants.SVG_NAMESPACE_URI;
1526        for (Node n = e.getFirstChild();
1527             n != null;
1528             n = n.getNextSibling()) {
1529            if (n.getNodeType() == Node.ELEMENT_NODE) {
1530                Element child = (Element)n;
1531                if (svg_ns.equals(child.getNamespaceURI()))
1532                    if (checkInteractiveElement(child))
1533                        return true;
1534            }
1535        }
1536        return false;
1537    }
1538    
1539
1540    // bridge extensions support //////////////////////////////////////////////
1541

1542    protected List JavaDoc extensions = null;
1543
1544    /**
1545     * Registers the bridges to handle SVG 1.0 elements.
1546     */

1547    public void registerSVGBridges() {
1548        UserAgent ua = getUserAgent();
1549        List JavaDoc ext = getBridgeExtensions(document);
1550        Iterator JavaDoc iter = ext.iterator();
1551
1552        while(iter.hasNext()) {
1553            BridgeExtension be = (BridgeExtension)iter.next();
1554            be.registerTags(this);
1555            ua.registerExtension(be);
1556        }
1557    }
1558
1559    public List JavaDoc getBridgeExtensions(Document doc) {
1560        Element root = ((SVGOMDocument)doc).getRootElement();
1561        String JavaDoc ver = root.getAttributeNS
1562            (null, SVGConstants.SVG_VERSION_ATTRIBUTE);
1563        BridgeExtension svgBE;
1564        if ((ver.length()==0) || ver.equals("1.0") || ver.equals("1.1"))
1565            svgBE = new SVGBridgeExtension();
1566        else
1567            svgBE = new SVG12BridgeExtension();
1568
1569        float priority = svgBE.getPriority();
1570        extensions = new LinkedList JavaDoc(getGlobalBridgeExtensions());
1571
1572        ListIterator JavaDoc li = extensions.listIterator();
1573        for (;;) {
1574            if (!li.hasNext()) {
1575                li.add(svgBE);
1576                break;
1577            }
1578            BridgeExtension lbe = (BridgeExtension)li.next();
1579            if (lbe.getPriority() > priority) {
1580                li.previous();
1581                li.add(svgBE);
1582                break;
1583            }
1584        }
1585
1586        return extensions;
1587    }
1588
1589    /**
1590     * Returns the extensions supported by this bridge context.
1591     */

1592    protected static List JavaDoc globalExtensions = null;
1593
1594    public synchronized static List JavaDoc getGlobalBridgeExtensions() {
1595        if (globalExtensions != null) {
1596            return globalExtensions;
1597        }
1598        globalExtensions = new LinkedList JavaDoc();
1599
1600        Iterator JavaDoc iter = Service.providers(BridgeExtension.class);
1601
1602        while (iter.hasNext()) {
1603            BridgeExtension be = (BridgeExtension)iter.next();
1604            float priority = be.getPriority();
1605            ListIterator JavaDoc li = globalExtensions.listIterator();
1606            for (;;) {
1607                if (!li.hasNext()) {
1608                    li.add(be);
1609                    break;
1610                }
1611                BridgeExtension lbe = (BridgeExtension)li.next();
1612                if (lbe.getPriority() > priority) {
1613                    li.previous();
1614                    li.add(be);
1615                    break;
1616                }
1617            }
1618        }
1619        return globalExtensions;
1620    }
1621
1622    public static class CSSEngineUserAgentWrapper implements CSSEngineUserAgent {
1623        UserAgent ua;
1624        CSSEngineUserAgentWrapper(UserAgent ua) {
1625            this.ua = ua;
1626        }
1627
1628        /**
1629         * Displays an error resulting from the specified Exception.
1630         */

1631        public void displayError(Exception JavaDoc ex) { ua.displayError(ex); }
1632
1633        /**
1634         * Displays a message in the User Agent interface.
1635         */

1636        public void displayMessage(String JavaDoc message) { ua.displayMessage(message); }
1637    }
1638
1639}
1640
1641
Popular Tags