KickJava   Java API By Example, From Geeks To Geeks.

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


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

18 package org.apache.batik.bridge;
19
20 import java.awt.Dimension JavaDoc;
21 import java.awt.RenderingHints JavaDoc;
22 import java.awt.Shape JavaDoc;
23 import java.awt.geom.AffineTransform JavaDoc;
24 import java.awt.geom.NoninvertibleTransformException JavaDoc;
25 import java.awt.geom.Rectangle2D JavaDoc;
26 import java.text.AttributedCharacterIterator JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Set JavaDoc;
31
32 import org.apache.batik.dom.svg.SVGSVGContext;
33 import org.apache.batik.dom.svg.SVGContext;
34 import org.apache.batik.dom.svg.SVGOMElement;
35 import org.apache.batik.ext.awt.image.renderable.ClipRable8Bit;
36 import org.apache.batik.ext.awt.image.renderable.Filter;
37 import org.apache.batik.gvt.CanvasGraphicsNode;
38 import org.apache.batik.gvt.CompositeGraphicsNode;
39 import org.apache.batik.gvt.GraphicsNode;
40 import org.apache.batik.gvt.ShapeNode;
41 import org.apache.batik.gvt.TextNode;
42 import org.apache.batik.gvt.font.GVTGlyphVector;
43 import org.apache.batik.gvt.renderer.StrokingTextPainter;
44 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
45 import org.apache.batik.gvt.text.TextSpanLayout;
46 import org.apache.batik.util.SVGConstants;
47 import org.w3c.dom.Element JavaDoc;
48 import org.w3c.dom.Node JavaDoc;
49 import org.w3c.dom.events.MutationEvent JavaDoc;
50 import org.w3c.dom.svg.SVGDocument;
51 import org.w3c.dom.svg.SVGSVGElement;
52 import org.w3c.dom.svg.SVGRect;
53
54 /**
55  * Bridge class for the <svg> element.
56  *
57  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
58  * @version $Id: SVGSVGElementBridge.java,v 1.47 2005/03/27 08:58:30 cam Exp $
59  */

