KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > swing > svg > JSVGComponent


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.swing.svg;
19
20 import java.awt.Cursor JavaDoc;
21 import java.awt.Dimension JavaDoc;
22 import java.awt.EventQueue JavaDoc;
23 import java.awt.Point JavaDoc;
24 import java.awt.Rectangle JavaDoc;
25 import java.awt.Shape JavaDoc;
26 import java.awt.event.ComponentAdapter JavaDoc;
27 import java.awt.event.ComponentEvent JavaDoc;
28 import java.awt.event.KeyEvent JavaDoc;
29 import java.awt.event.MouseEvent JavaDoc;
30 import java.awt.geom.AffineTransform JavaDoc;
31 import java.awt.geom.Dimension2D JavaDoc;
32 import java.awt.geom.NoninvertibleTransformException JavaDoc;
33 import java.awt.geom.Point2D JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.LinkedList JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Map JavaDoc;
41 import java.util.Set JavaDoc;
42
43 import javax.swing.JOptionPane JavaDoc;
44
45 import org.apache.batik.bridge.BridgeContext;
46 import org.apache.batik.bridge.BridgeException;
47 import org.apache.batik.bridge.BridgeExtension;
48 import org.apache.batik.bridge.DefaultScriptSecurity;
49 import org.apache.batik.bridge.DocumentLoader;
50 import org.apache.batik.bridge.ExternalResourceSecurity;
51 import org.apache.batik.bridge.RelaxedExternalResourceSecurity;
52 import org.apache.batik.bridge.ScriptSecurity;
53 import org.apache.batik.bridge.UpdateManager;
54 import org.apache.batik.bridge.UpdateManagerAdapter;
55 import org.apache.batik.bridge.UpdateManagerEvent;
56 import org.apache.batik.bridge.UpdateManagerListener;
57 import org.apache.batik.bridge.UserAgent;
58 import org.apache.batik.bridge.ViewBox;
59 import org.apache.batik.dom.svg.SVGDOMImplementation;
60 import org.apache.batik.dom.util.DOMUtilities;
61 import org.apache.batik.dom.util.XLinkSupport;
62 import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
63 import org.apache.batik.gvt.CanvasGraphicsNode;
64 import org.apache.batik.gvt.CompositeGraphicsNode;
65 import org.apache.batik.gvt.GraphicsNode;
66 import org.apache.batik.gvt.event.EventDispatcher;
67 import org.apache.batik.gvt.text.Mark;
68 import org.apache.batik.gvt.renderer.ImageRenderer;
69 import org.apache.batik.swing.gvt.GVTTreeRenderer;
70 import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
71 import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
72 import org.apache.batik.swing.gvt.JGVTComponent;
73 import org.apache.batik.swing.gvt.JGVTComponentListener;
74 import org.apache.batik.util.ParsedURL;
75 import org.apache.batik.util.RunnableQueue;
76 import org.apache.batik.util.SVGConstants;
77 import org.apache.batik.util.XMLResourceDescriptor;
78 import org.w3c.dom.Document JavaDoc;
79 import org.w3c.dom.DOMImplementation JavaDoc;
80 import org.w3c.dom.Element JavaDoc;
81 import org.w3c.dom.svg.SVGAElement;
82 import org.w3c.dom.svg.SVGDocument;
83 import org.w3c.dom.svg.SVGSVGElement;
84
85 /**
86  * This class represents a swing component that can display SVG documents. This
87  * component also lets you translate, zoom and rotate the document being
88  * displayed. This is the fundamental class for rendering SVG documents in a
89  * swing application.
90  *
91  * <h2>Rendering Process</h2>
92  *
93  * <p>The rendering process can be broken down into five phases. Not all of
94  * those steps are required - depending on the method used to specify the SVG
95  * document to display, but basically the steps in the rendering process
96  * are:</p>
97  *
98  * <ol>
99  *
100  * <li><b>Building a DOM tree</b>
101  *
102  * <blockquote>If the <tt>{@link #loadSVGDocument(String)}</tt> method is used,
103  * the SVG file is parsed and an SVG DOM Tree is built.</blockquote></li>
104  *
105  * <li><b>Building a GVT tree</b>
106  *
107  * <blockquote>Once an SVGDocument is created (using the step 1 or if the
108  * <tt>{@link #setSVGDocument(SVGDocument)}</tt> method has been used) - a GVT
109  * tree is constructed. The GVT tree is the data structure used internally to
110  * render an SVG document. see the <tt>{@link org.apache.batik.gvt}
111  * package.</tt></blockquote></li>
112  *
113  * <li><b>Executing the SVGLoad event handlers</b>
114  *
115  * <blockquote>
116  * If the document is dynamic, the scripts are initialized and the
117  * SVGLoad event is dispatched before the initial rendering.
118  * </blockquote></li>
119  *
120  * <li><b>Rendering the GVT tree</b>
121  *
122  * <blockquote>Then the GVT tree is rendered. see the <tt>{@link
123  * org.apache.batik.gvt.renderer}</tt> package.</blockquote></li>
124  *
125  * <li><b>Running the document</b>
126  *
127  * <blockquote>
128  * If the document is dynamic, the update threads are started.
129  * </blockquote></li>
130  *
131  * </ol>
132  *
133  * <p>Those steps are performed in a separate thread. To be notified to what
134  * happens and eventually perform some operations - such as resizing the window
135  * to the size of the document or get the SVGDocument built via a URI, five
136  * different listeners are provided (one per step):
137  * <tt>{@link SVGDocumentLoaderListener}</tt>,
138  * <tt>{@link GVTTreeBuilderListener}</tt>,
139  * <tt>{@link SVGLoadEventDispatcherListener}</tt>,
140  * <tt>{@link org.apache.batik.swing.gvt.GVTTreeRendererListener}</tt>,
141  * <tt>{@link org.apache.batik.bridge.UpdateManagerListener}</tt>.</p>
142  *
143  * <p>Each listener has methods to be notified of the start of a phase,
144  * and methods to be notified of the end of a phase.
145  * A phase cannot start before the preceding has finished.</p>
146  *
147  * <p>The following example shows how you can get the size of an SVG
148  * document. Note that due to how SVG is designed (units, percentages...), the
149  * size of an SVG document can be known only once the SVGDocument has been
150  * analyzed (ie. the GVT tree has been constructed).</p>
151  *
152  * <pre>
153  * final JSVGComponent svgComp = new JSVGComponent();
154  * svgComp.loadSVGDocument("foo.svg");
155  * svgComp.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
156  * public void gvtBuildCompleted(GVTTreeBuilderEvent evt) {
157  * Dimension2D size = svgComp.getSVGDocumentSize();
158  * // ...
159  * }
160  * });
161  * </pre>
162  *
163  * <p>The second example shows how you can access to the DOM tree when a URI has
164  * been used to display an SVG document.
165  *
166  * <pre>
167  * final JSVGComponent svgComp = new JSVGComponent();
168  * svgComp.loadSVGDocument("foo.svg");
169  * svgComp.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {
170  * public void documentLoadingCompleted(SVGDocumentLoaderEvent evt) {
171  * SVGDocument svgDoc = svgComp.getSVGDocument();
172  * //...
173  * }
174  * });
175  * </pre>
176  *
177  * <p>Conformed to the <a HREF=
178  * "http://java.sun.com/docs/books/tutorial/uiswing/overview/threads.html">
179  * single thread rule of swing</a>, the listeners are executed in the swing
180  * thread. The sequence of the method calls for a particular listener and
181  * the order of the listeners themselves are <em>guaranteed</em>.</p>
182  *
183  * <h2>User Agent</h2>
184  *
185  * <p>The <tt>JSVGComponent</tt> can pick up some informations to a user
186  * agent. The <tt>{@link SVGUserAgent}</tt> provides a way to control the
187  * resolution used to display an SVG document (controling the pixel to
188  * millimeter conversion factor), perform an operation in respond to a click on
189  * an hyperlink, control the default language to use, or specify a user
190  * stylesheet, or how to display errors when an error occured while
191  * building/rendering a document (invalid XML file, missing attributes...).</p>
192  *
193  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
194  * @version $Id: JSVGComponent.java,v 1.104 2005/03/29 10:48:02 deweese Exp $
195  */

