1 18 package org.apache.batik.gvt; 19 20 import java.awt.AlphaComposite ; 21 import java.awt.Composite ; 22 import java.awt.Graphics2D ; 23 import java.awt.RenderingHints ; 24 import java.awt.Shape ; 25 import java.awt.geom.AffineTransform ; 26 import java.awt.geom.NoninvertibleTransformException ; 27 import java.awt.geom.Point2D ; 28 import java.awt.geom.Rectangle2D ; 29 import java.lang.ref.WeakReference ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Map ; 33 34 import javax.swing.event.EventListenerList ; 35 36 import org.apache.batik.ext.awt.RenderingHintsKeyExt; 37 import org.apache.batik.ext.awt.image.renderable.ClipRable; 38 import org.apache.batik.ext.awt.image.renderable.Filter; 39 import org.apache.batik.gvt.event.GraphicsNodeChangeEvent; 40 import org.apache.batik.gvt.event.GraphicsNodeChangeListener; 41 import org.apache.batik.gvt.filter.GraphicsNodeRable; 42 import org.apache.batik.gvt.filter.GraphicsNodeRable8Bit; 43 import org.apache.batik.gvt.filter.Mask; 44 import org.apache.batik.util.HaltingThread; 45 46 54 public abstract class AbstractGraphicsNode implements GraphicsNode { 55 56 59 protected EventListenerList listeners; 60 61 64 protected AffineTransform transform; 65 66 70 protected AffineTransform inverseTransform; 71 72 76 protected Composite composite; 77 78 81 protected boolean isVisible = true; 82 83 86 protected ClipRable clip; 87 88 92 protected RenderingHints hints; 93 94 97 protected CompositeGraphicsNode parent; 98 99 102 protected RootGraphicsNode root; 103 104 107 protected Mask mask; 108 109 112 protected Filter filter; 113 114 117 protected int pointerEventType = VISIBLE_PAINTED; 118 119 122 protected WeakReference graphicsNodeRable; 123 124 127 protected WeakReference enableBackgroundGraphicsNodeRable; 128 129 132 protected WeakReference weakRef; 133 134 137 private Rectangle2D bounds; 138 139 140 protected GraphicsNodeChangeEvent changeStartedEvent = null; 141 protected GraphicsNodeChangeEvent changeCompletedEvent = null; 142 143 146 protected AbstractGraphicsNode() {} 147 148 152 public WeakReference getWeakReference() { 153 if (weakRef == null) 154 weakRef = new WeakReference (this); 155 return weakRef; 156 } 157 158 162 168 public int getPointerEventType() { 169 return pointerEventType; 170 } 171 172 178 public void setPointerEventType(int pointerEventType) { 179 this.pointerEventType = pointerEventType; 180 } 181 182 187 public void setTransform(AffineTransform newTransform) { 188 fireGraphicsNodeChangeStarted(); 189 this.transform = newTransform; 190 if(transform.getDeterminant() != 0){ 191 try{ 192 inverseTransform = transform.createInverse(); 193 }catch(NoninvertibleTransformException e){ 194 throw new Error (); 196 } 197 } else { 198 inverseTransform = transform; 201 } 202 if (parent != null) 203 parent.invalidateGeometryCache(); 204 fireGraphicsNodeChangeCompleted(); 205 } 206 207 210 public AffineTransform getTransform() { 211 return transform; 212 } 213 214 217 public AffineTransform getInverseTransform(){ 218 return inverseTransform; 219 } 220 221 225 public AffineTransform getGlobalTransform(){ 226 AffineTransform ctm = new AffineTransform (); 227 GraphicsNode node = this; 228 while (node != null) { 229 if(node.getTransform() != null){ 230 ctm.preConcatenate(node.getTransform()); 231 } 232 node = node.getParent(); 233 } 234 return ctm; 235 } 236 237 242 public void setComposite(Composite newComposite) { 243 fireGraphicsNodeChangeStarted(); 244 invalidateGeometryCache(); 245 this.composite = newComposite; 246 fireGraphicsNodeChangeCompleted(); 247 } 248 249 252 public Composite getComposite() { 253 return composite; 254 } 255 256 261 public void setVisible(boolean isVisible) { 262 fireGraphicsNodeChangeStarted(); 263 this.isVisible = isVisible; 264 invalidateGeometryCache(); 265 fireGraphicsNodeChangeCompleted(); 266 } 267 268 271 public boolean isVisible() { 272 return isVisible; 273 } 274 275 public void setClip(ClipRable newClipper) { 276 fireGraphicsNodeChangeStarted(); 277 invalidateGeometryCache(); 278 this.clip = newClipper; 279 fireGraphicsNodeChangeCompleted(); 280 } 281 282 285 public ClipRable getClip() { 286 return clip; 287 } 288 289 297 public void setRenderingHint(RenderingHints.Key key, Object value) { 298 fireGraphicsNodeChangeStarted(); 299 if (this.hints == null) { 300 this.hints = new RenderingHints (key, value); 301 } else { 302 hints.put(key, value); 303 } 304 fireGraphicsNodeChangeCompleted(); 305 } 306 307 313 public void setRenderingHints(Map hints) { 314 fireGraphicsNodeChangeStarted(); 315 if (this.hints == null) { 316 this.hints = new RenderingHints (hints); 317 } else { 318 this.hints.putAll(hints); 319 } 320 fireGraphicsNodeChangeCompleted(); 321 } 322 323 328 public void setRenderingHints(RenderingHints newHints) { 329 fireGraphicsNodeChangeStarted(); 330 this.hints = newHints; 331 fireGraphicsNodeChangeCompleted(); 332 } 333 334 337 public RenderingHints getRenderingHints() { 338 return hints; 339 } 340 341 346 public void setMask(Mask newMask) { 347 fireGraphicsNodeChangeStarted(); 348 invalidateGeometryCache(); 349 this.mask = newMask; 350 fireGraphicsNodeChangeCompleted(); 351 } 352 353 356 public Mask getMask() { 357 return mask; 358 } 359 360 365 public void setFilter(Filter newFilter) { 366 fireGraphicsNodeChangeStarted(); 367 invalidateGeometryCache(); 368 this.filter = newFilter; 369 fireGraphicsNodeChangeCompleted(); 370 } 371 372 375 public Filter getFilter() { 376 return filter; 377 } 378 379 384 public Filter getGraphicsNodeRable(boolean createIfNeeded) { 385 GraphicsNodeRable ret = null; 386 if (graphicsNodeRable != null) { 387 ret = (GraphicsNodeRable)graphicsNodeRable.get(); 388 if (ret != null) return ret; 389 } 390 if (createIfNeeded) { 391 ret = new GraphicsNodeRable8Bit(this); 392 graphicsNodeRable = new WeakReference (ret); 393 } 394 return ret; 395 } 396 397 402 public Filter getEnableBackgroundGraphicsNodeRable 403 (boolean createIfNeeded) { 404 GraphicsNodeRable ret = null; 405 if (enableBackgroundGraphicsNodeRable != null) { 406 ret = (GraphicsNodeRable)enableBackgroundGraphicsNodeRable.get(); 407 if (ret != null) return ret; 408 } 409 if (createIfNeeded) { 410 ret = new GraphicsNodeRable8Bit(this); 411 ret.setUsePrimitivePaint(false); 412 enableBackgroundGraphicsNodeRable = new WeakReference (ret); 413 } 414 return ret; 415 } 416 417 421 426 public void paint(Graphics2D g2d){ 427 if ((composite != null) && 428 (composite instanceof AlphaComposite )) { 429 AlphaComposite ac = (AlphaComposite )composite; 430 if (ac.getAlpha() < 0.001) 431 return; } 433 Rectangle2D bounds = getBounds(); 434 if (bounds == null) return; 435 436 Shape defaultClip = g2d.getClip(); 440 Composite defaultComposite = g2d.getComposite(); 441 AffineTransform defaultTransform = g2d.getTransform(); 442 RenderingHints defaultHints = null; 443 444 if (hints != null) { 445 defaultHints = g2d.getRenderingHints(); 446 g2d.addRenderingHints(hints); 447 } 448 if (transform != null) { 449 g2d.transform(transform); 450 } 451 if (composite != null) { 452 g2d.setComposite(composite); 453 } 454 if (clip != null){ 455 g2d.clip(clip.getClipPath()); 456 } 457 458 Shape curClip = g2d.getClip(); 459 g2d.setRenderingHint(RenderingHintsKeyExt.KEY_AREA_OF_INTEREST, 460 curClip); 461 462 boolean paintNeeded = true; 465 Shape g2dClip = curClip; if (g2dClip != null) { 467 Rectangle2D cb = g2dClip.getBounds2D(); 468 if(!bounds.intersects(cb.getX(), cb.getY(), 469 cb.getWidth(), cb.getHeight())) 470 paintNeeded = false; 471 } 472 473 if (paintNeeded){ 475 boolean antialiasedClip = false; 476 if ((clip != null) && clip.getUseAntialiasedClip()) { 477 antialiasedClip = isAntialiasedClip(g2d.getTransform(), 478 g2d.getRenderingHints(), 479 clip.getClipPath()); 480 } 481 482 boolean useOffscreen = isOffscreenBufferNeeded(); 483 484 useOffscreen |= antialiasedClip; 485 486 if (!useOffscreen) { 487 primitivePaint(g2d); 489 } else { 490 Filter filteredImage = null; 491 492 if(filter == null){ 493 filteredImage = getGraphicsNodeRable(true); 494 } 495 else { 496 filteredImage = filter; 498 } 499 500 if (mask != null) { 501 if (mask.getSource() != filteredImage){ 502 mask.setSource(filteredImage); 503 } 504 filteredImage = mask; 505 } 506 507 if (clip != null && antialiasedClip) { 508 if (clip.getSource() != filteredImage){ 509 clip.setSource(filteredImage); 510 } 511 filteredImage = clip; 512 } 513 514 if(antialiasedClip){ 515 g2d.setClip(null); 517 } 518 519 Rectangle2D filterBounds = filteredImage.getBounds2D(); 520 g2d.clip(filterBounds); 521 522 org.apache.batik.ext.awt.image.GraphicsUtil.drawImage 523 (g2d, filteredImage); 524 } 525 } 526 527 if (defaultHints != null) { 529 g2d.setRenderingHints(defaultHints); 530 } 531 g2d.setTransform(defaultTransform); 532 g2d.setClip(defaultClip); 533 if (composite != null) { 534 g2d.setComposite(defaultComposite); 535 } 536 } 537 538 541 private void traceFilter(Filter filter, String prefix){ 542 System.out.println(prefix + filter.getClass().getName()); 543 System.out.println(prefix + filter.getBounds2D()); 544 java.util.Vector sources = filter.getSources(); 545 int nSources = sources != null ? sources.size() : 0; 546 prefix += "\t"; 547 for(int i=0; i<nSources; i++){ 548 Filter source = (Filter)sources.elementAt(i); 549 traceFilter(source, prefix); 550 } 551 552 System.out.flush(); 553 } 554 555 559 protected boolean isOffscreenBufferNeeded() { 560 return ((filter != null) || 561 (mask != null) || 562 (composite != null && 563 !AlphaComposite.SrcOver.equals(composite))); 564 } 565 566 569 protected boolean isAntialiasedClip(AffineTransform usr2dev, 570 RenderingHints hints, 571 Shape clip){ 572 if (clip == null) return false; 585 586 Object val = hints.get(RenderingHintsKeyExt.KEY_TRANSCODING); 587 if ((val == RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) || 588 (val == RenderingHintsKeyExt.VALUE_TRANSCODING_VECTOR)) 589 return false; 590 591 if(!(clip instanceof Rectangle2D && 592 usr2dev.getShearX() == 0 && 593 usr2dev.getShearY() == 0)) 594 return true; 595 596 return false; 597 } 598 599 public void fireGraphicsNodeChangeStarted(GraphicsNode changeSrc) { 603 if (changeStartedEvent == null) 604 changeStartedEvent = new GraphicsNodeChangeEvent 605 (this, GraphicsNodeChangeEvent.CHANGE_STARTED); 606 changeStartedEvent.setChangeSrc(changeSrc); 607 fireGraphicsNodeChangeStarted(changeStartedEvent); 608 changeStartedEvent.setChangeSrc(null); 609 } 610 611 public void fireGraphicsNodeChangeStarted() { 615 if (changeStartedEvent == null) 616 changeStartedEvent = new GraphicsNodeChangeEvent 617 (this, GraphicsNodeChangeEvent.CHANGE_STARTED); 618 else { 619 changeStartedEvent.setChangeSrc(null); 620 } 621 fireGraphicsNodeChangeStarted(changeStartedEvent); 622 } 623 624 public void fireGraphicsNodeChangeStarted 625 (GraphicsNodeChangeEvent changeStartedEvent) { 626 628 RootGraphicsNode rootGN = getRoot(); 629 if (rootGN == null) return; 630 631 List l = rootGN.getTreeGraphicsNodeChangeListeners(); 632 if (l == null) return; 633 634 Iterator i = l.iterator(); 635 GraphicsNodeChangeListener gncl; 636 while (i.hasNext()) { 637 gncl = (GraphicsNodeChangeListener)i.next(); 638 gncl.changeStarted(changeStartedEvent); 639 } 640 } 641 642 public void fireGraphicsNodeChangeCompleted() { 643 if (changeCompletedEvent == null) { 644 changeCompletedEvent = new GraphicsNodeChangeEvent 645 (this, GraphicsNodeChangeEvent.CHANGE_COMPLETED); 646 } 647 648 650 RootGraphicsNode rootGN = getRoot(); 651 if (rootGN == null) return; 652 653 List l = rootGN.getTreeGraphicsNodeChangeListeners(); 654 if (l == null) return; 655 656 Iterator i = l.iterator(); 657 GraphicsNodeChangeListener gncl; 658 while (i.hasNext()) { 659 gncl = (GraphicsNodeChangeListener)i.next(); 660 gncl.changeCompleted(changeCompletedEvent); 661 } 662 } 663 664 665 669 672 public CompositeGraphicsNode getParent() { 673 return parent; 674 } 675 676 680 public RootGraphicsNode getRoot() { 681 return root; 682 } 683 684 689 protected void setRoot(RootGraphicsNode newRoot) { 690 this.root = newRoot; 691 } 692 693 698 protected void setParent(CompositeGraphicsNode newParent) { 699 this. parent = newParent; 700 } 701 702 706 711 protected void invalidateGeometryCache() { 712 716 if (parent != null) { 717 parent.invalidateGeometryCache(); 718 } 719 bounds = null; 720 } 721 722 726 public Rectangle2D getBounds(){ 727 if (bounds == null) { 730 if(filter == null){ 734 bounds = getPrimitiveBounds(); 735 } else { 736 bounds = filter.getBounds2D(); 737 } 738 if(bounds != null){ 740 if (clip != null) { 741 Rectangle2D clipR = clip.getClipPath().getBounds2D(); 742 if (clipR.intersects(bounds)) 743 Rectangle2D.intersect(bounds, clipR, bounds); 744 } 745 if (mask != null) { 747 Rectangle2D maskR = mask.getBounds2D(); 748 if (maskR.intersects(bounds)) 749 Rectangle2D.intersect(bounds, maskR, bounds); 750 } 751 } 752 753 bounds = normalizeRectangle(bounds); 754 755 if (HaltingThread.hasBeenHalted()) { 757 invalidateGeometryCache(); 760 } 761 } 762 763 return bounds; 764 } 765 766 773 public Rectangle2D getTransformedBounds(AffineTransform txf){ 774 AffineTransform t = txf; 775 if (transform != null) { 776 t = new AffineTransform (txf); 777 t.concatenate(transform); 778 } 779 780 Rectangle2D tBounds = null; 784 if (filter == null) { 785 tBounds = getTransformedPrimitiveBounds(txf); 787 } else { 788 tBounds = t.createTransformedShape 789 (filter.getBounds2D()).getBounds2D(); 790 } 791 if (tBounds != null) { 793 if (clip != null) { 794 Rectangle2D.intersect 795 (tBounds, 796 t.createTransformedShape(clip.getClipPath()).getBounds2D(), 797 tBounds); 798 } 799 800 if(mask != null) { 802 Rectangle2D.intersect 803 (tBounds, 804 t.createTransformedShape(mask.getBounds2D()).getBounds2D(), 805 tBounds); 806 } 807 } 808 809 return tBounds; 810 } 811 812 819 public Rectangle2D getTransformedPrimitiveBounds(AffineTransform txf) { 820 Rectangle2D tpBounds = getPrimitiveBounds(); 821 if (tpBounds == null) { 822 return null; 823 } 824 AffineTransform t = txf; 825 if (transform != null) { 826 t = new AffineTransform (txf); 827 t.concatenate(transform); 828 } 829 830 return t.createTransformedShape(tpBounds).getBounds2D(); 831 } 832 833 843 public Rectangle2D getTransformedGeometryBounds(AffineTransform txf) { 844 Rectangle2D tpBounds = getGeometryBounds(); 845 if (tpBounds == null) { 846 return null; 847 } 848 AffineTransform t = txf; 849 if (transform != null) { 850 t = new AffineTransform (txf); 851 t.concatenate(transform); 852 } 853 854 return t.createTransformedShape(tpBounds).getBounds2D(); 855 } 856 857 867 public Rectangle2D getTransformedSensitiveBounds(AffineTransform txf) { 868 Rectangle2D sBounds = getSensitiveBounds(); 869 if (sBounds == null) { 870 return null; 871 } 872 AffineTransform t = txf; 873 if (transform != null) { 874 t = new AffineTransform (txf); 875 t.concatenate(transform); 876 } 877 878 return t.createTransformedShape(sBounds).getBounds2D(); 879 } 880 881 887 public boolean contains(Point2D p) { 888 Rectangle2D b = getSensitiveBounds(); 889 if (b == null || !b.contains(p)) { 890 return false; 891 } 892 switch(pointerEventType) { 893 case VISIBLE_PAINTED: 894 case VISIBLE_FILL: 895 case VISIBLE_STROKE: 896 case VISIBLE: 897 return isVisible; 898 case PAINTED: 899 case FILL: 900 case STROKE: 901 case ALL: 902 return true; 903 case NONE: 904 default: 905 return false; 906 } 907 } 908 909 915 public boolean intersects(Rectangle2D r) { 916 Rectangle2D b = getBounds(); 917 if (b == null) return false; 918 919 return b.intersects(r); 920 } 921 922 928 public GraphicsNode nodeHitAt(Point2D p) { 929 return (contains(p) ? this : null); 930 } 931 932 static double EPSILON = 1e-6; 933 934 939 protected Rectangle2D normalizeRectangle(Rectangle2D bounds) { 940 if (bounds == null) return null; 941 942 if ((bounds.getWidth() < EPSILON)) { 943 if (bounds.getHeight() < EPSILON) { 944 AffineTransform gt = getGlobalTransform(); 945 double det = Math.sqrt(gt.getDeterminant()); 946 return new Rectangle2D.Double 947 (bounds.getX(), bounds.getY(), EPSILON/det, EPSILON/det); 948 } else { 949 double tmpW = bounds.getHeight()*EPSILON; 950 if (tmpW < bounds.getWidth()) 951 tmpW = bounds.getWidth(); 952 return new Rectangle2D.Double 953 (bounds.getX(), bounds.getY(), 954 tmpW, bounds.getHeight()); 955 } 956 } else if (bounds.getHeight() < EPSILON) { 957 double tmpH = bounds.getWidth()*EPSILON; 958 if (tmpH < bounds.getHeight()) 959 tmpH = bounds.getHeight(); 960 return new Rectangle2D.Double 961 (bounds.getX(), bounds.getY(), 962 bounds.getWidth(), tmpH); 963 } 964 return bounds; 965 } 966 967 } 968 | Popular Tags |