60 public class SVGSVGElementBridge
61     extends SVGGElementBridge
62     implements SVGSVGContext {
63
64     /**
65      * Constructs a new bridge for the &lt;svg> element.
66      */

67     public SVGSVGElementBridge() {}
68
69     /**
70      * Returns 'svg'.
71      */

72     public String JavaDoc getLocalName() {
73         return SVG_SVG_TAG;
74     }
75
76     /**
77      * Returns a new instance of this bridge.
78      */

79     public Bridge getInstance(){
80         return new SVGSVGElementBridge();
81     }
82
83     /**
84      * Creates a <tt>CompositeGraphicsNode</tt>.
85      */

86     protected GraphicsNode instantiateGraphicsNode() {
87         return new CanvasGraphicsNode();
88     }
89
90     /**
91      * Creates a <tt>GraphicsNode</tt> according to the specified parameters.
92      *
93      * @param ctx the bridge context to use
94      * @param e the element that describes the graphics node to build
95      * @return a graphics node that represents the specified element
96      */

97     public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
98     // 'requiredFeatures', 'requiredExtensions' and 'systemLanguage'
99
if (!SVGUtilities.matchUserAgent(e, ctx.getUserAgent())) {
100         return null;
101     }
102
103         CanvasGraphicsNode cgn;
104         cgn = (CanvasGraphicsNode)instantiateGraphicsNode();
105
106         UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);
107         String JavaDoc s;
108
109         // In some cases we converted document fragments which didn't
110
// have a parent SVG element, this check makes sure only the
111
// real root of the SVG Document tries to do negotiation with
112
// the UA.
113
SVGDocument doc = (SVGDocument)e.getOwnerDocument();
114         boolean isOutermost = (doc.getRootElement() == e);
115         float x = 0;
116         float y = 0;
117         // x and y have no meaning on the outermost 'svg' element
118
if (!isOutermost) {
119             // 'x' attribute - default is 0
120
s = e.getAttributeNS(null, SVG_X_ATTRIBUTE);
121             if (s.length() != 0) {
122                 x = UnitProcessor.svgHorizontalCoordinateToUserSpace
123                     (s, SVG_X_ATTRIBUTE, uctx);
124             }
125             // 'y' attribute - default is 0
126
s = e.getAttributeNS(null, SVG_Y_ATTRIBUTE);
127             if (s.length() != 0) {
128                 y = UnitProcessor.svgVerticalCoordinateToUserSpace
129                     (s, SVG_Y_ATTRIBUTE, uctx);
130             }
131         }
132
133         // 'width' attribute - default is 100%
134
s = e.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
135         if (s.length() == 0) {
136             s = SVG_SVG_WIDTH_DEFAULT_VALUE;
137         }
138         float w = UnitProcessor.svgHorizontalLengthToUserSpace
139             (s, SVG_WIDTH_ATTRIBUTE, uctx);
140
141         // 'height' attribute - default is 100%
142
s = e.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
143         if (s.length() == 0) {
144             s = SVG_SVG_HEIGHT_DEFAULT_VALUE;
145         }
146         float h = UnitProcessor.svgVerticalLengthToUserSpace
147             (s, SVG_HEIGHT_ATTRIBUTE, uctx);
148
149         // 'visibility'
150
cgn.setVisible(CSSUtilities.convertVisibility(e));
151
152         // 'viewBox' and "preserveAspectRatio' attributes
153
AffineTransform JavaDoc viewingTransform =
154             ViewBox.getPreserveAspectRatioTransform(e, w, h);
155
156         float actualWidth = w;
157         float actualHeight = h;
158         try {
159             AffineTransform JavaDoc vtInv = viewingTransform.createInverse();
160             actualWidth = (float) (w*vtInv.getScaleX());
161             actualHeight = (float) (h*vtInv.getScaleY());
162         } catch (NoninvertibleTransformException JavaDoc ex) {}
163
164         AffineTransform JavaDoc positionTransform =
165             AffineTransform.getTranslateInstance(x, y);
166         // The outermost preserveAspectRatio matrix is set by the user
167
// agent, so we don't need to set the transform for outermost svg
168
if (!isOutermost) {
169             // X & Y are ignored on outermost SVG.
170
cgn.setPositionTransform(positionTransform);
171         } else if (doc == ctx.getDocument()) {
172             // <!> FIXME: hack to compute the original document's size
173
ctx.setDocumentSize(new Dimension JavaDoc((int)(w+0.5f), (int)(h+0.5f)));
174         }
175         // Set the viewing transform, this is often updated when the
176
// component prepares for rendering.
177
cgn.setViewingTransform(viewingTransform);
178
179         // 'overflow' and 'clip'
180
Shape JavaDoc clip = null;
181         if (CSSUtilities.convertOverflow(e)) { // overflow:hidden
182
float [] offsets = CSSUtilities.convertClip(e);
183             if (offsets == null) { // clip:auto
184
clip = new Rectangle2D.Float JavaDoc(x, y, w, h);
185             } else { // clip:rect(<x> <y> <w> <h>)
186
// offsets[0] = top
187
// offsets[1] = right
188
// offsets[2] = bottom
189
// offsets[3] = left
190
clip = new Rectangle2D.Float JavaDoc(x+offsets[3],
191                                              y+offsets[0],
192                                              w-offsets[1]-offsets[3],
193                                              h-offsets[2]-offsets[0]);
194             }
195         }
196
197         if (clip != null) {
198             try {
199                 AffineTransform JavaDoc at = new AffineTransform JavaDoc(positionTransform);
200                 at.concatenate(viewingTransform);
201                 at = at.createInverse(); // clip in user space
202
clip = at.createTransformedShape(clip);
203                 Filter filter = cgn.getGraphicsNodeRable(true);
204                 cgn.setClip(new ClipRable8Bit(filter, clip));
205             } catch (NoninvertibleTransformException JavaDoc ex) {}
206         }
207         RenderingHints JavaDoc hints = null;
208         hints = CSSUtilities.convertColorRendering(e, hints);
209         if (hints != null)
210             cgn.setRenderingHints(hints);
211
212         // 'enable-background'
213
Rectangle2D JavaDoc r = CSSUtilities.convertEnableBackground(e);
214         if (r != null) {
215             cgn.setBackgroundEnable(r);
216         }
217
218         ctx.openViewport
219             (e, new SVGSVGElementViewport(actualWidth,
220                                           actualHeight));
221         return cgn;
222     }
223
224     /**
225      * Builds using the specified BridgeContext and element, the
226      * specified graphics node.
227      *
228      * @param ctx the bridge context to use
229      * @param e the element that describes the graphics node to build
230      * @param node the graphics node to build
231      */