196 public class JSVGComponent extends JGVTComponent {
197
198     /**
199      * Means that the component must auto detect whether
200      * the current document is static or dynamic.
201      */

202     public final static int AUTODETECT = 0;
203
204     /**
205      * Means that all document must be considered as dynamic.
206      *
207      * Indicates that all DOM listeners should be registered. This supports
208      * 'interactivity' (anchors and cursors), as well as DOM modifications
209      * listeners to update the GVT rendering tree.
210      */

211     public final static int ALWAYS_DYNAMIC = 1;
212
213     /**
214      * Means that all document must be considered as static.
215      *
216      * Indicates that no DOM listeners should be registered.
217      * In this case the generated GVT tree should be totally
218      * independent of the DOM tree (in practice text holds
219      * references to the source text elements for font resolution).
220      */

221     public final static int ALWAYS_STATIC = 2;
222
223     /**
224      * Means that all document must be considered as interactive.
225      *
226      * Indicates that DOM listeners should be registered to support,
227      * 'interactivity' this includes anchors and cursors, but does not
228      * include support for DOM modifications.
229      */

230     public final static int ALWAYS_INTERACTIVE = 3;
231
232     /**
233      * The document loader.
234      */

235     protected SVGDocumentLoader documentLoader;
236
237     /**
238      * The next document loader to run.
239      */

240     protected SVGDocumentLoader nextDocumentLoader;
241
242     /**
243      * The concrete bridge document loader.
244      */

245     protected DocumentLoader loader;
246
247     /**
248      * The GVT tree builder.
249      */

250     protected GVTTreeBuilder gvtTreeBuilder;
251
252     /**
253      * The next GVT tree builder to run.
254      */

255     protected GVTTreeBuilder nextGVTTreeBuilder;
256
257     /**
258      * The SVGLoadEventDispatcher.
259      */

260     protected SVGLoadEventDispatcher svgLoadEventDispatcher;
261
262     /**
263      * The update manager.
264      */

265     protected UpdateManager updateManager;
266
267     /**
268      * The next update manager.
269      */

270     protected UpdateManager nextUpdateManager;
271
272     /**
273      * The current SVG document.
274      */

275     protected SVGDocument svgDocument;
276
277     /**
278      * The document loader listeners.
279      */

280     protected List JavaDoc svgDocumentLoaderListeners = new LinkedList JavaDoc();
281
282     /**
283      * The GVT tree builder listeners.
284      */

285     protected List JavaDoc gvtTreeBuilderListeners = new LinkedList JavaDoc();
286
287     /**
288      * The SVG onload dispatcher listeners.
289      */

290     protected List JavaDoc svgLoadEventDispatcherListeners = new LinkedList JavaDoc();
291
292     /**
293      * The link activation listeners.
294      */

295     protected List JavaDoc linkActivationListeners = new LinkedList JavaDoc();
296
297     /**
298      * The update manager listeners.
299      */

300     protected List JavaDoc updateManagerListeners = new LinkedList JavaDoc();
301
302     /**
303      * The user agent.
304      */

305     protected UserAgent userAgent;
306
307     /**
308      * The SVG user agent.
309      */

310     protected SVGUserAgent svgUserAgent;
311
312     /**
313      * The current bridge context.
314      */

315     protected BridgeContext bridgeContext;
316
317     /**
318      * The current document fragment identifier.
319      */

320     protected String JavaDoc fragmentIdentifier;
321
322     /**
323      * Whether the current document has dynamic features.
324      */

325     protected boolean isDynamicDocument;
326
327     /**
328      * Whether the current document has dynamic features.
329      */

330     protected boolean isInteractiveDocument;
331
332     /**
333      * The document state.
334      */

335     protected int documentState;
336
337     protected Dimension JavaDoc prevComponentSize;
338
339     protected Runnable JavaDoc afterStopRunnable = null;
340
341     protected SVGUpdateOverlay updateOverlay; // = new SVGUpdateOverlay(20, 4);
342

343     protected boolean recenterOnResize = true;
344
345     protected AffineTransform JavaDoc viewingTransform = null;
346
347     /**
348      * Creates a new JSVGComponent.
349      */

350     public JSVGComponent() {
351         this(null, false, false);
352     }
353
354     /**
355      * Creates a new JSVGComponent.
356      * @param ua a SVGUserAgent instance or null.
357      * @param eventsEnabled Whether the GVT tree should be reactive
358      * to mouse and key events.
359      * @param selectableText Whether the text should be selectable.
360      */

361     public JSVGComponent(SVGUserAgent ua, boolean eventsEnabled,
362                          boolean selectableText) {
363         super(eventsEnabled, selectableText);
364
365         svgUserAgent = ua;
366
367         userAgent = new BridgeUserAgentWrapper(createUserAgent());
368
369         addSVGDocumentLoaderListener((SVGListener)listener);
370         addGVTTreeBuilderListener((SVGListener)listener);
371         addSVGLoadEventDispatcherListener((SVGListener)listener);
372         if (updateOverlay != null)
373             getOverlays().add(updateOverlay);
374     }
375
376     public void dispose() {
377         setSVGDocument(null);
378     }
379
380     /**
381      * Indicates if the canvas should recenter the content after
382      * the canvas is resized. If true it will try and keep the
383      * point that was at the center at the center after resize.
384      * Otherwise the upper left corner will be kept at the same point.
385      */

386     public boolean getRecenterOnResize() {
387         return recenterOnResize;
388     }
389     /**
390      * Returns sate of the recenter on resize flag.
391      */

392     public void setRecenterOnResize(boolean recenterOnResize) {
393         this.recenterOnResize = recenterOnResize;
394     }
395
396     /**
397      * Tells whether the component use dynamic features to
398      * process the current document.
399      */

400     public boolean isDynamic() {
401         return isDynamicDocument;
402     }
403
404     /**
405      * Tells whether the component use dynamic features to
406      * process the current document.
407      */

408     public boolean isInteractive() {
409         return isInteractiveDocument;
410     }
411
412     /**
413      * Sets the document state. The given value must be one of
414      * AUTODETECT, ALWAYS_DYNAMIC or ALWAYS_STATIC. This only
415      * effects the loading of subsequent documents, it has no
416      * effect on the currently loaded document.
417      */

418     public void setDocumentState(int state) {
419         documentState = state;
420     }
421
422     /**
423      * Returns the current update manager. The update manager becomes
424      * available after the first rendering completes. You can be
425      * notifed when the rendering completes by registering a
426      * GVTTreeRendererListener with the component and waiting for the
427      * <tt>gvtRenderingCompleted</tt> event.
428      *
429      * An UpdateManager is only created for Dynamic documents. By
430      * default the Canvas attempts to autodetect dynamic documents by
431      * looking for script elements and/or event attributes in the
432      * document, if it does not find these it assumes the document is
433      * static. Callers of this method will almost certainly want to
434      * call setDocumentState(ALWAYS_DYNAMIC) before loading the document
435      * (with setURI, setDocument, setSVGDocument etc.) so that an
436      * UpdateManager is always created (even for apparently static documents).
437      */

438     public UpdateManager getUpdateManager() {
439         if (svgLoadEventDispatcher != null) {
440             return svgLoadEventDispatcher.getUpdateManager();
441         }
442         if (nextUpdateManager != null) {
443             return nextUpdateManager;
444         }
445         return updateManager;
446     }
447
448     /**
449      * Resumes the processing of the current document.
450      */

451     public void resumeProcessing() {
452         if (updateManager != null) {
453             updateManager.resume();
454         }
455     }
456
457     /**
458      * Suspend the processing of the current document.
459      */

460     public void suspendProcessing() {
461         if (updateManager != null) {
462             updateManager.suspend();
463         }
464     }
465
466     /**
467      * Stops the processing of the current document.
468      */

469     public void stopProcessing() {
470         nextDocumentLoader = null;
471         nextGVTTreeBuilder = null;
472
473         if (documentLoader != null) {
474             documentLoader.halt();
475         }
476         if (gvtTreeBuilder != null) {
477             gvtTreeBuilder.halt();
478         }
479         if (svgLoadEventDispatcher != null) {
480             svgLoadEventDispatcher.halt();
481         }
482         if (nextUpdateManager != null) {
483             nextUpdateManager.interrupt();
484             nextUpdateManager = null;
485         }
486         if (updateManager != null) {
487             updateManager.interrupt();
488         }
489         super.stopProcessing();
490     }
491
492     /**
493      * Loads a SVG document from the given URL.
494      * <em>Note: Because the loading is multi-threaded, the current
495      * SVG document is not garanteed to be updated after this method
496      * returns. The only way to be notified a document has been loaded
497      * is to listen to the <tt>SVGDocumentLoaderEvent</tt>s.</em>
498      */

499     public void loadSVGDocument(String JavaDoc url) {
500         String JavaDoc oldURI = null;
501         if (svgDocument != null) {
502             oldURI = svgDocument.getURL();
503         }
504         final ParsedURL newURI = new ParsedURL(oldURI, url);
505
506         stopThenRun(new Runnable JavaDoc() {
507                 public void run() {
508                     String JavaDoc url = newURI.toString();
509                     fragmentIdentifier = newURI.getRef();
510
511                     loader = new DocumentLoader(userAgent);
512                     nextDocumentLoader = new SVGDocumentLoader(url, loader);
513                     nextDocumentLoader.setPriority(Thread.MIN_PRIORITY);
514
515                     Iterator JavaDoc it = svgDocumentLoaderListeners.iterator();
516                     while (it.hasNext()) {
517                         nextDocumentLoader.addSVGDocumentLoaderListener
518                             ((SVGDocumentLoaderListener)it.next());
519                     }
520                     startDocumentLoader();
521                 }
522             });
523     }
524
525     /**
526      * Starts a loading thread.
527      */

528     private void startDocumentLoader() {
529         documentLoader = nextDocumentLoader;
530         nextDocumentLoader = null;
531         documentLoader.start();
532     }
533
534     /**
535      * Sets the Document to display. If the document does not use
536      * Batik's SVG DOM Implemenation it will be cloned into that
537      * implementation. In this case you should use 'getSVGDocument()'
538      * to get the actual DOM that is attached to the rendering interface.
539      *
540      * Note that the prepartation for rendering and the rendering it's
541      * self occur asynchronously so you need to register event handlers
542      * if you want to know when the document is truely displayed.
543      *
544      * Notes for documents that you want to change in Java:
545      * From this point on you may only modify the
546      * the document in the UpdateManager thread @see #getUpdateManager.
547      * In many cases you also need to tell Batik to treat the document
548      * as a dynamic document by calling setDocumentState(ALWAYS_DYNAMIC).
549      */

550     public void setDocument(Document JavaDoc doc) {
551         if ((doc != null) &&
552             !(doc.getImplementation() instanceof SVGDOMImplementation)) {
553             DOMImplementation impl;
554             impl = SVGDOMImplementation.getDOMImplementation();
555             Document JavaDoc d = DOMUtilities.deepCloneDocument(doc, impl);
556             doc = d;
557         }
558         setSVGDocument((SVGDocument)doc);
559     }
560
561     /**
562      * Sets the SVGDocument to display. If the document does not use
563      * Batik's SVG DOM Implemenation it will be cloned into that
564      * implementation. In this case you should use 'getSVGDocument()'
565      * to get the actual DOM that is attached to the rendering
566      * interface.
567      *
568      * Note that the prepartation for rendering and the rendering it's
569      * self occur asynchronously so you need to register event handlers
570      * if you want to know when the document is truely displayed.
571      *
572      * Notes for documents that you want to change in Java.
573      * From this point on you may only modify the
574      * the document in the UpdateManager thread @see #getUpdateManager.
575      * In many cases you also need to tell Batik to treat the document
576      * as a dynamic document by calling setDocumentState(ALWAYS_DYNAMIC).
577      */

578     public void setSVGDocument(SVGDocument doc) {
579         if ((doc != null) &&
580             !(doc.getImplementation() instanceof SVGDOMImplementation)) {
581             DOMImplementation impl;
582             impl = SVGDOMImplementation.getDOMImplementation();
583             Document JavaDoc d = DOMUtilities.deepCloneDocument(doc, impl);
584             doc = (SVGDocument)d;
585         }
586
587         final SVGDocument svgdoc = doc;
588         stopThenRun(new Runnable JavaDoc() {
589                 public void run() {
590                     installSVGDocument(svgdoc);
591                 }
592             });
593     }
594
595     /**
596      * This method calls stop processing waits for all
597      * threads to die then runs the Runnable in the event
598      * queue thread. It returns immediately.
599      */

600     protected void stopThenRun(final Runnable JavaDoc r) {
601         if (afterStopRunnable != null) {
602             // Have it run our new runnable, and not
603
// run the 'old' runnable.
604
afterStopRunnable = r;
605             return;
606         }
607         afterStopRunnable = r;
608
609         stopProcessing();
610
611         if ((documentLoader == null) &&
612             (gvtTreeBuilder == null) &&
613             (gvtTreeRenderer == null) &&
614             (svgLoadEventDispatcher == null) &&
615             (nextUpdateManager == null) &&
616             (updateManager == null)) {
617             Runnable JavaDoc asr = afterStopRunnable;
618             afterStopRunnable = null;
619             asr.run();
620         }
621     }
622
623     /**
624      * This does the real work of installing the SVG Document after
625      * the update manager from the previous document (if any) has been
626      * properly 'shut down'.
627      */

628     protected void installSVGDocument(SVGDocument doc) {
629         svgDocument = doc;
630
631         if (bridgeContext != null) {
632             bridgeContext.dispose();
633             bridgeContext = null;
634         }
635
636         releaseRenderingReferences();
637
638         if (doc == null) {
639             isDynamicDocument = false;
640             isInteractiveDocument = false;
641             disableInteractions = true;
642             initialTransform = new AffineTransform JavaDoc();
643             setRenderingTransform(initialTransform, false);
644             Rectangle JavaDoc vRect = getRenderRect();
645             repaint(vRect.x, vRect.y,
646                     vRect.width, vRect.height);
647             return;
648         }
649
650         bridgeContext = createBridgeContext();
651
652         switch (documentState) {
653         case ALWAYS_STATIC:
654             isDynamicDocument = false;
655             isInteractiveDocument = false;
656             break;
657         case ALWAYS_INTERACTIVE:
658             isDynamicDocument = false;
659             isInteractiveDocument = true;
660             break;
661         case ALWAYS_DYNAMIC:
662             isDynamicDocument = true;
663             isInteractiveDocument = true;
664             break;
665         case AUTODETECT:
666             isDynamicDocument = bridgeContext.isDynamicDocument(doc);
667             if (isDynamicDocument)
668                 isInteractiveDocument = true;
669             else
670                 isInteractiveDocument =
671                     bridgeContext.isInteractiveDocument(doc);
672         }
673
674         if (isInteractiveDocument) {
675             if (isDynamicDocument)
676                 bridgeContext.setDynamicState(BridgeContext.DYNAMIC);
677             else
678                 bridgeContext.setDynamicState(BridgeContext.INTERACTIVE);
679         }
680
681         Element JavaDoc root = doc.getDocumentElement();
682         String JavaDoc znp = root.getAttributeNS
683             (null, SVGConstants.SVG_ZOOM_AND_PAN_ATTRIBUTE);
684
685         setDisableInteractions(!znp.equals(SVGConstants.SVG_MAGNIFY_VALUE));
686
687         nextGVTTreeBuilder = new GVTTreeBuilder(doc, bridgeContext);
688         nextGVTTreeBuilder.setPriority(Thread.MIN_PRIORITY);
689
690         Iterator JavaDoc it = gvtTreeBuilderListeners.iterator();
691         while (it.hasNext()) {
692             nextGVTTreeBuilder.addGVTTreeBuilderListener
693                 ((GVTTreeBuilderListener)it.next());
694         }
695
696         initializeEventHandling();
697
698         if (gvtTreeBuilder == null &&
699             documentLoader == null &&
700             gvtTreeRenderer == null &&
701             svgLoadEventDispatcher == null &&
702             updateManager == null) {
703             startGVTTreeBuilder();
704         }
705     }
706
707     /**
708      * Starts a tree builder.
709      */

710     protected void startGVTTreeBuilder() {
711         gvtTreeBuilder = nextGVTTreeBuilder;
712         nextGVTTreeBuilder = null;
713         gvtTreeBuilder.start();
714     }
715
716     /**
717      * Returns the current SVG document.
718      */

719     public SVGDocument getSVGDocument() {
720         return svgDocument;
721     }
722
723     /**
724      * Returns the size of the SVG document.
725      */

726     public Dimension2D JavaDoc getSVGDocumentSize() {
727         return bridgeContext.getDocumentSize();
728     }
729
730     /**
731      * Returns the current's document fragment identifier.
732      */

733     public String JavaDoc getFragmentIdentifier() {
734         return fragmentIdentifier;
735     }
736
737     /**
738      * Sets the current fragment identifier.
739      */

740     public void setFragmentIdentifier(String JavaDoc fi) {
741         fragmentIdentifier = fi;
742         if (computeRenderingTransform())
743             scheduleGVTRendering();
744     }
745
746     /**
747      * Removes all images from the image cache.
748      */

749     public void flushImageCache() {
750         ImageTagRegistry reg = ImageTagRegistry.getRegistry();
751         reg.flushCache();
752     }
753
754     public void setGraphicsNode(GraphicsNode gn, boolean createDispatcher) {
755         Dimension2D JavaDoc dim = bridgeContext.getDocumentSize();
756         Dimension JavaDoc mySz = new Dimension JavaDoc((int)dim.getWidth(),
757                                          (int)dim.getHeight());
758         JSVGComponent.this.setMySize(mySz);
759         SVGSVGElement elt = svgDocument.getRootElement();
760         prevComponentSize = getSize();
761         AffineTransform JavaDoc at = calculateViewingTransform
762             (fragmentIdentifier, elt);
763         CanvasGraphicsNode cgn = getCanvasGraphicsNode(gn);
764         cgn.setViewingTransform(at);
765         viewingTransform = null;
766         initialTransform = new AffineTransform JavaDoc();
767         setRenderingTransform(initialTransform, false);
768         jsvgComponentListener.updateMatrix(initialTransform);
769         addJGVTComponentListener(jsvgComponentListener);
770         addComponentListener(jsvgComponentListener);
771         super.setGraphicsNode(gn, createDispatcher);
772     }
773
774     /**
775      * Creates a new bridge context.
776      */

777     protected BridgeContext createBridgeContext() {
778         if (loader == null) {
779             loader = new DocumentLoader(userAgent);
780         }
781         BridgeContext result = new BridgeContext(userAgent, loader);
782         return result;
783     }
784
785     /**
786      * Starts a SVGLoadEventDispatcher thread.
787      */

788     protected void startSVGLoadEventDispatcher(GraphicsNode root) {
789         UpdateManager um = new UpdateManager(bridgeContext,
790                                              root,
791                                              svgDocument);
792         svgLoadEventDispatcher =
793             new SVGLoadEventDispatcher(root,
794                                        svgDocument,
795                                        bridgeContext,
796                                        um);
797         Iterator JavaDoc it = svgLoadEventDispatcherListeners.iterator();
798         while (it.hasNext()) {
799             svgLoadEventDispatcher.addSVGLoadEventDispatcherListener
800                 ((SVGLoadEventDispatcherListener)it.next());
801         }
802
803         svgLoadEventDispatcher.start();
804     }
805
806     /**
807      * Creates a new renderer.
808      */

809     protected ImageRenderer createImageRenderer() {
810         if (isDynamicDocument) {
811             return rendererFactory.createDynamicImageRenderer();
812         } else {
813             return rendererFactory.createStaticImageRenderer();
814         }
815     }
816
817     public CanvasGraphicsNode getCanvasGraphicsNode() {
818         return getCanvasGraphicsNode(gvtRoot);
819         
820     }
821
822     protected CanvasGraphicsNode getCanvasGraphicsNode(GraphicsNode gn) {
823         if (!(gn instanceof CompositeGraphicsNode))
824             return null;
825         CompositeGraphicsNode cgn = (CompositeGraphicsNode)gn;
826         List JavaDoc children = cgn.getChildren();
827         if (children.size() == 0)
828             return null;
829         gn = (GraphicsNode)children.get(0);
830         if (!(gn instanceof CanvasGraphicsNode))
831             return null;
832         return (CanvasGraphicsNode)gn;
833     }
834
835     public AffineTransform JavaDoc getViewingTransform() {
836         AffineTransform JavaDoc vt;
837         synchronized (this) {
838             vt = viewingTransform;
839             if (vt == null) {
840                 CanvasGraphicsNode cgn = getCanvasGraphicsNode();
841                 if (cgn != null)
842                     vt = cgn.getViewingTransform();
843             }
844         }
845         return vt;
846     }
847
848     /**
849      * Returns the transform from viewBox coords to screen coords
850      */

851     public AffineTransform JavaDoc getViewBoxTransform() {
852         AffineTransform JavaDoc at = getRenderingTransform();
853         if (at == null) at = new AffineTransform JavaDoc();
854         else at = new AffineTransform JavaDoc(at);
855         AffineTransform JavaDoc vt = getViewingTransform();
856         if (vt != null) {
857             at.concatenate(vt);
858         }
859         return at;
860     }
861
862     /**
863      * Computes the transform used for rendering.
864      * Returns true if the component needs to be repainted.
865      */

866     protected boolean computeRenderingTransform() {
867         if ((svgDocument == null) || (gvtRoot == null))
868             return false;
869
870         boolean ret = updateRenderingTransform();
871         initialTransform = new AffineTransform JavaDoc();
872         if (!initialTransform.equals(getRenderingTransform())) {
873             setRenderingTransform(initialTransform, false);
874             ret = true;
875         }
876         return ret;
877     }
878
879     protected AffineTransform JavaDoc calculateViewingTransform
880         (String JavaDoc fragIdent, SVGSVGElement svgElt) {
881         Dimension JavaDoc d = getSize();
882         if (d.width < 1) d.width = 1;
883         if (d.height < 1) d.height = 1;
884         return ViewBox.getViewTransform
885             (fragIdent, svgElt, d.width, d.height);
886     }
887
888     /**
889      * Updates the value of the transform used for rendering.
890      * Return true if a repaint is required, otherwise false.
891      */

892     protected boolean updateRenderingTransform() {
893         if ((svgDocument == null) || (gvtRoot == null))
894             return false;
895
896         try {
897             SVGSVGElement elt = svgDocument.getRootElement();
898             Dimension JavaDoc d = getSize();
899             Dimension JavaDoc oldD = prevComponentSize;
900             if (oldD == null) oldD = d;
901             prevComponentSize = d;
902             if (d.width < 1) d.width = 1;
903             if (d.height < 1) d.height = 1;
904             final AffineTransform JavaDoc at = calculateViewingTransform
905                 (fragmentIdentifier, elt);
906             AffineTransform JavaDoc vt = getViewingTransform();
907             if (at.equals(vt)) {
908                 // No new transform
909
// Only repaint if size really changed.
910
return ((oldD.width != d.width) || (oldD.height != d.height));
911             }
912
913             if (!recenterOnResize)
914                 return true;
915
916             // Here we map the old center of the component down to
917
// the user coodinate system with the old viewing
918
// transform and then back to the screen with the
919
// new viewing transform. We then adjust the rendering
920
// transform so it lands in the same place.
921
Point2D JavaDoc pt = new Point2D.Float JavaDoc(oldD.width/2.0f,
922                                            oldD.height/2.0f);
923             AffineTransform JavaDoc rendAT = getRenderingTransform();
924             if (rendAT != null) {
925                 try {
926                     AffineTransform JavaDoc invRendAT = rendAT.createInverse();
927                     pt = invRendAT.transform(pt, null);
928                 } catch (NoninvertibleTransformException JavaDoc e) { }
929             }
930             if (vt != null) {
931                 try {
932                     AffineTransform JavaDoc invVT = vt.createInverse();
933                     pt = invVT.transform(pt, null);
934                 } catch (NoninvertibleTransformException JavaDoc e) { }
935             }
936             if (at != null)
937                 pt = at.transform(pt, null);
938             if (rendAT != null)
939                 pt = rendAT.transform(pt, null);
940             
941             // Now figure out how far we need to shift things
942
// to get the center point to line up again.
943
float dx = (float)((d.width/2.0f) -pt.getX());
944             float dy = (float)((d.height/2.0f)-pt.getY());
945             // Round the values to nearest integer.
946
dx = (int)((dx < 0)?(dx - .5):(dx + .5));
947             dy = (int)((dy < 0)?(dy - .5):(dy + .5));
948             if ((dx != 0) || (dy != 0)) {
949                 rendAT.preConcatenate
950                     (AffineTransform.getTranslateInstance(dx, dy));
951                 setRenderingTransform(rendAT, false);
952             }
953             synchronized (this) {
954                 viewingTransform = at;
955             }
956             Runnable JavaDoc r = new Runnable JavaDoc() {
957                     AffineTransform JavaDoc myAT = at;
958                     CanvasGraphicsNode myCGN = getCanvasGraphicsNode();
959                     public void run() {
960                         synchronized (JSVGComponent.this) {
961                             myCGN.setViewingTransform(myAT);
962                             if (viewingTransform == myAT)
963                                 viewingTransform = null;
964                         }
965                     }
966                 };
967             UpdateManager um = getUpdateManager();
968             if (um != null) um.getUpdateRunnableQueue().invokeLater(r);
969             else r.run();
970         } catch (BridgeException e) {
971             userAgent.displayError(e);
972         }
973         return true;
974     }
975
976     /**
977      * Renders the GVT tree.
978      */

979     protected void renderGVTTree() {
980         if (!isInteractiveDocument ||
981             updateManager == null ||
982             !updateManager.isRunning()) {
983             super.renderGVTTree();
984             return;
985         }
986
987         final Rectangle JavaDoc visRect = getRenderRect();
988         if ((gvtRoot == null) ||
989             (visRect.width <= 0) ||
990             (visRect.height <= 0)) {
991             return;
992         }
993
994         // Area of interest computation.
995
AffineTransform JavaDoc inv = null;
996         try {
997             inv = renderingTransform.createInverse();
998         } catch (NoninvertibleTransformException JavaDoc e) {
999         }
1000        final Shape JavaDoc s;
1001        if (inv == null) s = visRect;
1002        else s = inv.createTransformedShape(visRect);
1003
1004        class UpdateRenderingRunnable implements Runnable JavaDoc {
1005            AffineTransform JavaDoc at;
1006            boolean doubleBuf;
1007            boolean clearPaintTrans;
1008            Shape JavaDoc aoi;
1009            int width;
1010            int height;
1011
1012            boolean active;
1013
1014            public UpdateRenderingRunnable(AffineTransform JavaDoc at,
1015                                           boolean doubleBuf,
1016                                           boolean clearPaintTrans,
1017                                           Shape JavaDoc aoi,
1018                                           int width, int height) {
1019                updateInfo(at, doubleBuf, clearPaintTrans, aoi, width, height);
1020                active = true;
1021            }
1022
1023            public void updateInfo(AffineTransform JavaDoc at,
1024                                   boolean doubleBuf,
1025                                   boolean clearPaintTrans,
1026                                   Shape JavaDoc aoi,
1027                                   int width, int height) {
1028                this.at = at;
1029                this.doubleBuf = doubleBuf;
1030                this.clearPaintTrans = clearPaintTrans;
1031                this.aoi = aoi;
1032                this.width = width;
1033                this.height = height;
1034                active = true;
1035            }
1036
1037            public void deactivate() {
1038                active = false;
1039            }
1040            public void run() {
1041                if (!active) return;
1042
1043                updateManager.updateRendering
1044                    (at, doubleBuf, clearPaintTrans, aoi, width, height);
1045            }
1046        }
1047        RunnableQueue rq = updateManager.getUpdateRunnableQueue();
1048
1049        // Events compression.
1050
synchronized (rq.getIteratorLock()) {
1051            Iterator JavaDoc it = rq.iterator();
1052            while (it.hasNext()) {
1053                Object JavaDoc next = it.next();
1054                if (next instanceof UpdateRenderingRunnable) {
1055                    ((UpdateRenderingRunnable)next).deactivate();
1056                }
1057            }
1058        }
1059
1060        rq.invokeLater(new UpdateRenderingRunnable
1061                       (renderingTransform,
1062                        doubleBufferedRendering, true, s,
1063                        visRect.width, visRect.height));
1064    }
1065
1066    /**
1067     * Handles an exception.
1068     */

1069    protected void handleException(Exception JavaDoc e) {
1070        userAgent.displayError(e);
1071    }
1072
1073    /**
1074     * Adds a SVGDocumentLoaderListener to this component.
1075     */

1076    public void addSVGDocumentLoaderListener(SVGDocumentLoaderListener l) {
1077        svgDocumentLoaderListeners.add(l);
1078    }
1079
1080    /**
1081     * Removes a SVGDocumentLoaderListener from this component.
1082     */

1083    public void removeSVGDocumentLoaderListener(SVGDocumentLoaderListener l) {
1084        svgDocumentLoaderListeners.remove(l);
1085    }
1086
1087    /**
1088     * Adds a GVTTreeBuilderListener to this component.
1089     */

1090    public void addGVTTreeBuilderListener(GVTTreeBuilderListener l) {
1091        gvtTreeBuilderListeners.add(l);
1092    }
1093
1094    /**
1095     * Removes a GVTTreeBuilderListener from this component.
1096     */

1097    public void removeGVTTreeBuilderListener(GVTTreeBuilderListener l) {
1098        gvtTreeBuilderListeners.remove(l);
1099    }
1100
1101    /**
1102     * Adds a SVGLoadEventDispatcherListener to this component.
1103     */

1104    public void addSVGLoadEventDispatcherListener
1105        (SVGLoadEventDispatcherListener l) {
1106        svgLoadEventDispatcherListeners.add(l);
1107    }
1108
1109    /**
1110     * Removes a SVGLoadEventDispatcherListener from this component.
1111     */

1112    public void removeSVGLoadEventDispatcherListener
1113        (SVGLoadEventDispatcherListener l) {
1114        svgLoadEventDispatcherListeners.remove(l);
1115    }
1116
1117    /**
1118     * Adds a LinkActivationListener to this component.
1119     */

1120    public void addLinkActivationListener(LinkActivationListener l) {
1121        linkActivationListeners.add(l);
1122    }
1123
1124    /**
1125     * Removes a LinkActivationListener from this component.
1126     */

1127    public void removeLinkActivationListener(LinkActivationListener l) {
1128        linkActivationListeners.remove(l);
1129    }
1130
1131    /**
1132     * Adds a UpdateManagerListener to this component.
1133     */

1134    public void addUpdateManagerListener(UpdateManagerListener l) {
1135        updateManagerListeners.add(l);
1136    }
1137
1138    /**
1139     * Removes a UpdateManagerListener from this component.
1140     */

1141    public void removeUpdateManagerListener(UpdateManagerListener l) {
1142        updateManagerListeners.remove(l);
1143    }
1144
1145    /**
1146     * Shows an alert dialog box.
1147     */

1148    public void showAlert(String JavaDoc message) {
1149        JOptionPane.showMessageDialog
1150            (this, Messages.formatMessage("script.alert",
1151                                          new Object JavaDoc[] { message }));
1152    }
1153
1154    /**
1155     * Shows a prompt dialog box.
1156     */

1157    public String JavaDoc showPrompt(String JavaDoc message) {
1158        return JOptionPane.showInputDialog
1159            (this, Messages.formatMessage("script.prompt",
1160                                          new Object JavaDoc[] { message }));
1161    }
1162
1163    /**
1164     * Shows a prompt dialog box.
1165     */

1166    public String JavaDoc showPrompt(String JavaDoc message, String JavaDoc defaultValue) {
1167        return (String JavaDoc)JOptionPane.showInputDialog
1168            (this,
1169             Messages.formatMessage("script.prompt",
1170                                    new Object JavaDoc[] { message }),
1171             null,
1172             JOptionPane.PLAIN_MESSAGE,
1173             null, null, defaultValue);
1174    }
1175
1176    /**
1177     * Shows a confirm dialog box.
1178     */

1179    public boolean showConfirm(String JavaDoc message) {
1180        return JOptionPane.showConfirmDialog
1181            (this, Messages.formatMessage("script.confirm",
1182                                          new Object JavaDoc[] { message }),
1183             "Confirm", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
1184    }
1185
1186
1187    /**
1188     * This method is called when the component knows the desired
1189     * size of the window (based on width/height of outermost SVG
1190     * element).
1191     * The default implementation simply calls setPreferredSize,
1192     * and invalidate.
1193     * However it is often useful to pack the window containing
1194     * this component.
1195     */

1196    public void setMySize(Dimension JavaDoc d) {
1197        setPreferredSize(d);
1198        invalidate();
1199    }
1200
1201    /**
1202     * The JGVTComponentListener.
1203     */

1204    protected JSVGComponentListener jsvgComponentListener =
1205        new JSVGComponentListener();
1206
1207    protected class JSVGComponentListener extends ComponentAdapter JavaDoc
1208        implements JGVTComponentListener {
1209        float prevScale = 0;
1210        float prevTransX = 0;
1211        float prevTransY = 0;
1212
1213        public void componentResized(ComponentEvent JavaDoc ce) {
1214            if (isDynamicDocument &&
1215                (updateManager != null) && updateManager.isRunning()) {
1216                updateManager.getUpdateRunnableQueue().invokeLater
1217                    (new Runnable JavaDoc() {
1218                        public void run() {
1219                            try {
1220                                updateManager.dispatchSVGResizeEvent();
1221                            } catch (InterruptedException JavaDoc ie) {
1222                            }
1223                        }});
1224            }
1225        }
1226
1227        public void componentTransformChanged(ComponentEvent JavaDoc event) {
1228            AffineTransform JavaDoc at = getRenderingTransform();
1229
1230            float currScale = (float)Math.sqrt(at.getDeterminant());
1231            float currTransX = (float)at.getTranslateX();
1232            float currTransY = (float)at.getTranslateY();
1233
1234            final boolean dispatchZoom = (currScale != prevScale);
1235            final boolean dispatchScroll = ((currTransX != prevTransX) ||
1236                                             (currTransX != prevTransX));
1237            if (isDynamicDocument &&
1238                (updateManager != null) && updateManager.isRunning()) {
1239                updateManager.getUpdateRunnableQueue().invokeLater
1240                    (new Runnable JavaDoc() {
1241                        public void run() {
1242                            try {
1243                                if (dispatchZoom)
1244                                    updateManager.dispatchSVGZoomEvent();
1245                                if (dispatchScroll)
1246                                    updateManager.dispatchSVGScrollEvent();
1247                            } catch (InterruptedException JavaDoc ie) {
1248                            }
1249                        }});
1250            }
1251            prevScale = currScale;
1252            prevTransX = currTransX;
1253            prevTransY = currTransY;
1254        }
1255
1256        public void updateMatrix(AffineTransform JavaDoc at) {
1257            prevScale = (float)Math.sqrt(at.getDeterminant());
1258            prevTransX = (float)at.getTranslateX();
1259            prevTransY = (float)at.getTranslateY();
1260        }
1261    }
1262
1263
1264    /**
1265     * Creates an instance of Listener.
1266     */

1267    protected Listener createListener() {
1268        return new SVGListener();
1269    }
1270
1271    /**
1272     * To hide the listener methods.
1273     */

1274    protected class SVGListener
1275        extends Listener
1276        implements SVGDocumentLoaderListener,
1277                   GVTTreeBuilderListener,
1278                   SVGLoadEventDispatcherListener,
1279                   UpdateManagerListener {
1280
1281        /**
1282         * Creates a new SVGListener.
1283         */

1284        protected SVGListener() {
1285        }
1286
1287        // SVGDocumentLoaderListener /////////////////////////////////////////
1288

1289        /**
1290         * Called when the loading of a document was started.
1291         */

1292        public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
1293        }
1294
1295        /**
1296         * Called when the loading of a document was completed.
1297         */

1298        public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
1299            if (nextDocumentLoader != null) {
1300                startDocumentLoader();
1301                return;
1302            }
1303
1304            documentLoader = null;
1305            if (afterStopRunnable != null) {
1306                EventQueue.invokeLater(afterStopRunnable);
1307                afterStopRunnable = null;
1308                return;
1309            }
1310                
1311            setSVGDocument(e.getSVGDocument());
1312        }
1313
1314        /**
1315         * Called when the loading of a document was cancelled.
1316         */

1317        public void documentLoadingCancelled(SVGDocumentLoaderEvent e) {
1318            if (nextDocumentLoader != null) {
1319                startDocumentLoader();
1320                return;
1321            }
1322
1323            documentLoader = null;
1324            if (afterStopRunnable != null) {
1325                EventQueue.invokeLater(afterStopRunnable);
1326                afterStopRunnable = null;
1327                return;
1328            }
1329
1330            if (nextGVTTreeBuilder != null) {
1331                startGVTTreeBuilder();
1332                return;
1333            }
1334        }
1335
1336        /**
1337         * Called when the loading of a document has failed.
1338         */

1339        public void documentLoadingFailed(SVGDocumentLoaderEvent e) {
1340            if (nextDocumentLoader != null) {
1341                startDocumentLoader();
1342                return;
1343            }
1344
1345            documentLoader = null;
1346            userAgent.displayError(((SVGDocumentLoader)e.getSource()).
1347                                   getException());
1348
1349            if (afterStopRunnable != null) {
1350                EventQueue.invokeLater(afterStopRunnable);
1351                afterStopRunnable = null;
1352                return;
1353            }
1354            if (nextGVTTreeBuilder != null) {
1355                startGVTTreeBuilder();
1356                return;
1357            }
1358        }
1359
1360        // GVTTreeBuilderListener ////////////////////////////////////////////
1361

1362        /**
1363         * Called when a build started.
1364         * The data of the event is initialized to the old document.
1365         */

1366        public void gvtBuildStarted(GVTTreeBuilderEvent e) {
1367            removeJGVTComponentListener(jsvgComponentListener);
1368            removeComponentListener(jsvgComponentListener);
1369        }
1370
1371        /**
1372         * Called when a build was completed.
1373         */

1374        public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
1375            if (nextGVTTreeBuilder != null) {
1376                startGVTTreeBuilder();
1377                return;
1378            }
1379
1380            loader = null;
1381            gvtTreeBuilder = null;
1382
1383            if (afterStopRunnable != null) {
1384                EventQueue.invokeLater(afterStopRunnable);
1385                afterStopRunnable = null;
1386                return;
1387            }
1388
1389            if (nextDocumentLoader != null) {
1390                startDocumentLoader();
1391                return;
1392            }
1393
1394            gvtRoot = null;
1395
1396            if (isDynamicDocument && JSVGComponent.this.eventsEnabled) {
1397                startSVGLoadEventDispatcher(e.getGVTRoot());
1398            } else {
1399                if (isInteractiveDocument) {
1400                    nextUpdateManager = new UpdateManager(bridgeContext,
1401                                                          e.getGVTRoot(),
1402                                                          svgDocument);
1403                }
1404                    
1405                JSVGComponent.this.setGraphicsNode(e.getGVTRoot(), false);
1406                scheduleGVTRendering();
1407            }
1408        }
1409
1410        /**
1411         * Called when a build was cancelled.
1412         */

