1 18 package org.apache.batik.bridge; 19 20 import java.awt.Dimension ; 21 import java.awt.RenderingHints ; 22 import java.awt.Shape ; 23 import java.awt.geom.AffineTransform ; 24 import java.awt.geom.NoninvertibleTransformException ; 25 import java.awt.geom.Rectangle2D ; 26 import java.text.AttributedCharacterIterator ; 27 import java.util.ArrayList ; 28 import java.util.HashSet ; 29 import java.util.List ; 30 import java.util.Set ; 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 ; 48 import org.w3c.dom.Node ; 49 import org.w3c.dom.events.MutationEvent ; 50 import org.w3c.dom.svg.SVGDocument; 51 import org.w3c.dom.svg.SVGSVGElement; 52 import org.w3c.dom.svg.SVGRect; 53 54 60 public class SVGSVGElementBridge 61 extends SVGGElementBridge 62 implements SVGSVGContext { 63 64 67 public SVGSVGElementBridge() {} 68 69 72 public String getLocalName() { 73 return SVG_SVG_TAG; 74 } 75 76 79 public Bridge getInstance(){ 80 return new SVGSVGElementBridge(); 81 } 82 83 86 protected GraphicsNode instantiateGraphicsNode() { 87 return new CanvasGraphicsNode(); 88 } 89 90 97 public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { 98 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 s; 108 109 SVGDocument doc = (SVGDocument)e.getOwnerDocument(); 114 boolean isOutermost = (doc.getRootElement() == e); 115 float x = 0; 116 float y = 0; 117 if (!isOutermost) { 119 s = e.getAttributeNS(null, SVG_X_ATTRIBUTE); 121 if (s.length() != 0) { 122 x = UnitProcessor.svgHorizontalCoordinateToUserSpace 123 (s, SVG_X_ATTRIBUTE, uctx); 124 } 125 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 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 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 cgn.setVisible(CSSUtilities.convertVisibility(e)); 151 152 AffineTransform viewingTransform = 154 ViewBox.getPreserveAspectRatioTransform(e, w, h); 155 156 float actualWidth = w; 157 float actualHeight = h; 158 try { 159 AffineTransform vtInv = viewingTransform.createInverse(); 160 actualWidth = (float) (w*vtInv.getScaleX()); 161 actualHeight = (float) (h*vtInv.getScaleY()); 162 } catch (NoninvertibleTransformException ex) {} 163 164 AffineTransform positionTransform = 165 AffineTransform.getTranslateInstance(x, y); 166 if (!isOutermost) { 169 cgn.setPositionTransform(positionTransform); 171 } else if (doc == ctx.getDocument()) { 172 ctx.setDocumentSize(new Dimension ((int)(w+0.5f), (int)(h+0.5f))); 174 } 175 cgn.setViewingTransform(viewingTransform); 178 179 Shape clip = null; 181 if (CSSUtilities.convertOverflow(e)) { float [] offsets = CSSUtilities.convertClip(e); 183 if (offsets == null) { clip = new Rectangle2D.Float (x, y, w, h); 185 } else { clip = new Rectangle2D.Float (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 at = new AffineTransform (positionTransform); 200 at.concatenate(viewingTransform); 201 at = at.createInverse(); clip = at.createTransformedShape(clip); 203 Filter filter = cgn.getGraphicsNodeRable(true); 204 cgn.setClip(new ClipRable8Bit(filter, clip)); 205 } catch (NoninvertibleTransformException ex) {} 206 } 207 RenderingHints hints = null; 208 hints = CSSUtilities.convertColorRendering(e, hints); 209 if (hints != null) 210 cgn.setRenderingHints(hints); 211 212 Rectangle2D 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 232 public void buildGraphicsNode(BridgeContext ctx, 233 Element e, 234 GraphicsNode node) { 235 236 node.setComposite(CSSUtilities.convertOpacity(e)); 238 node.setFilter(CSSUtilities.convertFilter(e, node, ctx)); 240 node.setMask(CSSUtilities.convertMask(e, node, ctx)); 242 node.setPointerEventType(CSSUtilities.convertPointerEvents(e)); 244 245 initializeDynamicSupport(ctx, e, node); 246 247 ctx.closeViewport(e); 248 } 249 250 252 255 public void dispose() { 256 ctx.removeViewport(e); 257 super.dispose(); 258 } 259 260 263 public void handleDOMAttrModifiedEvent(MutationEvent evt) { 264 String 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 float x = 0; 278 float y = 0; 279 UnitProcessor.Context uctx; 280 uctx = UnitProcessor.createContext(ctx, e); 281 String s = e.getAttributeNS(null, SVG_X_ATTRIBUTE); 283 if (s.length() != 0) { 284 x = UnitProcessor.svgHorizontalCoordinateToUserSpace 285 (s, SVG_X_ATTRIBUTE, uctx); 286 } 287 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 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 s; 307 UnitProcessor.Context uctx; 308 uctx = UnitProcessor.createContext(ctx, e); 309 float x = 0; 311 float y = 0; 312 if (!isOutermost) { 313 s = e.getAttributeNS(null, SVG_X_ATTRIBUTE); 315 if (s.length() != 0) { 316 x = UnitProcessor.svgHorizontalCoordinateToUserSpace 317 (s, SVG_X_ATTRIBUTE, uctx); 318 } 319 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 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 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 AffineTransform newVT = 348 ViewBox.getPreserveAspectRatioTransform(e, w, h); 349 AffineTransform 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 cgn.setViewingTransform(newVT); 358 359 Shape clip = null; 361 if (CSSUtilities.convertOverflow(e)) { float [] offsets = CSSUtilities.convertClip(e); 363 if (offsets == null) { clip = new Rectangle2D.Float (x, y, w, h); 365 } else { clip = new Rectangle2D.Float (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 at; 380 at = cgn.getPositionTransform(); 381 at = new AffineTransform (at); 382 at.concatenate(newVT); 383 at = at.createInverse(); clip = at.createTransformedShape(clip); 385 Filter filter = cgn.getGraphicsNodeRable(true); 386 cgn.setClip(new ClipRable8Bit(filter, clip)); 387 } catch (NoninvertibleTransformException 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 404 public static class SVGSVGElementViewport implements Viewport { 405 private float width; 406 private float height; 407 408 413 public SVGSVGElementViewport(float w, float h) { 414 this.width = w; 415 this.height = h; 416 } 417 418 421 public float getWidth(){ 422 return width; 423 } 424 425 428 public float getHeight(){ 429 return height; 430 } 431 } 432 433 public static final 434 AttributedCharacterIterator.Attribute TEXT_COMPOUND_DELIMITER 435 = GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER; 436 437 public List getIntersectionList(SVGRect svgRect, Element end) { 438 List ret = new ArrayList (); 439 Rectangle2D rect = new Rectangle2D.Float (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 svgBounds = svgGN.getSensitiveBounds(); 448 if (svgBounds == null) 449 return ret; 450 451 if (!rect.intersects(svgBounds)) 454 return ret; 455 456 Element base = e; 457 AffineTransform ati = svgGN.getGlobalTransform(); 458 try { 459 ati = ati.createInverse(); 460 } catch (NoninvertibleTransformException 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 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 nsURI = curr.getNamespaceURI(); 481 String 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 if ((ancestors != null) && (ancestors.contains(curr))) 493 break; 494 curr = getNext(curr, base, end); 495 continue; 496 } 497 498 499 AffineTransform at = gn.getGlobalTransform(); 500 Rectangle2D 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 if ((ancestors != null) && (ancestors.contains(curr))) 510 break; 511 curr = getNext(curr, base, end); 512 continue; 513 } 514 515 if (isGroup) { 519 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 if (SVGConstants.SVG_NAMESPACE_URI.equals(nsURI) && 535 SVGConstants.SVG_USE_TAG.equals(tag)) { 536 if (rect.contains(gnBounds)) 539 ret.add(curr); 540 } if (gn instanceof ShapeNode) { 541 ShapeNode sn = (ShapeNode)gn; 542 Shape 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 elems = txtBridge.getTextIntersectionSet(at, rect); 553 554 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 getEnclosureList(SVGRect svgRect, Element end) { 573 List ret = new ArrayList (); 574 Rectangle2D rect = new Rectangle2D.Float (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 svgBounds = svgGN.getSensitiveBounds(); 582 if (svgBounds == null) 583 return ret; 584 585 if (!rect.intersects(svgBounds)) 588 return ret; 589 590 Element base = e; 591 AffineTransform ati = svgGN.getGlobalTransform(); 592 try { 593 ati = ati.createInverse(); 594 } catch (NoninvertibleTransformException 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 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 nsURI = curr.getNamespaceURI(); 617 String 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 if ((ancestors != null) && (ancestors.contains(curr))) 629 break; 630 curr = getNext(curr, base, end); 631 continue; 632 } 633 634 635 AffineTransform at = gn.getGlobalTransform(); 636 Rectangle2D 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 if ((ancestors != null) && (ancestors.contains(curr))) 646 break; 647 curr = getNext(curr, base, end); 648 continue; 649 } 650 651 if (isGroup) { 654 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 if (rect.contains(gnBounds)) 672 ret.add(curr); 673 } else if (gn instanceof TextNode) { 674 SVGOMElement svgElem = (SVGOMElement)curr; 677 SVGTextElementBridge txtBridge; 678 txtBridge = (SVGTextElementBridge)svgElem.getSVGContext(); 679 Set elems = txtBridge.getTextEnclosureSet(at, rect); 680 681 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 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; 703 Rectangle2D rect = new Rectangle2D.Float 704 (svgRect.getX(), svgRect.getY(), 705 svgRect.getWidth(), svgRect.getHeight()); 706 AffineTransform ati = svgGN.getGlobalTransform(); 707 708 try { 709 ati = ati.createInverse(); 710 } catch (NoninvertibleTransformException 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 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 at = gn.getGlobalTransform(); 732 at.preConcatenate(ati); 733 734 gnBounds = at.createTransformedShape(gnBounds).getBounds2D(); 735 if (!rect.intersects(gnBounds)) 736 return false; 737 738 if (!(gn instanceof ShapeNode)) 740 return true; 741 742 ShapeNode sn = (ShapeNode)gn; 743 Shape 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 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 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; 780 Rectangle2D rect = new Rectangle2D.Float 781 (svgRect.getX(), svgRect.getY(), 782 svgRect.getWidth(), svgRect.getHeight()); 783 AffineTransform ati = svgGN.getGlobalTransform(); 784 try { 785 ati = ati.createInverse(); 786 } catch (NoninvertibleTransformException e) { } 787 788 AffineTransform 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 elems, List 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 getAncestors(Element end, Element base) { 815 Set ret = new HashSet (); 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) return null; 824 825 return ret; 826 } 827 828 protected Element getNext(Element curr, Element base, Element end) { 829 Node next; 830 next = curr.getNextSibling(); 832 while (next != null) { 833 if (next instanceof Element) 834 break; 835 next = next.getNextSibling(); 836 } 837 while (next == null) { 838 curr = (Element)curr.getParentNode(); 840 if ((curr == end) || (curr == base)) { 841 next = null; 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 |