232     public void buildGraphicsNode(BridgeContext ctx,
233                                   Element e,
234                                   GraphicsNode node) {
235
236         // 'opacity'
237
node.setComposite(CSSUtilities.convertOpacity(e));
238         // 'filter'
239
node.setFilter(CSSUtilities.convertFilter(e, node, ctx));
240         // 'mask'
241
node.setMask(CSSUtilities.convertMask(e, node, ctx));
242         // 'pointer-events'
243
node.setPointerEventType(CSSUtilities.convertPointerEvents(e));
244
245         initializeDynamicSupport(ctx, e, node);
246
247         ctx.closeViewport(e);
248     }
249
250     // BridgeUpdateHandler implementation //////////////////////////////////
251

252     /**
253      * Disposes this BridgeUpdateHandler and releases all resources.
254      */

255     public void dispose() {
256         ctx.removeViewport(e);
257         super.dispose();
258     }
259
260     /**
261      * Invoked when an MutationEvent of type 'DOMAttrModified' is fired.
262      */

263     public void handleDOMAttrModifiedEvent(MutationEvent JavaDoc evt) {
264         // Don't call 'super' because there is no 'transform'
265
// attribute on <svg>
266
String JavaDoc attrName = evt.getAttrName();
267         boolean rebuild = false;
268         if (attrName.equals(SVG_WIDTH_ATTRIBUTE) ||
269             attrName.equals(SVG_HEIGHT_ATTRIBUTE) ) {
270             rebuild = true;
271         } else if (attrName.equals(SVG_X_ATTRIBUTE) ||
272                    attrName.equals(SVG_Y_ATTRIBUTE)) {
273             SVGDocument doc = (SVGDocument)e.getOwnerDocument();
274             boolean isOutermost = (doc.getRootElement() == e);
275             if (!isOutermost) {
276                 // X & Y are ignored on outermost SVG.
277
float x = 0;
278                 float y = 0;
279                 UnitProcessor.Context uctx;
280                 uctx = UnitProcessor.createContext(ctx, e);
281                 // 'x' attribute - default is 0
282
String JavaDoc s = e.getAttributeNS(null, SVG_X_ATTRIBUTE);
283                 if (s.length() != 0) {
284                     x = UnitProcessor.svgHorizontalCoordinateToUserSpace
285                         (s, SVG_X_ATTRIBUTE, uctx);
286                 }
287                 // 'y' attribute - default is 0
288
s = e.getAttributeNS(null, SVG_Y_ATTRIBUTE);
289                 if (s.length() != 0) {
290                     y = UnitProcessor.svgVerticalCoordinateToUserSpace
291                         (s, SVG_Y_ATTRIBUTE, uctx);
292                 }
293
294                 AffineTransform JavaDoc positionTransform =
295                     AffineTransform.getTranslateInstance(x, y);
296                 CanvasGraphicsNode cgn;
297                 cgn = (CanvasGraphicsNode)node;
298
299                 cgn.setPositionTransform(positionTransform);
300             }
301         } else if (attrName.equals(SVG_VIEW_BOX_ATTRIBUTE) ||
302                    attrName.equals(SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE)) {
303             SVGDocument doc = (SVGDocument)e.getOwnerDocument();
304             boolean isOutermost = (doc.getRootElement() == e);
305
306             String JavaDoc s;
307             UnitProcessor.Context uctx;
308             uctx = UnitProcessor.createContext(ctx, e);
309             // X & Y are ignored on outermost SVG.
310
float x = 0;
311             float y = 0;
312             if (!isOutermost) {
313                 // 'x' attribute - default is 0
314
s = e.getAttributeNS(null, SVG_X_ATTRIBUTE);
315                 if (s.length() != 0) {
316                     x = UnitProcessor.svgHorizontalCoordinateToUserSpace
317                         (s, SVG_X_ATTRIBUTE, uctx);
318                 }
319                 // 'y' attribute - default is 0
320
s = e.getAttributeNS(null, SVG_Y_ATTRIBUTE);
321                 if (s.length() != 0) {
322                     y = UnitProcessor.svgVerticalCoordinateToUserSpace
323                         (s, SVG_Y_ATTRIBUTE, uctx);
324                 }
325             }
326             
327             // 'width' attribute - default is 100%
328
s = e.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
329             if (s.length() == 0) {
330                 s = SVG_SVG_WIDTH_DEFAULT_VALUE;
331             }
332             float w = UnitProcessor.svgHorizontalLengthToUserSpace
333                 (s, SVG_WIDTH_ATTRIBUTE, uctx);
334             
335             // 'height' attribute - default is 100%
336
s = e.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
337             if (s.length() == 0) {
338                 s = SVG_SVG_HEIGHT_DEFAULT_VALUE;
339             }
340             float h = UnitProcessor.svgVerticalLengthToUserSpace
341                 (s, SVG_HEIGHT_ATTRIBUTE, uctx);
342             
343             CanvasGraphicsNode cgn;
344             cgn = (CanvasGraphicsNode)node;
345             
346             // 'viewBox' and "preserveAspectRatio' attributes
347
AffineTransform JavaDoc newVT =
348                 ViewBox.getPreserveAspectRatioTransform(e, w, h);
349             AffineTransform JavaDoc oldVT = cgn.getViewingTransform();
350             if ((newVT.getScaleX() != oldVT.getScaleX()) ||
351                 (newVT.getScaleY() != oldVT.getScaleY()) ||
352                 (newVT.getShearX() != oldVT.getShearX()) ||
353                 (newVT.getShearY() != oldVT.getShearY()))
354                 rebuild = true;
355             else {
356                 // Only differs in translate.
357
cgn.setViewingTransform(newVT);
358                 
359                 // 'overflow' and 'clip'
360
Shape JavaDoc clip = null;
361                 if (CSSUtilities.convertOverflow(e)) { // overflow:hidden
362
float [] offsets = CSSUtilities.convertClip(e);
363                     if (offsets == null) { // clip:auto
364
clip = new Rectangle2D.Float JavaDoc(x, y, w, h);
365                     } else { // clip:rect(<x> <y> <w> <h>)
366
// offsets[0] = top
367
// offsets[1] = right
368
// offsets[2] = bottom
369
// offsets[3] = left
370
clip = new Rectangle2D.Float JavaDoc(x+offsets[3],
371                                                      y+offsets[0],
372                                                      w-offsets[1]-offsets[3],
373                                                      h-offsets[2]-offsets[0]);
374                     }
375                 }
376                 
377                 if (clip != null) {
378                     try {
379                         AffineTransform JavaDoc at;
380                         at = cgn.getPositionTransform();
381                         at = new AffineTransform JavaDoc(at);
382                         at.concatenate(newVT);
383                         at = at.createInverse(); // clip in user space
384
clip = at.createTransformedShape(clip);
385                         Filter filter = cgn.getGraphicsNodeRable(true);
386                         cgn.setClip(new ClipRable8Bit(filter, clip));
387                     } catch (NoninvertibleTransformException JavaDoc ex) {}
388                 }
389             }
390         }
391
392         if (rebuild) {
393             CompositeGraphicsNode gn = node.getParent();
394             gn.remove(node);
395             disposeTree(e);
396
397             handleElementAdded(gn, e.getParentNode(), e);
398         }
399     }
400
401     /**
402      * A viewport defined an &lt;svg> element.
403      */