1413        public void gvtBuildCancelled(GVTTreeBuilderEvent e) {
1414            if (nextGVTTreeBuilder != null) {
1415                startGVTTreeBuilder();
1416                return;
1417            }
1418
1419            loader = null;
1420            gvtTreeBuilder = null;
1421
1422            if (afterStopRunnable != null) {
1423                EventQueue.invokeLater(afterStopRunnable);
1424                afterStopRunnable = null;
1425                return;
1426            }
1427
1428            if (nextDocumentLoader != null) {
1429                startDocumentLoader();
1430                return;
1431            }
1432            JSVGComponent.this.image = null;
1433            repaint();
1434        }
1435
1436        /**
1437         * Called when a build failed.
1438         */

1439        public void gvtBuildFailed(GVTTreeBuilderEvent e) {
1440            if (nextGVTTreeBuilder != null) {
1441                startGVTTreeBuilder();
1442                return;
1443            }
1444
1445            loader = null;
1446            gvtTreeBuilder = null;
1447
1448            if (afterStopRunnable != null) {
1449                EventQueue.invokeLater(afterStopRunnable);
1450                afterStopRunnable = null;
1451                return;
1452            }
1453
1454            if (nextDocumentLoader != null) {
1455                startDocumentLoader();
1456                return;
1457            }
1458
1459            GraphicsNode gn = e.getGVTRoot();
1460            if (gn == null) {
1461                JSVGComponent.this.image = null;
1462                repaint();
1463            } else {
1464                JSVGComponent.this.setGraphicsNode(gn, false);
1465                computeRenderingTransform();
1466            }
1467            userAgent.displayError(((GVTTreeBuilder)e.getSource())
1468                                   .getException());
1469        }
1470
1471        // SVGLoadEventDispatcherListener ////////////////////////////////////
1472

1473        /**
1474         * Called when a onload event dispatch started.
1475         */

1476        public void svgLoadEventDispatchStarted
1477            (SVGLoadEventDispatcherEvent e) {
1478        }
1479
1480        /**
1481         * Called when a onload event dispatch was completed.
1482         */

1483        public void svgLoadEventDispatchCompleted
1484            (SVGLoadEventDispatcherEvent e) {
1485            nextUpdateManager = svgLoadEventDispatcher.getUpdateManager();
1486            svgLoadEventDispatcher = null;
1487
1488            if (afterStopRunnable != null) {
1489                nextUpdateManager.interrupt();
1490                nextUpdateManager = null;
1491            
1492                EventQueue.invokeLater(afterStopRunnable);
1493                afterStopRunnable = null;
1494                return;
1495            }
1496
1497            if (nextGVTTreeBuilder != null) {
1498                nextUpdateManager.interrupt();
1499                nextUpdateManager = null;
1500            
1501                startGVTTreeBuilder();
1502                return;
1503            }
1504            if (nextDocumentLoader != null) {
1505                nextUpdateManager.interrupt();
1506                nextUpdateManager = null;
1507            
1508                startDocumentLoader();
1509                return;
1510            }
1511
1512            JSVGComponent.this.setGraphicsNode(e.getGVTRoot(), false);
1513            scheduleGVTRendering();
1514        }
1515
1516        /**
1517         * Called when a onload event dispatch was cancelled.
1518         */

1519        public void svgLoadEventDispatchCancelled
1520            (SVGLoadEventDispatcherEvent e) {
1521            nextUpdateManager = svgLoadEventDispatcher.getUpdateManager();
1522            svgLoadEventDispatcher = null;
1523
1524            nextUpdateManager.interrupt();
1525            nextUpdateManager = null;
1526            
1527            if (afterStopRunnable != null) {
1528                EventQueue.invokeLater(afterStopRunnable);
1529                afterStopRunnable = null;
1530                return;
1531            }
1532
1533            if (nextGVTTreeBuilder != null) {
1534                startGVTTreeBuilder();
1535                return;
1536            }
1537            if (nextDocumentLoader != null) {
1538                startDocumentLoader();
1539                return;
1540            }
1541        }
1542
1543        /**
1544         * Called when a onload event dispatch failed.
1545         */

1546        public void svgLoadEventDispatchFailed
1547            (SVGLoadEventDispatcherEvent e) {
1548            nextUpdateManager = svgLoadEventDispatcher.getUpdateManager();
1549            svgLoadEventDispatcher = null;
1550
1551            nextUpdateManager.interrupt();
1552            nextUpdateManager = null;
1553
1554            if (afterStopRunnable != null) {
1555                EventQueue.invokeLater(afterStopRunnable);
1556                afterStopRunnable = null;
1557                return;
1558            }
1559
1560            if (nextGVTTreeBuilder != null) {
1561                startGVTTreeBuilder();
1562                return;
1563            }
1564            if (nextDocumentLoader != null) {
1565                startDocumentLoader();
1566                return;
1567            }
1568
1569            GraphicsNode gn = e.getGVTRoot();
1570            if (gn == null) {
1571                JSVGComponent.this.image = null;
1572                repaint();
1573            } else {
1574                JSVGComponent.this.setGraphicsNode(gn, false);
1575                computeRenderingTransform();
1576            }
1577            userAgent.displayError(((SVGLoadEventDispatcher)e.getSource())
1578                                   .getException());
1579        }
1580
1581        // GVTTreeRendererListener ///////////////////////////////////////////
1582

1583        /**
1584         * Called when a rendering was completed.
1585         */

1586        public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
1587            super.gvtRenderingCompleted(e);
1588
1589            if (afterStopRunnable != null) {
1590                if (nextUpdateManager != null) {
1591                    nextUpdateManager.interrupt();
1592                    nextUpdateManager = null;
1593                }
1594                EventQueue.invokeLater(afterStopRunnable);
1595                afterStopRunnable = null;
1596                return;
1597            }
1598
1599            if (nextGVTTreeBuilder != null) {
1600                if (nextUpdateManager != null) {
1601                    nextUpdateManager.interrupt();
1602                    nextUpdateManager = null;
1603                }
1604                startGVTTreeBuilder();
1605                return;
1606            }
1607            if (nextDocumentLoader != null) {
1608                if (nextUpdateManager != null) {
1609                    nextUpdateManager.interrupt();
1610                    nextUpdateManager = null;
1611                }
1612                startDocumentLoader();
1613                return;
1614            }
1615            
1616            if (nextUpdateManager != null) {
1617                updateManager = nextUpdateManager;
1618                nextUpdateManager = null;
1619                updateManager.addUpdateManagerListener(this);
1620                updateManager.manageUpdates(renderer);
1621            }
1622        }
1623
1624        /**
1625         * Called when a rendering was cancelled.
1626         */

1627        public void gvtRenderingCancelled(GVTTreeRendererEvent e) {
1628            super.gvtRenderingCancelled(e);
1629
1630            if (afterStopRunnable != null) {
1631                if (nextUpdateManager != null) {
1632                    nextUpdateManager.interrupt();
1633                    nextUpdateManager = null;
1634                }
1635
1636                EventQueue.invokeLater(afterStopRunnable);
1637                afterStopRunnable = null;
1638                return;
1639            }
1640
1641            if (nextGVTTreeBuilder != null) {
1642                if (nextUpdateManager != null) {
1643                    nextUpdateManager.interrupt();
1644                    nextUpdateManager = null;
1645                }
1646
1647                startGVTTreeBuilder();
1648                return;
1649            }
1650            if (nextDocumentLoader != null) {
1651                if (nextUpdateManager != null) {
1652                    nextUpdateManager.interrupt();
1653                    nextUpdateManager = null;
1654                }
1655                startDocumentLoader();
1656                return;
1657            }
1658        }
1659
1660        /**
1661         * Called when a rendering failed.
1662         */