404     public static class SVGSVGElementViewport implements Viewport {
405         private float width;
406         private float height;
407
408         /**
409          * Constructs a new viewport with the specified <tt>SVGSVGElement</tt>.
410          * @param w the width of the viewport
411          * @param h the height of the viewport
412          */

413         public SVGSVGElementViewport(float w, float h) {
414             this.width = w;
415             this.height = h;
416         }
417
418         /**
419          * Returns the width of this viewport.
420          */

421         public float getWidth(){
422             return width;
423         }
424
425         /**
426          * Returns the height of this viewport.
427          */

428         public float getHeight(){
429             return height;
430         }
431     }
432
433     public static final
434         AttributedCharacterIterator.Attribute JavaDoc TEXT_COMPOUND_DELIMITER
435         = GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER;
436
437     public List JavaDoc getIntersectionList(SVGRect svgRect, Element end) {
438         List JavaDoc ret = new ArrayList JavaDoc();
439         Rectangle2D JavaDoc rect = new Rectangle2D.Float JavaDoc(svgRect.getX(),
440                                                  svgRect.getY(),
441                                                  svgRect.getWidth(),
442                                                  svgRect.getHeight());
443
444         GraphicsNode svgGN = ctx.getGraphicsNode(e);
445         if (svgGN == null) return ret;
446
447         Rectangle2D JavaDoc svgBounds = svgGN.getSensitiveBounds();
448         if (svgBounds == null)
449             return ret;
450
451         // If the svg elem doesn't intersect none of the children
452
// will.
453
if (!rect.intersects(svgBounds))
454             return ret;
455
456         Element base = e;
457         AffineTransform JavaDoc ati = svgGN.getGlobalTransform();
458         try {
459             ati = ati.createInverse();
460         } catch (NoninvertibleTransformException JavaDoc e) {
461         }
462         
463         Element curr;
464         Node next = base.getFirstChild();
465         while (next != null) {
466             if (next instanceof Element)
467                 break;
468             next = next.getNextSibling();
469         }
470         if (next == null) return ret;
471         curr = (Element)next;
472
473         Set JavaDoc ancestors = null;
474         if (end != null) {
475             ancestors = getAncestors(end, base);
476             if (ancestors == null)
477                 end = null;
478         }
479         while (curr != null) {
480             String JavaDoc nsURI = curr.getNamespaceURI();
481             String JavaDoc tag = curr.getLocalName();
482             boolean isGroup;
483             isGroup = (SVGConstants.SVG_NAMESPACE_URI.equals(nsURI) &&
484                        ((SVGConstants.SVG_G_TAG.equals(tag)) ||
485                         (SVGConstants.SVG_SVG_TAG.equals(tag)) ||
486                         (SVGConstants.SVG_A_TAG.equals(tag))));
487
488             GraphicsNode gn = ctx.getGraphicsNode(curr);
489             if (gn == null) {
490                 // No graphics node but check if curr is an
491
// ancestor of end.
492
if ((ancestors != null) && (ancestors.contains(curr)))
493                     break;
494                 curr = getNext(curr, base, end);
495                 continue;
496             }
497                 
498
499             AffineTransform JavaDoc at = gn.getGlobalTransform();
500             Rectangle2D JavaDoc gnBounds = gn.getSensitiveBounds();
501             at.preConcatenate(ati);
502             if (gnBounds != null)
503                 gnBounds = at.createTransformedShape(gnBounds).getBounds2D();
504                 
505             if ((gnBounds == null) ||
506                 (!rect.intersects(gnBounds))) {
507                 // Graphics node does not intersect check if curr is
508
// an ancestor of end.
509
if ((ancestors != null) && (ancestors.contains(curr)))
510                     break;
511                 curr = getNext(curr, base, end);
512                 continue;
513             }
514
515             // Check if it is an SVG 'g', or 'svg' element in
516
// which case don't add this node but do check it's
517
// children.
518
if (isGroup) {
519                 // Check children.
520
next = curr.getFirstChild();
521                 while (next != null) {
522                     if (next instanceof Element)
523                         break;
524                     next = next.getNextSibling();
525                 }
526                 if (next != null) {
527                     curr = (Element)next;
528                     continue;
529                 }
530             } else {
531                 if (curr == end) break;
532                 // Otherwise check this node for intersection more
533
// carefully and if it still intersects add it.
534
if (SVGConstants.SVG_NAMESPACE_URI.equals(nsURI) &&
535                     SVGConstants.SVG_USE_TAG.equals(tag)) {
536                     // FIXX: This really isn't right we need to
537
// Add the proxy children.
538
if (rect.contains(gnBounds))
539                         ret.add(curr);
540                 } if (gn instanceof ShapeNode) {
541                     ShapeNode sn = (ShapeNode)gn;
542                     Shape JavaDoc sensitive = sn.getSensitiveArea();
543                     if (sensitive != null) {
544                         sensitive = at.createTransformedShape(sensitive);
545                         if (sensitive.intersects(rect))
546                             ret.add(curr);
547                     }
548                 } else if (gn instanceof TextNode) {
549                     SVGOMElement svgElem = (SVGOMElement)curr;
550                     SVGTextElementBridge txtBridge;
551                     txtBridge = (SVGTextElementBridge)svgElem.getSVGContext();
552                     Set JavaDoc elems = txtBridge.getTextIntersectionSet(at, rect);
553
554                     // filter elems based on who is before end as
555
// children of curr, if needed.
556
if ((ancestors != null) && ancestors.contains(curr))
557                         filterChildren(curr, end, elems, ret);
558                     else
559                         ret.addAll(elems);
560
561                 } else {
562                     ret.add(curr);
563                 }
564             }
565
566             curr = getNext(curr, base, end);
567         }
568
569         return ret;
570     }
571
572     public List JavaDoc getEnclosureList(SVGRect svgRect, Element end) {
573         List JavaDoc ret = new ArrayList JavaDoc();
574         Rectangle2D JavaDoc rect = new Rectangle2D.Float JavaDoc(svgRect.getX(),
575                                                  svgRect.getY(),
576                                                  svgRect.getWidth(),
577                                                  svgRect.getHeight());
578         GraphicsNode svgGN = ctx.getGraphicsNode(e);
579         if (svgGN == null) return ret;
580
581         Rectangle2D JavaDoc svgBounds = svgGN.getSensitiveBounds();
582         if (svgBounds == null)
583             return ret;
584
585         // If the svg elem doesn't at least intersect none of the
586
// children will be enclosed.
587
if (!rect.intersects(svgBounds))
588             return ret;
589
590         Element base = e;
591         AffineTransform JavaDoc ati = svgGN.getGlobalTransform();
592         try {
593             ati = ati.createInverse();
594         } catch (NoninvertibleTransformException JavaDoc e) {
595         }
596         
597         Element curr;
598         Node next = base.getFirstChild();
599         while (next != null) {
600             if (next instanceof Element)
601                 break;
602             next = next.getNextSibling();
603         }
604
605         if (next == null) return ret;
606         curr = (Element)next;
607
608         Set JavaDoc ancestors = null;
609         if (end != null) {
610             ancestors = getAncestors(end, base);
611             if (ancestors == null)
612                 end = null;
613         }
614
615         while (curr != null) {
616             String JavaDoc nsURI = curr.getNamespaceURI();
617             String JavaDoc tag = curr.getLocalName();
618             boolean isGroup;
619             isGroup = (SVGConstants.SVG_NAMESPACE_URI.equals(nsURI) &&
620                        ((SVGConstants.SVG_G_TAG.equals(tag)) ||
621                         (SVGConstants.SVG_SVG_TAG.equals(tag)) ||
622                         (SVGConstants.SVG_A_TAG.equals(tag))));
623
624             GraphicsNode gn = ctx.getGraphicsNode(curr);
625             if (gn == null) {
626                 // No graphics node but check if curr is an
627
// ancestor of end.
628
if ((ancestors != null) && (ancestors.contains(curr)))
629                     break;
630                 curr = getNext(curr, base, end);
631                 continue;
632             }
633                 
634
635             AffineTransform JavaDoc at = gn.getGlobalTransform();
636             Rectangle2D JavaDoc gnBounds = gn.getSensitiveBounds();
637             at.preConcatenate(ati);
638             if (gnBounds != null)
639                 gnBounds = at.createTransformedShape(gnBounds).getBounds2D();
640
641             if ((gnBounds == null) ||
642                 (!rect.intersects(gnBounds))) {
643                 // Graphics node does not intersect check if curr is
644
// an ancestor of end.
645
if ((ancestors != null) && (ancestors.contains(curr)))
646                     break;
647                 curr = getNext(curr, base, end);
648                 continue;
649             }
650
651             // If it is a group then don't add this node but do check
652
// it's children.
653
if (isGroup) {
654                 // Check children.
655
next = curr.getFirstChild();
656                 while (next != null) {
657                     if (next instanceof Element)
658                         break;
659                     next = next.getNextSibling();
660                 }
661                 if (next != null) {
662                     curr = (Element)next;
663                     continue;
664                 }
665             } else {
666                 if (curr == end) break;
667                 if (SVGConstants.SVG_NAMESPACE_URI.equals(nsURI) &&
668                     SVGConstants.SVG_USE_TAG.equals(tag)) {
669                     // FIXX: This really isn't right we need to
670
// Add the proxy children.
671
if (rect.contains(gnBounds))
672                         ret.add(curr);
673                 } else if (gn instanceof TextNode) {
674                     // If gnBounds is contained in rect then just add
675
// all the children
676
SVGOMElement svgElem = (SVGOMElement)curr;
677                     SVGTextElementBridge txtBridge;
678                     txtBridge = (SVGTextElementBridge)svgElem.getSVGContext();
679                     Set JavaDoc elems = txtBridge.getTextEnclosureSet(at, rect);
680                     
681                     // filter elems based on who is before end as
682
// children of curr if needed.
683
if ((ancestors != null) && ancestors.contains(curr))
684                         filterChildren(curr, end, elems, ret);
685                     else
686                         ret.addAll(elems);
687                 } else if (rect.contains(gnBounds)) {
688                     // shape nodes
689
ret.add(curr);
690                 }
691             }
692
693             curr = getNext(curr, base, end);
694         }
695         return ret;
696     }
697
698     public boolean checkIntersection (Element element, SVGRect svgRect ) {
699
700         GraphicsNode svgGN = ctx.getGraphicsNode(e);
701         if (svgGN == null) return false; // not in tree?
702

703         Rectangle2D JavaDoc rect = new Rectangle2D.Float JavaDoc
704             (svgRect.getX(), svgRect.getY(),
705              svgRect.getWidth(), svgRect.getHeight());
706         AffineTransform JavaDoc ati = svgGN.getGlobalTransform();
707
708         try {
709             ati = ati.createInverse();
710         } catch (NoninvertibleTransformException JavaDoc e) { }
711
712         SVGContext svgctx = null;
713         if (element instanceof SVGOMElement) {
714             svgctx = ((SVGOMElement)element).getSVGContext();
715             if ((svgctx instanceof SVGTextElementBridge) ||
716                 (svgctx instanceof
717                  SVGTextElementBridge.AbstractTextChildSVGContext)) {
718                 return SVGTextElementBridge.getTextIntersection
719                     (ctx, element, ati, rect, true);
720             }
721         }
722
723         Rectangle2D JavaDoc gnBounds = null;
724         GraphicsNode gn = ctx.getGraphicsNode(element);
725         if (gn != null)
726             gnBounds = gn.getSensitiveBounds();
727
728         if (gnBounds == null) return false;
729
730
731         AffineTransform JavaDoc at = gn.getGlobalTransform();
732         at.preConcatenate(ati);
733
734         gnBounds = at.createTransformedShape(gnBounds).getBounds2D();
735         if (!rect.intersects(gnBounds))
736             return false;
737
738         // Check GN more closely
739
if (!(gn instanceof ShapeNode))
740             return true;
741
742         ShapeNode sn = (ShapeNode)gn;
743         Shape JavaDoc sensitive = sn.getSensitiveArea();
744         if (sensitive == null) return false;
745
746         sensitive = at.createTransformedShape(sensitive);
747         if (sensitive.intersects(rect))
748             return true;
749
750         return false;
751     }
752
753     public boolean checkEnclosure (Element element, SVGRect svgRect ) {
754         GraphicsNode gn = ctx.getGraphicsNode(element);
755         Rectangle2D JavaDoc gnBounds = null;
756         SVGContext svgctx = null;
757         if (element instanceof SVGOMElement) {
758             svgctx = ((SVGOMElement)element).getSVGContext();
759             if ((svgctx instanceof SVGTextElementBridge) ||
760                 (svgctx instanceof
761                  SVGTextElementBridge.AbstractTextChildSVGContext)) {
762                 gnBounds = SVGTextElementBridge.getTextBounds
763                     (ctx, element, true);
764                 Element p = (Element)element.getParentNode();
765                 // Get GN for text children so we can get transform.
766
while ((p != null) && (gn == null)) {
767                     gn = ctx.getGraphicsNode(p);
768                     p = (Element)p.getParentNode();
769                 }
770             } else if (gn != null)
771                 gnBounds = gn.getSensitiveBounds();
772         } else if (gn != null)
773             gnBounds = gn.getSensitiveBounds();
774
775         if (gnBounds == null) return false;
776
777         GraphicsNode svgGN = ctx.getGraphicsNode(e);
778         if (svgGN == null) return false; // not in tree?
779

780         Rectangle2D JavaDoc rect = new Rectangle2D.Float JavaDoc
781             (svgRect.getX(), svgRect.getY(),
782              svgRect.getWidth(), svgRect.getHeight());
783         AffineTransform JavaDoc ati = svgGN.getGlobalTransform();
784         try {
785             ati = ati.createInverse();
786         } catch (NoninvertibleTransformException JavaDoc e) { }
787
788         AffineTransform JavaDoc at = gn.getGlobalTransform();
789         at.preConcatenate(ati);
790
791         gnBounds = at.createTransformedShape(gnBounds).getBounds2D();
792
793         return rect.contains(gnBounds);
794     }
795
796     public boolean filterChildren(Element curr, Element end,
797                                   Set JavaDoc elems, List JavaDoc ret) {
798         Node child = curr.getFirstChild();
799         while (child != null) {
800             if ((child instanceof Element) &&
801                 filterChildren((Element)child, end, elems, ret))
802                 return true;
803             child = child.getNextSibling();
804         }
805
806         if (curr == end) return true;
807
808         if (elems.contains(curr))
809             ret.add(curr);
810
811         return false;
812     }
813
814     protected Set JavaDoc getAncestors(Element end, Element base) {
815         Set JavaDoc ret = new HashSet JavaDoc();
816         Element p = end;
817         do {
818             ret.add(p);
819             p = (Element)p.getParentNode();
820         } while ((p != null) && (p != base));
821         
822         if (p == null) // 'end' is not a child of 'base'.
823
return null;
824
825         return ret;
826     }
827
828     protected Element getNext(Element curr, Element base, Element end) {
829         Node next;
830         // Check the next element.
831
next = curr.getNextSibling();
832         while (next != null) {
833             if (next instanceof Element)
834                 break;
835             next = next.getNextSibling();
836         }
837         while (next == null) {
838             // No sibling so check parent's siblings...
839
curr = (Element)curr.getParentNode();
840             if ((curr == end) || (curr == base)) {
841                 next = null; // signal we are done!
842
break;
843             }
844             next = curr.getNextSibling();
845             while (next != null) {
846                 if (next instanceof Element)
847                     break;
848                 next = next.getNextSibling();
849             }
850         }
851
852         return (Element)next;
853     }
854
855     public void deselectAll() {
856         ctx.getUserAgent().deselectAll();
857     }
858 }
859
Popular Tags