1663        public void gvtRenderingFailed(GVTTreeRendererEvent e) {
1664            super.gvtRenderingFailed(e);
1665
1666            if (afterStopRunnable != null) {
1667                if (nextUpdateManager != null) {
1668                    nextUpdateManager.interrupt();
1669                    nextUpdateManager = null;
1670                }
1671
1672                EventQueue.invokeLater(afterStopRunnable);
1673                afterStopRunnable = null;
1674                return;
1675            }
1676
1677            if (nextGVTTreeBuilder != null) {
1678                if (nextUpdateManager != null) {
1679                    nextUpdateManager.interrupt();
1680                    nextUpdateManager = null;
1681                }
1682
1683                startGVTTreeBuilder();
1684                return;
1685            }
1686            if (nextDocumentLoader != null) {
1687                if (nextUpdateManager != null) {
1688                    nextUpdateManager.interrupt();
1689                    nextUpdateManager = null;
1690                }
1691
1692                startDocumentLoader();
1693                return;
1694            }
1695        }
1696
1697        // UpdateManagerListener //////////////////////////////////////////
1698

1699        /**
1700         * Called when the manager was started.
1701         */

1702        public void managerStarted(final UpdateManagerEvent e) {
1703            EventQueue.invokeLater(new Runnable JavaDoc() {
1704                    public void run() {
1705                        suspendInteractions = false;
1706
1707                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1708                        
1709                        if (dll.length > 0) {
1710                            for (int i = 0; i < dll.length; i++) {
1711                                ((UpdateManagerListener)dll[i]).
1712                                    managerStarted(e);
1713                            }
1714                        }
1715                    }
1716                });
1717        }
1718
1719        /**
1720         * Called when the manager was suspended.
1721         */

1722        public void managerSuspended(final UpdateManagerEvent e) {
1723            EventQueue.invokeLater(new Runnable JavaDoc() {
1724                    public void run() {
1725                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1726                        
1727                        if (dll.length > 0) {
1728                            for (int i = 0; i < dll.length; i++) {
1729                                ((UpdateManagerListener)dll[i]).
1730                                    managerSuspended(e);
1731                            }
1732                        }
1733                    }
1734                });
1735        }
1736
1737        /**
1738         * Called when the manager was resumed.
1739         */

1740        public void managerResumed(final UpdateManagerEvent e) {
1741            EventQueue.invokeLater(new Runnable JavaDoc() {
1742                    public void run() {
1743                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1744                        
1745                        if (dll.length > 0) {
1746                            for (int i = 0; i < dll.length; i++) {
1747                                ((UpdateManagerListener)dll[i]).
1748                                    managerResumed(e);
1749                            }
1750                        }
1751                    }
1752                });
1753        }
1754
1755        /**
1756         * Called when the manager was stopped.
1757         */

1758        public void managerStopped(final UpdateManagerEvent e) {
1759            EventQueue.invokeLater(new Runnable JavaDoc() {
1760                    public void run() {
1761                        updateManager = null;
1762                        
1763
1764                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1765                        
1766                        if (dll.length > 0) {
1767                            for (int i = 0; i < dll.length; i++) {
1768                                ((UpdateManagerListener)dll[i]).
1769                                    managerStopped(e);
1770                            }
1771                        }
1772
1773                        if (afterStopRunnable != null) {
1774                            EventQueue.invokeLater(afterStopRunnable);
1775                            afterStopRunnable = null;
1776                            return;
1777                        }
1778
1779                        if (nextGVTTreeBuilder != null) {
1780                            startGVTTreeBuilder();
1781                            return;
1782                        }
1783                        if (nextDocumentLoader != null) {
1784                            startDocumentLoader();
1785                            return;
1786                        }
1787                    }
1788                });
1789        }
1790
1791        /**
1792         * Called when an update started.
1793         */

1794        public void updateStarted(final UpdateManagerEvent e) {
1795            EventQueue.invokeLater(new Runnable JavaDoc() {
1796                    public void run() {
1797                        if (!doubleBufferedRendering) {
1798                            image = e.getImage();
1799                        }
1800
1801                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1802                        
1803                        if (dll.length > 0) {
1804                            for (int i = 0; i < dll.length; i++) {
1805                                ((UpdateManagerListener)dll[i]).
1806                                    updateStarted(e);
1807                            }
1808                        }
1809                    }
1810                });
1811        }
1812
1813        /**
1814         * Called when an update was completed.
1815         */

1816        public void updateCompleted(final UpdateManagerEvent e) {
1817            // IMPORTANT:
1818
// ==========
1819
//
1820
// The following call is 'invokeAndWait' and not
1821
// 'invokeLater' because it is essential that the
1822
// UpdateManager thread (which invokes this
1823
// 'updateCompleted' method, blocks until the repaint
1824
// has completed. Otherwise, there is a possibility
1825
// that internal buffers would get updated in the
1826
// middle of a swing repaint.
1827
//
1828
try {
1829                EventQueue.invokeAndWait(new Runnable JavaDoc() {
1830                        public void run() {
1831                            image = e.getImage();
1832                            if (e.getClearPaintingTransform())
1833                                paintingTransform = null;
1834
1835                            List JavaDoc l = e.getDirtyAreas();
1836                            if (l != null) {
1837                                Rectangle JavaDoc visRect = getRenderRect();
1838                                Iterator JavaDoc i = l.iterator();
1839                                while (i.hasNext()) {
1840                                    Rectangle JavaDoc r = (Rectangle JavaDoc)i.next();
1841                                    if (updateOverlay != null) {
1842                                        updateOverlay.addRect(r);
1843                                        r = getRenderRect();
1844                                    }
1845
1846                                    if (doubleBufferedRendering)
1847                                        repaint(r);
1848                                    else
1849                                        paintImmediately(r);
1850                                }
1851                                if (updateOverlay != null)
1852                                    updateOverlay.endUpdate();
1853                            }
1854                            suspendInteractions = false;
1855                        }
1856                    });
1857            } catch (Exception JavaDoc ex) {
1858            }
1859            
1860
1861            EventQueue.invokeLater(new Runnable JavaDoc() {
1862                    public void run() {
1863                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1864                        
1865                        if (dll.length > 0) {
1866                            for (int i = 0; i < dll.length; i++) {
1867                                ((UpdateManagerListener)dll[i]).
1868                                    updateCompleted(e);
1869                            }
1870                        }
1871                    }
1872                });
1873        }
1874
1875        /**
1876         * Called when an update failed.
1877         */

1878        public void updateFailed(final UpdateManagerEvent e) {
1879            EventQueue.invokeLater(new Runnable JavaDoc() {
1880                    public void run() {
1881                        Object JavaDoc[] dll = updateManagerListeners.toArray();
1882                        
1883                        if (dll.length > 0) {
1884                            for (int i = 0; i < dll.length; i++) {
1885                                ((UpdateManagerListener)dll[i]).
1886                                    updateFailed(e);
1887                            }
1888                        }
1889                    }
1890                });
1891        }
1892
1893        // Event propagation to GVT ///////////////////////////////////////
1894

1895        /**
1896         * Dispatches the event to the GVT tree.
1897         */

1898        protected void dispatchKeyTyped(final KeyEvent JavaDoc e) {
1899            if (!isDynamicDocument) {
1900                super.dispatchKeyTyped(e);
1901                return;
1902            }
1903
1904            if (updateManager != null && updateManager.isRunning()) {
1905                updateManager.getUpdateRunnableQueue().invokeLater
1906                    (new Runnable JavaDoc() {
1907                        public void run() {
1908                            eventDispatcher.keyTyped(e);
1909                        }
1910                    });
1911            }
1912
1913        }
1914
1915        /**
1916         * Dispatches the event to the GVT tree.
1917         */

1918        protected void dispatchKeyPressed(final KeyEvent JavaDoc e) {
1919            if (!isDynamicDocument) {
1920                super.dispatchKeyPressed(e);
1921                return;
1922            }
1923
1924            if (updateManager != null && updateManager.isRunning()) {
1925                updateManager.getUpdateRunnableQueue().invokeLater
1926                    (new Runnable JavaDoc() {
1927                        public void run() {
1928                            eventDispatcher.keyPressed(e);
1929                        }
1930                    });
1931            }
1932        }
1933
1934        /**
1935         * Dispatches the event to the GVT tree.
1936         */

1937        protected void dispatchKeyReleased(final KeyEvent JavaDoc e) {
1938            if (!isDynamicDocument) {
1939                super.dispatchKeyReleased(e);
1940                return;
1941            }
1942
1943            if (updateManager != null && updateManager.isRunning()) {
1944                updateManager.getUpdateRunnableQueue().invokeLater
1945                    (new Runnable JavaDoc() {
1946                        public void run() {
1947                            eventDispatcher.keyReleased(e);
1948                        }
1949                    });
1950            }
1951        }
1952
1953        /**
1954         * Dispatches the event to the GVT tree.
1955         */

1956        protected void dispatchMouseClicked(final MouseEvent JavaDoc e) {
1957            if (!isInteractiveDocument) {
1958                super.dispatchMouseClicked(e);
1959                return;
1960            }
1961
1962            if (updateManager != null && updateManager.isRunning()) {
1963                updateManager.getUpdateRunnableQueue().invokeLater
1964                    (new Runnable JavaDoc() {
1965                        public void run() {
1966                            eventDispatcher.mouseClicked(e);
1967                            
1968                        }
1969                    });
1970            }
1971        }
1972
1973        /**
1974         * Dispatches the event to the GVT tree.
1975         */

1976        protected void dispatchMousePressed(final MouseEvent JavaDoc e) {
1977            if (!isDynamicDocument) {
1978                super.dispatchMousePressed(e);
1979                return;
1980            }
1981
1982            if (updateManager != null && updateManager.isRunning()) {
1983                updateManager.getUpdateRunnableQueue().invokeLater
1984                    (new Runnable JavaDoc() {
1985                        public void run() {
1986                            eventDispatcher.mousePressed(e);
1987                        }
1988                    });
1989            }
1990        }
1991
1992        /**
1993         * Dispatches the event to the GVT tree.
1994         */

1995        protected void dispatchMouseReleased(final MouseEvent JavaDoc e) {
1996            if (!isDynamicDocument) {
1997                super.dispatchMouseReleased(e);
1998                return;
1999            }
2000
2001            if (updateManager != null && updateManager.isRunning()) {
2002                updateManager.getUpdateRunnableQueue().invokeLater
2003                    (new Runnable JavaDoc() {
2004                        public void run() {
2005                            eventDispatcher.mouseReleased(e);
2006                        }
2007                    });
2008            }
2009        }
2010
2011        /**
2012         * Dispatches the event to the GVT tree.
2013         */

2014        protected void dispatchMouseEntered(final MouseEvent JavaDoc e) {
2015            if (!isInteractiveDocument) {
2016                super.dispatchMouseEntered(e);
2017                return;
2018            }
2019
2020            if (updateManager != null && updateManager.isRunning()) {
2021                updateManager.getUpdateRunnableQueue().invokeLater
2022                    (new Runnable JavaDoc() {
2023                        public void run() {
2024                            eventDispatcher.mouseEntered(e);
2025                        }
2026                    });
2027            }
2028        }
2029
2030        /**
2031         * Dispatches the event to the GVT tree.
2032         */

2033        protected void dispatchMouseExited(final MouseEvent JavaDoc e) {
2034            if (!isInteractiveDocument) {
2035                super.dispatchMouseExited(e);
2036                return;
2037            }
2038
2039            if (updateManager != null && updateManager.isRunning()) {
2040                updateManager.getUpdateRunnableQueue().invokeLater
2041                    (new Runnable JavaDoc() {
2042                        public void run() {
2043                            eventDispatcher.mouseExited(e);
2044                        }
2045                    });
2046            }
2047        }
2048
2049        /**
2050         * Dispatches the event to the GVT tree.
2051         */

2052        protected void dispatchMouseDragged(MouseEvent JavaDoc e) {
2053            if (!isDynamicDocument) {
2054                super.dispatchMouseDragged(e);
2055                return;
2056            }
2057
2058            class MouseDraggedRunnable implements Runnable JavaDoc {
2059                MouseEvent JavaDoc event;
2060                MouseDraggedRunnable(MouseEvent JavaDoc evt) {
2061                    event = evt;
2062                }
2063                public void run() {
2064                    eventDispatcher.mouseDragged(event);
2065                }
2066            }
2067
2068            if (updateManager != null && updateManager.isRunning()) {
2069                RunnableQueue rq = updateManager.getUpdateRunnableQueue();
2070
2071                // Events compression.
2072
synchronized (rq.getIteratorLock()) {
2073                    Iterator JavaDoc it = rq.iterator();
2074                    while (it.hasNext()) {
2075                        Object JavaDoc next = it.next();
2076                        if (next instanceof MouseDraggedRunnable) {
2077                            MouseDraggedRunnable mdr;
2078                            mdr = (MouseDraggedRunnable)next;
2079                            MouseEvent JavaDoc mev = mdr.event;
2080                            if (mev.getModifiers() == e.getModifiers()) {
2081                                mdr.event = e;
2082                            }
2083                            return;
2084                        }
2085                    }
2086                }
2087
2088                rq.invokeLater(new MouseDraggedRunnable(e));
2089            }
2090        }
2091
2092        /**
2093         * Dispatches the event to the GVT tree.
2094         */

2095        protected void dispatchMouseMoved(MouseEvent JavaDoc e) {
2096            if (!isInteractiveDocument) {
2097                super.dispatchMouseMoved(e);
2098                return;
2099            }
2100
2101            class MouseMovedRunnable implements Runnable JavaDoc {
2102                MouseEvent JavaDoc event;
2103                MouseMovedRunnable(MouseEvent JavaDoc evt) {
2104                    event = evt;
2105                }
2106                public void run() {
2107                    eventDispatcher.mouseMoved(event);
2108                }
2109            }
2110
2111            if (updateManager != null && updateManager.isRunning()) {
2112                RunnableQueue rq = updateManager.getUpdateRunnableQueue();
2113
2114                // Events compression.
2115
int i = 0;
2116                synchronized (rq.getIteratorLock()) {
2117                    Iterator JavaDoc it = rq.iterator();
2118                    while (it.hasNext()) {
2119                        Object JavaDoc next = it.next();
2120                        if (next instanceof MouseMovedRunnable) {
2121                            MouseMovedRunnable mmr;
2122                            mmr = (MouseMovedRunnable)next;
2123                            MouseEvent JavaDoc mev = mmr.event;
2124                            if (mev.getModifiers() == e.getModifiers()) {
2125                                mmr.event = e;
2126                            }
2127                            return;
2128                        }
2129                        i++;
2130                    }
2131
2132                }
2133
2134                rq.invokeLater(new MouseMovedRunnable(e));
2135            }
2136        }
2137    }
2138
2139    /**
2140     * Creates a UserAgent.
2141     */

2142    protected UserAgent createUserAgent() {
2143        return new BridgeUserAgent();
2144    }
2145
2146    /**
2147     * The user-agent wrapper, which call the methods in the event thread.
2148     */

2149    protected static class BridgeUserAgentWrapper implements UserAgent {
2150
2151        /**
2152         * The wrapped user agent.
2153         */

2154        protected UserAgent userAgent;
2155
2156        /**
2157         * Creates a new BridgeUserAgentWrapper.
2158         */

2159        public BridgeUserAgentWrapper(UserAgent ua) {
2160            userAgent = ua;
2161        }
2162
2163        /**
2164         * Returns the event dispatcher to use.
2165         */

2166        public EventDispatcher getEventDispatcher() {
2167            if (EventQueue.isDispatchThread()) {
2168                return userAgent.getEventDispatcher();
2169            } else {
2170                class Query implements Runnable JavaDoc {
2171                    EventDispatcher result;
2172                    public void run() {
2173                        result = userAgent.getEventDispatcher();
2174                    }
2175                }
2176                Query q = new Query();
2177                invokeAndWait(q);
2178                return q.result;
2179            }
2180        }
2181
2182        /**
2183         * Returns the default size of the viewport.
2184         */

2185        public Dimension2D JavaDoc getViewportSize() {
2186            if (EventQueue.isDispatchThread()) {
2187                return userAgent.getViewportSize();
2188            } else {
2189                class Query implements Runnable JavaDoc {
2190                    Dimension2D JavaDoc result;
2191                    public void run() {
2192                        result = userAgent.getViewportSize();
2193                    }
2194                }
2195                Query q = new Query();
2196                invokeAndWait(q);
2197                return q.result;
2198            }
2199        }
2200
2201        /**
2202         * Displays an error resulting from the specified Exception.
2203         */

2204        public void displayError(final Exception JavaDoc ex) {
2205            if (EventQueue.isDispatchThread()) {
2206                userAgent.displayError(ex);
2207            } else {
2208                EventQueue.invokeLater(new Runnable JavaDoc() {
2209                        public void run() {
2210                            userAgent.displayError(ex);
2211                        }
2212                    });
2213            }
2214        }
2215
2216        /**
2217         * Displays a message in the User Agent interface.
2218         */

2219        public void displayMessage(final String JavaDoc message) {
2220            if (EventQueue.isDispatchThread()) {
2221                userAgent.displayMessage(message);
2222            } else {
2223                EventQueue.invokeLater(new Runnable JavaDoc() {
2224                        public void run() {
2225                            userAgent.displayMessage(message);
2226                        }
2227                    });
2228            }
2229        }
2230
2231        /**
2232         * Shows an alert dialog box.
2233         */

2234        public void showAlert(final String JavaDoc message) {
2235            if (EventQueue.isDispatchThread()) {
2236                userAgent.showAlert(message);
2237            } else {
2238                invokeAndWait(new Runnable JavaDoc() {
2239                        public void run() {
2240                            userAgent.showAlert(message);
2241                        }
2242                    });
2243            }
2244        }
2245
2246        /**
2247         * Shows a prompt dialog box.
2248         */

2249        public String JavaDoc showPrompt(final String JavaDoc message) {
2250            if (EventQueue.isDispatchThread()) {
2251                return userAgent.showPrompt(message);
2252            } else {
2253                class Query implements Runnable JavaDoc {
2254                    String JavaDoc result;
2255                    public void run() {
2256                        result = userAgent.showPrompt(message);
2257                    }
2258                }
2259                Query q = new Query();
2260                invokeAndWait(q);
2261                return q.result;
2262            }
2263        }
2264
2265        /**
2266         * Shows a prompt dialog box.
2267         */

2268        public String JavaDoc showPrompt(final String JavaDoc message,
2269                                 final String JavaDoc defaultValue) {
2270            if (EventQueue.isDispatchThread()) {
2271                return userAgent.showPrompt(message, defaultValue);
2272            } else {
2273                class Query implements Runnable JavaDoc {
2274                    String JavaDoc result;
2275                    public void run() {
2276                        result = userAgent.showPrompt(message, defaultValue);
2277                    }
2278                }
2279                Query q = new Query();
2280                invokeAndWait(q);
2281                return q.result;
2282            }
2283        }
2284
2285        /**
2286         * Shows a confirm dialog box.
2287         */

2288        public boolean showConfirm(final String JavaDoc message) {
2289            if (EventQueue.isDispatchThread()) {
2290                return userAgent.showConfirm(message);
2291            } else {
2292                class Query implements Runnable JavaDoc {
2293                    boolean result;
2294                    public void run() {
2295                        result = userAgent.showConfirm(message);
2296                    }
2297                }
2298                Query q = new Query();
2299                invokeAndWait(q);
2300                return q.result;
2301            }
2302        }
2303
2304        /**
2305         * Returns the size of a px CSS unit in millimeters.
2306         */

2307        public float getPixelUnitToMillimeter() {
2308            if (EventQueue.isDispatchThread()) {
2309                return userAgent.getPixelUnitToMillimeter();
2310            } else {
2311                class Query implements Runnable JavaDoc {
2312                    float result;
2313                    public void run() {
2314                        result = userAgent.getPixelUnitToMillimeter();
2315                    }
2316                }
2317                Query q = new Query();
2318                invokeAndWait(q);
2319                return q.result;
2320            }
2321        }
2322
2323        /**
2324         * Returns the size of a px CSS unit in millimeters.
2325         * This will be removed after next release.
2326         * @see #getPixelUnitToMillimeter()
2327         */

2328        public float getPixelToMM() { return getPixelUnitToMillimeter(); }
2329
2330
2331        /**
2332         * Returns the default font family.
2333         */

2334        public String JavaDoc getDefaultFontFamily() {
2335            if (EventQueue.isDispatchThread()) {
2336                return userAgent.getDefaultFontFamily();
2337            } else {
2338                class Query implements Runnable JavaDoc {
2339                    String JavaDoc result;
2340                    public void run() {
2341                        result = userAgent.getDefaultFontFamily();
2342                    }
2343                }
2344                Query q = new Query();
2345                invokeAndWait(q);
2346                return q.result;
2347            }
2348        }
2349
2350        public float getMediumFontSize() {
2351            if (EventQueue.isDispatchThread()) {
2352                return userAgent.getMediumFontSize();
2353            } else {
2354                class Query implements Runnable JavaDoc {
2355                    float result;
2356                    public void run() {
2357                        result = userAgent.getMediumFontSize();
2358                    }
2359                }
2360                Query q = new Query();
2361                invokeAndWait(q);
2362                return q.result;
2363            }
2364        }
2365
2366        public float getLighterFontWeight(float f) {
2367            if (EventQueue.isDispatchThread()) {
2368                return userAgent.getLighterFontWeight(f);
2369            } else {
2370                final float ff = f;
2371                class Query implements Runnable JavaDoc {
2372                    float result;
2373                    public void run() {
2374                        result = userAgent.getLighterFontWeight(ff);
2375                    }
2376                }
2377                Query q = new Query();
2378                invokeAndWait(q);
2379                return q.result;
2380            }
2381        }
2382
2383        public float getBolderFontWeight(float f) {
2384            if (EventQueue.isDispatchThread()) {
2385                return userAgent.getBolderFontWeight(f);
2386            } else {
2387                final float ff = f;
2388                class Query implements Runnable JavaDoc {
2389                    float result;
2390                    public void run() {
2391                        result = userAgent.getBolderFontWeight(ff);
2392                    }
2393                }
2394                Query q = new Query();
2395                invokeAndWait(q);
2396                return q.result;
2397            }
2398        }
2399
2400        /**
2401         * Returns the language settings.
2402         */

2403        public String JavaDoc getLanguages() {
2404            if (EventQueue.isDispatchThread()) {
2405                return userAgent.getLanguages();
2406            } else {
2407                class Query implements Runnable JavaDoc {
2408                    String JavaDoc result;
2409                    public void run() {
2410                        result = userAgent.getLanguages();
2411                    }
2412                }
2413                Query q = new Query();
2414                invokeAndWait(q);
2415                return q.result;
2416            }
2417        }
2418
2419        /**
2420         * Returns the user stylesheet uri.
2421         * @return null if no user style sheet was specified.
2422         */

2423        public String JavaDoc getUserStyleSheetURI() {
2424            if (EventQueue.isDispatchThread()) {
2425                return userAgent.getUserStyleSheetURI();
2426            } else {
2427                class Query implements Runnable JavaDoc {
2428                    String JavaDoc result;
2429                    public void run() {
2430                        result = userAgent.getUserStyleSheetURI();
2431                    }
2432                }
2433                Query q = new Query();
2434                invokeAndWait(q);
2435                return q.result;
2436            }
2437        }
2438
2439        /**
2440         * Opens a link.
2441         * @param elt The activated link element.
2442         */

2443        public void openLink(final SVGAElement elt) {
2444            if (EventQueue.isDispatchThread()) {
2445                userAgent.openLink(elt);
2446            } else {
2447                EventQueue.invokeLater(new Runnable JavaDoc() {
2448                        public void run() {
2449                            userAgent.openLink(elt);
2450                        }
2451                    });
2452            }
2453        }
2454        
2455        /**
2456         * Informs the user agent to change the cursor.
2457         * @param cursor the new cursor
2458         */

2459        public void setSVGCursor(final Cursor JavaDoc cursor) {
2460            if (EventQueue.isDispatchThread()) {
2461                userAgent.setSVGCursor(cursor);
2462            } else {
2463                EventQueue.invokeLater(new Runnable JavaDoc() {
2464                        public void run() {
2465                            userAgent.setSVGCursor(cursor);
2466                        }
2467                    });
2468            }
2469        }
2470        
2471        /**
2472         * Informs the user agent that the text selection should be changed.
2473         * @param start The Mark for the start of the selection.
2474         * @param end The Mark for the end of the selection.
2475         */

2476        public void setTextSelection(final Mark start, final Mark end) {
2477            if (EventQueue.isDispatchThread()) {
2478                userAgent.setTextSelection(start, end);
2479            } else {
2480                EventQueue.invokeLater(new Runnable JavaDoc() {
2481                        public void run() {
2482                            userAgent.setTextSelection(start, end);
2483                        }
2484                    });
2485            }
2486        }
2487
2488        /**
2489         * Informs the user agent that the text should be deselected.
2490         */

2491        public void deselectAll() {
2492            if (EventQueue.isDispatchThread()) {
2493                userAgent.deselectAll();
2494            } else {
2495                EventQueue.invokeLater(new Runnable JavaDoc() {
2496                        public void run() {
2497                            userAgent.deselectAll();
2498                        }
2499                    });
2500            }
2501        }
2502
2503        /**
2504         * Returns the class name of the XML parser.
2505         */

2506        public String JavaDoc getXMLParserClassName() {
2507            if (EventQueue.isDispatchThread()) {
2508                return userAgent.getXMLParserClassName();
2509            } else {
2510                class Query implements Runnable JavaDoc {
2511                    String JavaDoc result;
2512                    public void run() {
2513                        result = userAgent.getXMLParserClassName();
2514                    }
2515                }
2516                Query q = new Query();
2517                invokeAndWait(q);
2518                return q.result;
2519            }
2520        }
2521
2522        /**
2523         * Returns true if the XML parser must be in validation mode, false
2524         * otherwise.
2525         */

2526        public boolean isXMLParserValidating() {
2527            if (EventQueue.isDispatchThread()) {
2528                return userAgent.isXMLParserValidating();
2529            } else {
2530                class Query implements Runnable JavaDoc {
2531                    boolean result;
2532                    public void run() {
2533                        result = userAgent.isXMLParserValidating();
2534                    }
2535                }
2536                Query q = new Query();
2537                invokeAndWait(q);
2538                return q.result;
2539            }
2540        }
2541        
2542        /**
2543         * Returns the <code>AffineTransform</code> currently
2544         * applied to the drawing by the UserAgent.
2545         */

2546        public AffineTransform JavaDoc getTransform() {
2547            if (EventQueue.isDispatchThread()) {
2548                return userAgent.getTransform();
2549            } else {
2550                class Query implements Runnable JavaDoc {
2551                    AffineTransform JavaDoc result;
2552                    public void run() {
2553                        result = userAgent.getTransform();
2554                    }
2555                }
2556                Query q = new Query();
2557                invokeAndWait(q);
2558                return q.result;
2559            }
2560        }
2561
2562        /**
2563         * Sets the <code>AffineTransform</code> to be
2564         * applied to the drawing by the UserAgent.
2565         */

2566        public void setTransform(AffineTransform JavaDoc at) {
2567            if (EventQueue.isDispatchThread()) {
2568                userAgent.setTransform(at);
2569            } else {
2570                final AffineTransform JavaDoc affine = at;
2571                class Query implements Runnable JavaDoc {
2572                    public void run() {
2573                        userAgent.setTransform(affine);
2574                    }
2575                }
2576                Query q = new Query();
2577                invokeAndWait(q);
2578            }
2579        }
2580
2581        /**
2582         * Returns this user agent's CSS media.
2583         */

2584        public String JavaDoc getMedia() {
2585            if (EventQueue.isDispatchThread()) {
2586                return userAgent.getMedia();
2587            } else {
2588                class Query implements Runnable JavaDoc {
2589                    String JavaDoc result;
2590                    public void run() {
2591                        result = userAgent.getMedia();
2592                    }
2593                }
2594                Query q = new Query();
2595                invokeAndWait(q);
2596                return q.result;
2597            }
2598        }
2599        
2600        /**
2601         * Returns this user agent's alternate style-sheet title.
2602         */

2603        public String JavaDoc getAlternateStyleSheet() {
2604            if (EventQueue.isDispatchThread()) {
2605                return userAgent.getAlternateStyleSheet();
2606            } else {
2607                class Query implements Runnable JavaDoc {
2608                    String JavaDoc result;
2609                    public void run() {
2610                        result = userAgent.getAlternateStyleSheet();
2611                    }
2612                }
2613                Query q = new Query();
2614                invokeAndWait(q);
2615                return q.result;
2616            }
2617        }
2618
2619        /**
2620         * Returns the location on the screen of the
2621         * client area in the UserAgent.
2622         */

2623        public Point JavaDoc getClientAreaLocationOnScreen() {
2624            if (EventQueue.isDispatchThread()) {
2625                return userAgent.getClientAreaLocationOnScreen();
2626            } else {
2627                class Query implements Runnable JavaDoc {
2628                    Point JavaDoc result;
2629                    public void run() {
2630                        result = userAgent.getClientAreaLocationOnScreen();
2631                    }
2632                }
2633                Query q = new Query();
2634                invokeAndWait(q);
2635                return q.result;
2636            }
2637        }
2638
2639        /**
2640         * Tells whether the given feature is supported by this
2641         * user agent.
2642         */

2643        public boolean hasFeature(final String JavaDoc s) {
2644            if (EventQueue.isDispatchThread()) {
2645                return userAgent.hasFeature(s);
2646            } else {
2647                class Query implements Runnable JavaDoc {
2648                    boolean result;
2649                    public void run() {
2650                        result = userAgent.hasFeature(s);
2651                    }
2652                }
2653                Query q = new Query();
2654                invokeAndWait(q);
2655                return q.result;
2656            }
2657        }
2658        
2659        /**
2660         * Tells whether the given extension is supported by this
2661         * user agent.
2662         */

2663        public boolean supportExtension(final String JavaDoc s) {
2664            if (EventQueue.isDispatchThread()) {
2665                return userAgent.supportExtension(s);
2666            } else {
2667                class Query implements Runnable JavaDoc {
2668                    boolean result;
2669                    public void run() {
2670                        result = userAgent.supportExtension(s);
2671                    }
2672                }
2673                Query q = new Query();
2674                invokeAndWait(q);
2675                return q.result;
2676            }
2677        }
2678
2679        /**
2680         * Lets the bridge tell the user agent that the following
2681         * extension is supported by the bridge.
2682         */

2683        public void registerExtension(final BridgeExtension ext) {
2684            if (EventQueue.isDispatchThread()) {
2685                userAgent.registerExtension(ext);
2686            } else {
2687                EventQueue.invokeLater(new Runnable JavaDoc() {
2688                        public void run() {
2689                            userAgent.registerExtension(ext);
2690                        }
2691                    });
2692            }
2693        }
2694        
2695        /**
2696         * Notifies the UserAgent that the input element
2697         * has been found in the document. This is sometimes
2698         * called, for example, to handle &lt;a&gt; or
2699         * &lt;title&gt; elements in a UserAgent-dependant
2700         * way.
2701         */

2702        public void handleElement(final Element JavaDoc elt, final Object JavaDoc data) {
2703            if (EventQueue.isDispatchThread()) {
2704                userAgent.handleElement(elt, data);
2705            } else {
2706                EventQueue.invokeLater(new Runnable JavaDoc() {
2707                        public void run() {
2708                            userAgent.handleElement(elt, data);
2709                        }
2710                    });
2711            }
2712        }
2713
2714        /**
2715         * Returns the security settings for the given script
2716         * type, script url and document url
2717         *
2718         * @param scriptType type of script, as found in the
2719         * type attribute of the &lt;script&gt; element.
2720         * @param scriptPURL url for the script, as defined in
2721         * the script's xlink:href attribute. If that
2722         * attribute was empty, then this parameter should
2723         * be null
2724         * @param docPURL url for the document into which the
2725         * script was found.
2726         */

2727        public ScriptSecurity getScriptSecurity(String JavaDoc scriptType,
2728                                                ParsedURL scriptPURL,
2729                                                ParsedURL docPURL){
2730            if (EventQueue.isDispatchThread()) {
2731                return userAgent.getScriptSecurity(scriptType,
2732                                                   scriptPURL,
2733                                                   docPURL);
2734            } else {
2735                final String JavaDoc st = scriptType;
2736                final ParsedURL sPURL= scriptPURL;
2737                final ParsedURL dPURL= docPURL;
2738                class Query implements Runnable JavaDoc {
2739                    ScriptSecurity result;
2740                    public void run() {
2741                        result = userAgent.getScriptSecurity(st, sPURL, dPURL);
2742                    }
2743                }
2744                Query q = new Query();
2745                invokeAndWait(q);
2746                return q.result;
2747            }
2748        }
2749    
2750        /**
2751         * This method throws a SecurityException if the script
2752         * of given type, found at url and referenced from docURL
2753         * should not be loaded.
2754         *
2755         * This is a convenience method to call checkLoadScript
2756         * on the ScriptSecurity strategy returned by
2757         * getScriptSecurity.
2758         *
2759         * @param scriptType type of script, as found in the
2760         * type attribute of the &lt;script&gt; element.
2761         * @param scriptPURL url for the script, as defined in
2762         * the script's xlink:href attribute. If that
2763         * attribute was empty, then this parameter should
2764         * be null
2765         * @param docPURL url for the document into which the
2766         * script was found.
2767         */

2768        public void checkLoadScript(String JavaDoc scriptType,
2769                                    ParsedURL scriptPURL,
2770                                    ParsedURL docPURL) throws SecurityException JavaDoc {
2771            if (EventQueue.isDispatchThread()) {
2772                userAgent.checkLoadScript(scriptType,
2773                                          scriptPURL,
2774                                          docPURL);
2775            } else {
2776                final String JavaDoc st = scriptType;
2777                final ParsedURL sPURL= scriptPURL;
2778                final ParsedURL dPURL= docPURL;
2779                class Query implements Runnable JavaDoc {
2780                    SecurityException JavaDoc se = null;
2781                    public void run() {
2782                        try {
2783                            userAgent.checkLoadScript(st, sPURL, dPURL);
2784                        } catch (SecurityException JavaDoc se) {
2785                            this.se = se;
2786                        }
2787                    }
2788                }
2789                Query q = new Query();
2790                invokeAndWait(q);
2791                if (q.se != null) {
2792                    q.se.fillInStackTrace();
2793                    throw q.se;
2794                }
2795            }
2796        }
2797        
2798
2799        /**
2800         * Returns the security settings for the given resource
2801         * url and document url
2802         *
2803         * @param resourcePURL url for the resource, as defined in
2804         * the resource's xlink:href attribute. If that
2805         * attribute was empty, then this parameter should
2806         * be null
2807         * @param docPURL url for the document into which the
2808         * resource was found.
2809         */

2810        public ExternalResourceSecurity
2811            getExternalResourceSecurity(ParsedURL resourcePURL,
2812                                        ParsedURL docPURL){
2813            if (EventQueue.isDispatchThread()) {
2814                return userAgent.getExternalResourceSecurity(resourcePURL,
2815                                                             docPURL);
2816            } else {
2817                final ParsedURL rPURL= resourcePURL;
2818                final ParsedURL dPURL= docPURL;
2819                class Query implements Runnable JavaDoc {
2820                    ExternalResourceSecurity result;
2821                    public void run() {
2822                        result = userAgent.getExternalResourceSecurity(rPURL, dPURL);
2823                    }
2824                }
2825                Query q = new Query();
2826                invokeAndWait(q);
2827                return q.result;
2828            }
2829        }
2830    
2831        /**
2832         * This method throws a SecurityException if the resource
2833         * found at url and referenced from docURL
2834         * should not be loaded.
2835         *
2836         * This is a convenience method to call checkLoadExternalResource
2837         * on the ExternalResourceSecurity strategy returned by
2838         * getExternalResourceSecurity.
2839         *
2840         * @param resourceURL url for the resource, as defined in
2841         * the resource's xlink:href attribute. If that
2842         * attribute was empty, then this parameter should
2843         * be null
2844         * @param docURL url for the document into which the
2845         * resource was found.
2846         */

2847        public void
2848            checkLoadExternalResource(ParsedURL resourceURL,
2849                                      ParsedURL docURL) throws SecurityException JavaDoc {
2850            if (EventQueue.isDispatchThread()) {
2851                userAgent.checkLoadExternalResource(resourceURL,
2852                                                    docURL);
2853            } else {
2854                final ParsedURL rPURL= resourceURL;
2855                final ParsedURL dPURL= docURL;
2856                class Query implements Runnable JavaDoc {
2857                    SecurityException JavaDoc se;
2858                    public void run() {
2859                        try {
2860                            userAgent.checkLoadExternalResource(rPURL, dPURL);
2861                        } catch (SecurityException JavaDoc se) {
2862                            this.se = se;
2863                        }
2864                    }
2865                }
2866                Query q = new Query();
2867                invokeAndWait(q);
2868                if (q.se != null) {
2869                    q.se.fillInStackTrace();
2870                    throw q.se;
2871                }
2872            }
2873        }
2874        
2875        /**
2876         * Invokes the given runnable from the event thread, and wait
2877         * for the run method to terminate.
2878         */

2879        protected void invokeAndWait(Runnable JavaDoc r) {
2880            try {
2881                EventQueue.invokeAndWait(r);
2882            } catch (Exception JavaDoc e) {
2883            }
2884        }
2885    }
2886
2887    /**
2888     * To hide the user-agent methods.
2889     */

2890    protected class BridgeUserAgent implements UserAgent {
2891
2892        /**
2893         * Creates a new user agent.
2894         */

2895        protected BridgeUserAgent() {
2896        }
2897
2898        /**
2899         * Returns the default size of the viewport of this user agent (0, 0).
2900         */

2901        public Dimension2D JavaDoc getViewportSize() {
2902            return getSize();
2903        }
2904
2905        /**
2906         * Returns the <code>EventDispatcher</code> used by the
2907         * <code>UserAgent</code> to dispatch events on GVT.
2908         */

2909        public EventDispatcher getEventDispatcher() {
2910            return JSVGComponent.this.eventDispatcher;
2911        }
2912
2913        /**
2914         * Displays an error message in the User Agent interface.
2915         */

2916        public void displayError(String JavaDoc message) {
2917            if (svgUserAgent != null) {
2918                svgUserAgent.displayError(message);
2919            }
2920        }
2921
2922        /**
2923         * Displays an error resulting from the specified Exception.
2924         */

2925        public void displayError(Exception JavaDoc ex) {
2926            if (svgUserAgent != null) {
2927                svgUserAgent.displayError(ex);
2928            }
2929        }
2930
2931        /**
2932         * Displays a message in the User Agent interface.
2933         */

2934        public void displayMessage(String JavaDoc message) {
2935            if (svgUserAgent != null) {
2936                svgUserAgent.displayMessage(message);
2937            }
2938        }
2939
2940        /**
2941         * Shows an alert dialog box.
2942         */

2943        public void showAlert(String JavaDoc message) {
2944            if (svgUserAgent != null) {
2945                svgUserAgent.showAlert(message);
2946                return;
2947            }
2948            JSVGComponent.this.showAlert(message);
2949        }
2950
2951        /**
2952         * Shows a prompt dialog box.
2953         */

2954        public String JavaDoc showPrompt(String JavaDoc message) {
2955            if (svgUserAgent != null) {
2956                return svgUserAgent.showPrompt(message);
2957            }
2958            return JSVGComponent.this.showPrompt(message);
2959        }
2960
2961        /**
2962         * Shows a prompt dialog box.
2963         */

2964        public String JavaDoc showPrompt(String JavaDoc message, String JavaDoc defaultValue) {
2965            if (svgUserAgent != null) {
2966                return svgUserAgent.showPrompt(message, defaultValue);
2967            }
2968            return JSVGComponent.this.showPrompt(message, defaultValue);
2969        }
2970
2971        /**
2972         * Shows a confirm dialog box.
2973         */

2974        public boolean showConfirm(String JavaDoc message) {
2975            if (svgUserAgent != null) {
2976                return svgUserAgent.showConfirm(message);
2977            }
2978            return JSVGComponent.this.showConfirm(message);
2979        }
2980
2981        /**
2982         * Returns the size of a px CSS unit in millimeters.
2983         */

2984        public float getPixelUnitToMillimeter() {
2985            if (svgUserAgent != null) {
2986                return svgUserAgent.getPixelUnitToMillimeter();
2987            }
2988            return 0.264583333333333333333f; // 96 dpi
2989
}
2990
2991        /**
2992         * Returns the size of a px CSS unit in millimeters.
2993         * This will be removed after next release.
2994         * @see #getPixelUnitToMillimeter()
2995         */

2996        public float getPixelToMM() { return getPixelUnitToMillimeter(); }
2997
2998        /**
2999         * Returns the default font family.
3000         */

3001        public String JavaDoc getDefaultFontFamily() {
3002            if (svgUserAgent != null) {
3003                return svgUserAgent.getDefaultFontFamily();
3004            }
3005            return "Arial, Helvetica, sans-serif";
3006        }
3007
3008        /**
3009         * Returns the medium font size.
3010         */

3011        public float getMediumFontSize() {
3012            if (svgUserAgent != null) {
3013                return svgUserAgent.getMediumFontSize();
3014            }
3015            // 9pt (72pt = 1in)
3016
return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
3017        }
3018
3019        /**
3020         * Returns a lighter font-weight.
3021         */

3022        public float getLighterFontWeight(float f) {
3023            if (svgUserAgent != null) {
3024                return svgUserAgent.getLighterFontWeight(f);
3025            }
3026            // Round f to nearest 100...
3027
int weight = ((int)((f+50)/100))*100;
3028            switch (weight) {
3029            case 100: return 100;
3030            case 200: return 100;
3031            case 300: return 200;
3032            case 400: return 300;
3033            case 500: return 400;
3034            case 600: return 400;
3035            case 700: return 400;
3036            case 800: return 400;
3037            case 900: return 400;
3038            default:
3039                throw new IllegalArgumentException JavaDoc("Bad Font Weight: " + f);
3040            }
3041        }
3042
3043        /**
3044         * Returns a bolder font-weight.
3045         */

3046        public float getBolderFontWeight(float f) {
3047            if (svgUserAgent != null) {
3048                return svgUserAgent.getBolderFontWeight(f);
3049            }
3050            // Round f to nearest 100...
3051
int weight = ((int)((f+50)/100))*100;
3052            switch (weight) {
3053            case 100: return 600;
3054            case 200: return 600;
3055            case 300: return 600;
3056            case 400: return 600;
3057            case 500: return 600;
3058            case 600: return 700;
3059            case 700: return 800;
3060            case 800: return 900;
3061            case 900: return 900;
3062            default:
3063                throw new IllegalArgumentException JavaDoc("Bad Font Weight: " + f);
3064            }
3065        }
3066
3067        /**
3068         * Returns the language settings.
3069         */

3070        public String JavaDoc getLanguages() {
3071            if (svgUserAgent != null) {
3072                return svgUserAgent.getLanguages();
3073            }
3074            return "en";
3075        }
3076
3077        /**
3078         * Returns the user stylesheet uri.
3079         * @return null if no user style sheet was specified.
3080         */

3081        public String JavaDoc getUserStyleSheetURI() {
3082            if (svgUserAgent != null) {
3083                return svgUserAgent.getUserStyleSheetURI();
3084            }
3085            return null;
3086        }
3087
3088        /**
3089         * Opens a link.
3090         * @param elt The activated link element.
3091         */

3092        public void openLink(SVGAElement elt) {
3093            String JavaDoc show = XLinkSupport.getXLinkShow(elt);
3094            String JavaDoc href = XLinkSupport.getXLinkHref(elt);
3095            if (show.equals("new")) {
3096                fireLinkActivatedEvent(elt, href);
3097                if (svgUserAgent != null) {
3098                    String JavaDoc oldURI = svgDocument.getURL();
3099                    ParsedURL newURI = null;
3100                    // if the anchor element is in an external resource
3101
if (elt.getOwnerDocument() != svgDocument) {
3102                        SVGDocument doc = (SVGDocument)elt.getOwnerDocument();
3103                        href = new ParsedURL(doc.getURL(), href).toString();
3104                    }
3105                    newURI = new ParsedURL(oldURI, href);
3106                    href = newURI.toString();
3107                    svgUserAgent.openLink(href, true);
3108                } else {
3109                    JSVGComponent.this.loadSVGDocument(href);
3110                }
3111                return;
3112            }
3113
3114            // Always use anchor element's document for base URI,
3115
// for when it comes from an external resource.
3116
ParsedURL newURI = new ParsedURL
3117                (((SVGDocument)elt.getOwnerDocument()).getURL(), href);
3118
3119            // replace href with a fully resolved URI.
3120
href = newURI.toString();
3121
3122            // Avoid reloading if possible.
3123
if (svgDocument != null) {
3124
3125                ParsedURL oldURI = new ParsedURL(svgDocument.getURL());
3126                // Check if they reference the same file.
3127
if (newURI.sameFile(oldURI)) {
3128                    // They do, see if it's a new Fragment Ident.
3129
String JavaDoc s = newURI.getRef();
3130                    if ((fragmentIdentifier != s) &&
3131                        ((s == null) || (!s.equals(fragmentIdentifier)))) {
3132                        // It is, so update rendering transform.
3133
fragmentIdentifier = s;
3134                        if (computeRenderingTransform())
3135                            scheduleGVTRendering();
3136                    }
3137                    // Let every one know the link fired (but don't
3138
// load doc, it's already loaded.).
3139
fireLinkActivatedEvent(elt, href);
3140                    return;
3141                }
3142            }
3143                
3144            fireLinkActivatedEvent(elt, href);
3145            if (svgUserAgent != null) {
3146                svgUserAgent.openLink(href, false);
3147            } else {
3148                JSVGComponent.this.loadSVGDocument(href);
3149            }
3150        }
3151
3152        /**
3153         * Fires a LinkActivatedEvent.
3154         */

3155        protected void fireLinkActivatedEvent(SVGAElement elt, String JavaDoc href) {
3156            Object JavaDoc[] ll = linkActivationListeners.toArray();
3157
3158            if (ll.length > 0) {
3159                LinkActivationEvent ev;
3160                ev = new LinkActivationEvent(JSVGComponent.this, elt, href);
3161
3162                for (int i = 0; i < ll.length; i++) {
3163                    LinkActivationListener l = (LinkActivationListener)ll[i];
3164                    l.linkActivated(ev);
3165                }
3166            }
3167        }
3168
3169        /**
3170         * Informs the user agent to change the cursor.
3171         * @param cursor the new cursor
3172         */

3173        public void setSVGCursor(Cursor JavaDoc cursor) {
3174            if (cursor != JSVGComponent.this.getCursor())
3175                JSVGComponent.this.setCursor(cursor);
3176        }
3177
3178        /**
3179         * Informs the user agent that the text selection has changed.
3180         * @param start The Mark for the start of the selection.
3181         * @param end The Mark for the end of the selection.
3182         */

3183        public void setTextSelection(Mark start, Mark end) {
3184            JSVGComponent.this.select(start, end);
3185        }
3186
3187        /**
3188         * Informs the user agent that the text selection should be
3189         * cleared.
3190         */

3191        public void deselectAll() {
3192            JSVGComponent.this.deselectAll();
3193        }
3194
3195        /**
3196         * Returns the class name of the XML parser.
3197         */

3198        public String JavaDoc getXMLParserClassName() {
3199            if (svgUserAgent != null) {
3200                return svgUserAgent.getXMLParserClassName();
3201            }
3202            return XMLResourceDescriptor.getXMLParserClassName();
3203        }
3204
3205    /**
3206     * Returns true if the XML parser must be in validation mode, false
3207     * otherwise depending on the SVGUserAgent.
3208     */

3209    public boolean isXMLParserValidating() {
3210            if (svgUserAgent != null) {
3211                return svgUserAgent.isXMLParserValidating();
3212            }
3213            return false;
3214    }
3215    
3216        /**
3217         * Returns the <code>AffineTransform</code> currently
3218         * applied to the drawing by the UserAgent.
3219         */

3220        public AffineTransform JavaDoc getTransform() {
3221            return JSVGComponent.this.renderingTransform;
3222        }
3223
3224        /**
3225         * Sets the <code>AffineTransform</code> to be
3226         * applied to the drawing by the UserAgent.
3227         */

3228        public void setTransform(AffineTransform JavaDoc at) {
3229            JSVGComponent.this.setRenderingTransform(at);
3230        }
3231
3232        /**
3233         * Returns this user agent's CSS media.
3234         */

3235        public String JavaDoc getMedia() {
3236            if (svgUserAgent != null) {
3237                return svgUserAgent.getMedia();
3238            }
3239            return "screen";
3240        }
3241
3242        /**
3243         * Returns this user agent's alternate style-sheet title.
3244         */

3245        public String JavaDoc getAlternateStyleSheet() {
3246            if (svgUserAgent != null) {
3247                return svgUserAgent.getAlternateStyleSheet();
3248            }
3249            return null;
3250        }
3251
3252        /**
3253         * Returns the location on the screen of the
3254         * client area in the UserAgent.
3255         */

3256        public Point JavaDoc getClientAreaLocationOnScreen() {
3257            return getLocationOnScreen();
3258        }
3259
3260        /**
3261         * Tells whether the given feature is supported by this
3262         * user agent.
3263         */

3264        public boolean hasFeature(String JavaDoc s) {
3265            return FEATURES.contains(s);
3266        }
3267
3268        protected Map JavaDoc extensions = new HashMap JavaDoc();
3269
3270        /**
3271         * Tells whether the given extension is supported by this
3272         * user agent.
3273         */

3274        public boolean supportExtension(String JavaDoc s) {
3275            if ((svgUserAgent != null) &&
3276                (svgUserAgent.supportExtension(s)))
3277                return true;
3278
3279            return extensions.containsKey(s);
3280        }
3281
3282        /**
3283         * Lets the bridge tell the user agent that the following
3284         * extension is supported by the bridge.
3285         */

3286        public void registerExtension(BridgeExtension ext) {
3287            Iterator JavaDoc i = ext.getImplementedExtensions();
3288            while (i.hasNext())
3289                extensions.put(i.next(), ext);
3290        }
3291
3292
3293        /**
3294         * Notifies the UserAgent that the input element
3295         * has been found in the document. This is sometimes
3296         * called, for example, to handle &lt;a&gt; or
3297         * &lt;title&gt; elements in a UserAgent-dependant
3298         * way.
3299         */

3300        public void handleElement(Element JavaDoc elt, Object JavaDoc data) {
3301            if (svgUserAgent != null) {
3302                svgUserAgent.handleElement(elt, data);
3303            }
3304        }
3305
3306        /**
3307         * Returns the security settings for the given script
3308         * type, script url and document url
3309         *
3310         * @param scriptType type of script, as found in the
3311         * type attribute of the &lt;script&gt; element.
3312         * @param scriptURL url for the script, as defined in
3313         * the script's xlink:href attribute. If that
3314         * attribute was empty, then this parameter should
3315         * be null
3316         * @param docURL url for the document into which the
3317         * script was found.
3318         */

3319        public ScriptSecurity getScriptSecurity(String JavaDoc scriptType,
3320                                                ParsedURL scriptURL,
3321                                                ParsedURL docURL){
3322            if (svgUserAgent != null){
3323                return svgUserAgent.getScriptSecurity(scriptType,
3324                                                      scriptURL,
3325                                                      docURL);
3326            } else {
3327                return new DefaultScriptSecurity(scriptType,
3328                                                 scriptURL,
3329                                                 docURL);
3330            }
3331        }
3332    
3333        /**
3334         * This method throws a SecurityException if the script
3335         * of given type, found at url and referenced from docURL
3336         * should not be loaded.
3337         *
3338         * This is a convenience method to call checkLoadScript
3339         * on the ScriptSecurity strategy returned by
3340         * getScriptSecurity.
3341         *
3342         * @param scriptType type of script, as found in the
3343         * type attribute of the &lt;script&gt; element.
3344         * @param scriptURL url for the script, as defined in
3345         * the script's xlink:href attribute. If that
3346         * attribute was empty, then this parameter should
3347         * be null
3348         * @param docURL url for the document into which the
3349         * script was found.
3350         */

3351        public void checkLoadScript(String JavaDoc scriptType,
3352                                    ParsedURL scriptURL,
3353                                    ParsedURL docURL) throws SecurityException JavaDoc {
3354            if (svgUserAgent != null) {
3355                svgUserAgent.checkLoadScript(scriptType,
3356                                             scriptURL,
3357                                             docURL);
3358            } else {
3359                ScriptSecurity s = getScriptSecurity(scriptType,
3360                                                     scriptURL,
3361                                                     docURL);
3362                if (s != null) {
3363                    s.checkLoadScript();
3364                }
3365            }
3366        }
3367        
3368        /**
3369         * Returns the security settings for the given
3370         * resource url and document url
3371         *
3372         * @param resourceURL url for the script, as defined in
3373         * the resource's xlink:href attribute. If that
3374         * attribute was empty, then this parameter should
3375         * be null
3376         * @param docURL url for the document into which the
3377         * script was found.
3378         */

3379        public ExternalResourceSecurity
3380            getExternalResourceSecurity(ParsedURL resourceURL,
3381                                        ParsedURL docURL){
3382            if (svgUserAgent != null){
3383                return svgUserAgent.getExternalResourceSecurity(resourceURL,
3384                                                                docURL);
3385            } else {
3386                return new RelaxedExternalResourceSecurity(resourceURL,
3387                                                           docURL);
3388            }
3389        }
3390    
3391        /**
3392         * This method throws a SecurityException if the resource
3393         * found at url and referenced from docURL
3394         * should not be loaded.
3395         *
3396         * This is a convenience method to call checkLoadExternalResource
3397         * on the ExternalResourceSecurity strategy returned by
3398         * getExternalResourceSecurity.
3399         *
3400         * @param resourceURL url for the resource, as defined in
3401         * the resource's xlink:href attribute. If that
3402         * attribute was empty, then this parameter should
3403         * be null
3404         * @param docURL url for the document into which the
3405         * resource was found.
3406         */

3407        public void
3408            checkLoadExternalResource(ParsedURL resourceURL,
3409                                      ParsedURL docURL) throws SecurityException JavaDoc {
3410            if (svgUserAgent != null) {
3411                svgUserAgent.checkLoadExternalResource(resourceURL,
3412                                                       docURL);
3413            } else {
3414                ExternalResourceSecurity s
3415                    = getExternalResourceSecurity(resourceURL, docURL);
3416                
3417                if (s != null) {
3418                    s.checkLoadExternalResource();
3419                }
3420            }
3421        }
3422        
3423
3424    }
3425
3426    protected final static Set JavaDoc FEATURES = new HashSet JavaDoc();
3427    static {
3428        FEATURES.add(SVGConstants.SVG_ORG_W3C_SVG_FEATURE);
3429        FEATURES.add(SVGConstants.SVG_ORG_W3C_SVG_LANG_FEATURE);
3430        FEATURES.add(SVGConstants.SVG_ORG_W3C_SVG_STATIC_FEATURE);
3431    }
3432}
3433
Popular Tags