1 7 package javax.swing; 8 9 import java.applet.Applet ; 10 import java.awt.*; 11 import java.awt.event.*; 12 import java.awt.image.*; 13 import java.lang.reflect.*; 14 import java.lang.ref.WeakReference ; 15 import java.security.AccessController ; 16 import java.util.*; 17 import java.util.logging.*; 18 import sun.awt.SubRegionShowable; 19 import sun.java2d.SunGraphics2D; 20 import sun.security.action.GetPropertyAction; 21 22 29 class BufferStrategyPaintManager extends RepaintManager.PaintManager { 30 53 private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; 57 private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD; 58 59 63 private static boolean TRY_FLIP; 64 65 private static final Logger LOGGER = Logger.getLogger( 66 "javax.swing.BufferStrategyPaintManager"); 67 68 73 private ArrayList<BufferInfo> bufferInfos; 74 75 79 private boolean painting; 80 84 private boolean showing; 85 86 private int accumulatedX; 94 private int accumulatedY; 95 private int accumulatedMaxX; 96 private int accumulatedMaxY; 97 98 102 105 private JComponent rootJ; 106 109 private Container root; 110 113 private int xOffset; 114 117 private int yOffset; 118 121 private Graphics bsg; 122 125 private BufferStrategy bufferStrategy; 126 129 private BufferInfo bufferInfo; 130 131 135 private boolean disposeBufferOnEnd; 136 137 138 static { 139 TRY_FLIP = "true".equals(AccessController.doPrivileged( 140 new GetPropertyAction("swing.useFlipBufferStrategy", "false"))); 141 } 142 143 private static Method getGetBufferStrategyMethod() { 144 if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) { 145 getMethods(); 146 } 147 return COMPONENT_GET_BUFFER_STRATEGY_METHOD; 148 } 149 150 private static Method getCreateBufferStrategyMethod() { 151 if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) { 152 getMethods(); 153 } 154 return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; 155 } 156 157 private static void getMethods() { 158 java.security.AccessController.doPrivileged( 159 new java.security.PrivilegedAction <Object >() { 160 public Object run() { 161 try { 162 COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class. 163 getDeclaredMethod("createBufferStrategy", 164 new Class [] { int.class, 165 BufferCapabilities.class }); 166 COMPONENT_CREATE_BUFFER_STRATEGY_METHOD. 167 setAccessible(true); 168 COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class. 169 getDeclaredMethod("getBufferStrategy"); 170 COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true); 171 } catch (SecurityException e) { 172 assert false; 173 } catch (NoSuchMethodException nsme) { 174 assert false; 175 } 176 return null; 177 } 178 }); 179 } 180 181 BufferStrategyPaintManager() { 182 bufferInfos = new ArrayList<BufferInfo>(1); 183 } 184 185 189 192 protected void dispose() { 193 SwingUtilities.invokeLater(new Runnable () { 197 public void run() { 198 java.util.List <BufferInfo> bufferInfos; 199 synchronized(BufferStrategyPaintManager.this) { 200 while (showing) { 201 try { 202 wait(); 203 } catch (InterruptedException ie) { 204 } 205 } 206 bufferInfos = BufferStrategyPaintManager.this.bufferInfos; 207 BufferStrategyPaintManager.this.bufferInfos = null; 208 } 209 dispose(bufferInfos); 210 } 211 }); 212 } 213 214 private void dispose(java.util.List <BufferInfo> bufferInfos) { 215 if (LOGGER.isLoggable(Level.FINER)) { 216 LOGGER.log(Level.FINER, "BufferStrategyPaintManager disposed", 217 new RuntimeException ()); 218 } 219 if (bufferInfos != null) { 220 for (BufferInfo bufferInfo : bufferInfos) { 221 bufferInfo.dispose(); 222 } 223 } 224 } 225 226 231 public boolean show(Container c, int x, int y, int w, int h) { 232 synchronized(this) { 233 if (painting) { 234 return false; 237 } 238 showing = true; 239 } 240 try { 241 BufferInfo info = getBufferInfo(c); 242 BufferStrategy bufferStrategy; 243 if (info != null && !info.usingFlip && info.isInSync() && 244 (bufferStrategy = info.getBufferStrategy(false)) != null) { 245 SubRegionShowable bsSubRegion = 246 (SubRegionShowable)bufferStrategy; 247 boolean paintAllOnExpose = info.getPaintAllOnExpose(); 248 info.setPaintAllOnExpose(false); 249 if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) { 250 return !paintAllOnExpose; 251 } 252 bufferInfo.setContentsLostDuringExpose(true); 257 } 258 } 259 finally { 260 synchronized(this) { 261 showing = false; 262 notifyAll(); 263 } 264 } 265 return false; 266 } 267 268 public boolean paint(JComponent paintingComponent, 269 JComponent bufferComponent, Graphics g, 270 int x, int y, int w, int h) { 271 if (prepare(paintingComponent, true, x, y, w, h)) { 272 if ((g instanceof SunGraphics2D) && 273 ((SunGraphics2D)g).getDestination() == root) { 274 int cx = ((SunGraphics2D)bsg).constrainX; 278 int cy = ((SunGraphics2D)bsg).constrainY; 279 if (cx != 0 || cy != 0) { 280 bsg.translate(-cx, -cy); 281 } 282 ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy, 283 x + w, y + h); 284 bsg.setClip(x, y, w, h); 285 paintingComponent.paintToOffscreen(bsg, x, y, w, h, 286 x + w, y + h); 287 accumulate(xOffset + x, yOffset + y, w, h); 288 return true; 289 } else { 290 bufferInfo.setInSync(false); 294 } 296 } 297 if (LOGGER.isLoggable(Level.FINER)) { 299 LOGGER.finer("prepare failed"); 300 } 301 return super.paint(paintingComponent, bufferComponent, g, x, y, w, h); 302 } 303 304 public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h, 305 int deltaX, int deltaY, boolean clip) { 306 if (prepare(c, false, 0, 0, 0, 0) && bufferInfo.isInSync()) { 313 if (clip) { 314 Rectangle cBounds = c.getVisibleRect(); 315 int relX = xOffset + x; 316 int relY = yOffset + y; 317 bsg.clipRect(xOffset + cBounds.x, 318 yOffset + cBounds.y, 319 cBounds.width, cBounds.height); 320 bsg.copyArea(relX, relY, w, h, deltaX, deltaY); 321 } 322 else { 323 bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX, 324 deltaY); 325 } 326 accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h); 327 } else { 328 if (LOGGER.isLoggable(Level.FINER)) { 329 LOGGER.finer("copyArea: prepare failed or not in sync"); 330 } 331 if (!flushAccumulatedRegion()) { 335 rootJ.repaint(); 338 } else { 339 super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip); 340 } 341 } 342 } 343 344 public void beginPaint() { 345 synchronized(this) { 346 painting = true; 347 while(showing) { 350 try { 351 wait(); 352 } catch (InterruptedException ie) { 353 } 354 } 355 } 356 if (LOGGER.isLoggable(Level.FINEST)) { 357 LOGGER.finest("beginPaint"); 358 } 359 resetAccumulated(); 361 } 362 363 public void endPaint() { 364 if (LOGGER.isLoggable(Level.FINEST)) { 365 LOGGER.finest("endPaint: region " + accumulatedX + " " + 366 accumulatedY + " " + accumulatedMaxX + " " + 367 accumulatedMaxY); 368 } 369 if (painting) { 370 if (!flushAccumulatedRegion()) { 371 if (!isRepaintingRoot()) { 372 repaintRoot(rootJ); 373 } 374 else { 375 resetDoubleBufferPerWindow(); 377 rootJ.repaint(); 379 } 380 } 381 } 382 383 BufferInfo toDispose = null; 384 synchronized(this) { 385 painting = false; 386 if (disposeBufferOnEnd) { 387 disposeBufferOnEnd = false; 388 toDispose = bufferInfo; 389 bufferInfos.remove(toDispose); 390 } 391 } 392 if (toDispose != null) { 393 toDispose.dispose(); 394 } 395 } 396 397 402 private boolean flushAccumulatedRegion() { 403 boolean success = true; 404 if (accumulatedX != Integer.MAX_VALUE) { 405 SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy; 406 boolean contentsLost = bufferStrategy.contentsLost(); 407 if (!contentsLost) { 408 bsSubRegion.show(accumulatedX, accumulatedY, 409 accumulatedMaxX, accumulatedMaxY); 410 contentsLost = bufferStrategy.contentsLost(); 411 } 412 if (contentsLost) { 413 if (LOGGER.isLoggable(Level.FINER)) { 414 LOGGER.finer("endPaint: contents lost"); 415 } 416 bufferInfo.setInSync(false); 418 success = false; 419 } 420 } 421 resetAccumulated(); 422 return success; 423 } 424 425 private void resetAccumulated() { 426 accumulatedX = Integer.MAX_VALUE; 427 accumulatedY = Integer.MAX_VALUE; 428 accumulatedMaxX = 0; 429 accumulatedMaxY = 0; 430 } 431 432 438 public void doubleBufferingChanged(final JRootPane rootPane) { 439 if ((!rootPane.isDoubleBuffered() || 440 !rootPane.getUseTrueDoubleBuffering()) && 441 rootPane.getParent() != null) { 442 if (!SwingUtilities.isEventDispatchThread()) { 443 Runnable updater = new Runnable () { 444 public void run() { 445 doubleBufferingChanged0(rootPane); 446 } 447 }; 448 SwingUtilities.invokeLater(updater); 449 } 450 else { 451 doubleBufferingChanged0(rootPane); 452 } 453 } 454 } 455 456 459 private void doubleBufferingChanged0(JRootPane rootPane) { 460 BufferInfo info; 462 synchronized(this) { 463 while(showing) { 466 try { 467 wait(); 468 } catch (InterruptedException ie) { 469 } 470 } 471 info = getBufferInfo(rootPane.getParent()); 472 if (painting && bufferInfo == info) { 473 disposeBufferOnEnd = true; 478 info = null; 479 } else if (info != null) { 480 bufferInfos.remove(info); 481 } 482 } 483 if (info != null) { 484 info.dispose(); 485 } 486 } 487 488 493 private boolean prepare(JComponent c, boolean isPaint, int x, int y, 494 int w, int h) { 495 if (bsg != null) { 496 bsg.dispose(); 497 bsg = null; 498 } 499 bufferStrategy = null; 500 if (fetchRoot(c)) { 501 boolean contentsLost = false; 502 BufferInfo bufferInfo = getBufferInfo(root); 503 if (bufferInfo == null) { 504 contentsLost = true; 505 bufferInfo = new BufferInfo(root); 506 bufferInfos.add(bufferInfo); 507 if (LOGGER.isLoggable(Level.FINER)) { 508 LOGGER.finer("prepare: new BufferInfo: " + root); 509 } 510 } 511 this.bufferInfo = bufferInfo; 512 if (!bufferInfo.hasBufferStrategyChanged()) { 513 bufferStrategy = bufferInfo.getBufferStrategy(true); 514 if (bufferStrategy != null) { 515 bsg = bufferStrategy.getDrawGraphics(); 516 if (bufferStrategy.contentsRestored()) { 517 contentsLost = true; 518 if (LOGGER.isLoggable(Level.FINER)) { 519 LOGGER.finer( 520 "prepare: contents restored in prepare"); 521 } 522 } 523 } 524 else { 525 return false; 528 } 529 if (bufferInfo.getContentsLostDuringExpose()) { 530 contentsLost = true; 531 bufferInfo.setContentsLostDuringExpose(false); 532 if (LOGGER.isLoggable(Level.FINER)) { 533 LOGGER.finer("prepare: contents lost on expose"); 534 } 535 } 536 if (isPaint && c == rootJ && x == 0 && y == 0 && 537 c.getWidth() == w && c.getHeight() == h) { 538 bufferInfo.setInSync(true); 539 } 540 else if (contentsLost) { 541 bufferInfo.setInSync(false); 546 if (!isRepaintingRoot()) { 547 repaintRoot(rootJ); 548 } 549 else { 550 resetDoubleBufferPerWindow(); 552 } 553 } 554 return (bufferInfos != null); 555 } 556 } 557 return false; 558 } 559 560 private boolean fetchRoot(JComponent c) { 561 boolean encounteredHW = false; 562 rootJ = c; 563 root = c; 564 xOffset = yOffset = 0; 565 while (root != null && (!(root instanceof Window) && 566 !(root instanceof Applet ))) { 567 xOffset += root.getX(); 568 yOffset += root.getY(); 569 root = root.getParent(); 570 if (root != null) { 571 if (root instanceof JComponent ) { 572 rootJ = (JComponent )root; 573 } 574 else if (!root.isLightweight()) { 575 if (!encounteredHW) { 576 encounteredHW = true; 577 } 578 else { 579 return false; 590 } 591 } 592 } 593 } 594 if ((root instanceof RootPaneContainer ) && 595 (rootJ instanceof JRootPane )) { 596 if (rootJ.isDoubleBuffered() && 600 ((JRootPane )rootJ).getUseTrueDoubleBuffering()) { 601 return true; 606 } 607 } 608 return false; 610 } 611 612 615 private void resetDoubleBufferPerWindow() { 616 if (bufferInfos != null) { 617 dispose(bufferInfos); 618 bufferInfos = null; 619 repaintManager.setPaintManager(null); 620 } 621 } 622 623 627 private BufferInfo getBufferInfo(Container root) { 628 for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) { 629 BufferInfo bufferInfo = bufferInfos.get(counter); 630 Container biRoot = bufferInfo.getRoot(); 631 if (biRoot == null) { 632 bufferInfos.remove(counter); 634 if (LOGGER.isLoggable(Level.FINER)) { 635 LOGGER.finer("BufferInfo pruned, root null"); 636 } 637 } 638 else if (biRoot == root) { 639 return bufferInfo; 640 } 641 } 642 return null; 643 } 644 645 private void accumulate(int x, int y, int w, int h) { 646 accumulatedX = Math.min(x, accumulatedX); 647 accumulatedY = Math.min(y, accumulatedY); 648 accumulatedMaxX = Math.max(accumulatedMaxX, x + w); 649 accumulatedMaxY = Math.max(accumulatedMaxY, y + h); 650 } 651 652 653 654 661 private class BufferInfo extends ComponentAdapter implements 662 WindowListener { 663 private WeakReference <BufferStrategy> weakBS; 670 private WeakReference <Container> root; 671 private boolean usingFlip; 673 private boolean inSync; 676 private boolean contentsLostDuringExpose; 678 private boolean paintAllOnExpose; 680 681 682 public BufferInfo(Container root) { 683 this.root = new WeakReference <Container>(root); 684 root.addComponentListener(this); 685 if (root instanceof Window) { 686 ((Window)root).addWindowListener(this); 687 } 688 } 689 690 public void setPaintAllOnExpose(boolean paintAllOnExpose) { 691 this.paintAllOnExpose = paintAllOnExpose; 692 } 693 694 public boolean getPaintAllOnExpose() { 695 return paintAllOnExpose; 696 } 697 698 public void setContentsLostDuringExpose(boolean value) { 699 contentsLostDuringExpose = value; 700 } 701 702 public boolean getContentsLostDuringExpose() { 703 return contentsLostDuringExpose; 704 } 705 706 public void setInSync(boolean inSync) { 707 this.inSync = inSync; 708 } 709 710 715 public boolean isInSync() { 716 return inSync; 717 } 718 719 722 public Container getRoot() { 723 return (root == null) ? null : root.get(); 724 } 725 726 735 public BufferStrategy getBufferStrategy(boolean create) { 736 BufferStrategy bs = (weakBS == null) ? null : weakBS.get(); 737 if (bs == null && create) { 738 bs = createBufferStrategy(); 739 if (bs != null) { 740 weakBS = new WeakReference <BufferStrategy>(bs); 741 } 742 if (LOGGER.isLoggable(Level.FINER)) { 743 LOGGER.finer("getBufferStrategy: created bs: " + bs); 744 } 745 } 746 return bs; 747 } 748 749 752 public boolean usingFlip() { 753 return usingFlip; 754 } 755 756 760 public boolean hasBufferStrategyChanged() { 761 Container root = getRoot(); 762 if (root != null) { 763 BufferStrategy ourBS = null; 764 BufferStrategy componentBS = null; 765 766 ourBS = getBufferStrategy(false); 767 if (root instanceof Window) { 768 componentBS = ((Window)root).getBufferStrategy(); 769 } 770 else { 771 try { 772 componentBS = (BufferStrategy) 773 getGetBufferStrategyMethod().invoke(root); 774 } catch (InvocationTargetException ite) { 775 assert false; 776 } catch (IllegalArgumentException iae) { 777 assert false; 778 } catch (IllegalAccessException iae2) { 779 assert false; 780 } 781 } 782 if (componentBS != ourBS) { 783 if (ourBS != null) { 785 ourBS.dispose(); 786 } 787 weakBS = null; 788 return true; 789 } 790 } 791 return false; 792 } 793 794 799 private BufferStrategy createBufferStrategy() { 800 BufferCapabilities caps; 801 Container root = getRoot(); 802 if (root == null) { 803 return null; 804 } 805 BufferStrategy bs = null; 806 if (TRY_FLIP) { 807 bs = createBufferStrategy(root,BufferCapabilities.FlipContents. 808 COPIED); 809 usingFlip = true; 810 if (LOGGER.isLoggable(Level.FINER)) { 811 LOGGER.finer("createBufferStrategy: using flip strategy"); 812 } 813 } 814 if (bs == null) { 815 bs = createBufferStrategy(root, null); 816 usingFlip = false; 817 } 818 if (!(bs instanceof SubRegionShowable)) { 819 bs = null; 825 } 826 return bs; 827 } 828 829 private BufferStrategy createBufferStrategy(Container root, 833 BufferCapabilities.FlipContents type) { 834 BufferCapabilities caps = new BufferCapabilities( 835 new ImageCapabilities(true), 836 new ImageCapabilities(true), 837 type); 838 BufferStrategy bs = null; 839 if (root instanceof Applet ) { 840 try { 841 getCreateBufferStrategyMethod().invoke(root, 2, caps); 842 bs = (BufferStrategy)getGetBufferStrategyMethod(). 843 invoke(root); 844 } catch (InvocationTargetException ite) { 845 if (LOGGER.isLoggable(Level.FINER)) { 847 LOGGER.log(Level.FINER, "createBufferStratety failed", 848 ite); 849 } 850 } catch (IllegalArgumentException iae) { 851 assert false; 852 } catch (IllegalAccessException iae2) { 853 assert false; 854 } 855 } 856 else { 857 try { 858 ((Window)root).createBufferStrategy(2, caps); 859 bs = ((Window)root).getBufferStrategy(); 860 } catch (AWTException e) { 861 if (LOGGER.isLoggable(Level.FINER)) { 863 LOGGER.log(Level.FINER, "createBufferStratety failed", 864 e); 865 } 866 } 867 } 868 return bs; 869 } 870 871 874 public void dispose() { 875 Container root = getRoot(); 876 if (LOGGER.isLoggable(Level.FINER)) { 877 LOGGER.log(Level.FINER, "disposed BufferInfo for: " + root); 878 } 879 if (root != null) { 880 root.removeComponentListener(this); 881 if (root instanceof Window) { 882 ((Window)root).removeWindowListener(this); 883 } 884 BufferStrategy bs = getBufferStrategy(false); 885 if (bs != null) { 886 bs.dispose(); 887 } 888 } 889 this.root = null; 890 weakBS = null; 891 } 892 893 public void componentHidden(ComponentEvent e) { 900 Container root = getRoot(); 901 if (root != null && root.isVisible()) { 902 root.repaint(); 911 } 912 else { 913 setPaintAllOnExpose(true); 914 } 915 } 916 917 public void windowIconified(WindowEvent e) { 918 setPaintAllOnExpose(true); 919 } 920 921 public void windowClosed(WindowEvent e) { 923 synchronized(BufferStrategyPaintManager.this) { 925 while (showing) { 926 try { 927 BufferStrategyPaintManager.this.wait(); 928 } catch (InterruptedException ie) { 929 } 930 } 931 bufferInfos.remove(this); 932 } 933 dispose(); 934 } 935 936 public void windowOpened(WindowEvent e) { 937 } 938 939 public void windowClosing(WindowEvent e) { 940 } 941 942 public void windowDeiconified(WindowEvent e) { 943 } 944 945 public void windowActivated(WindowEvent e) { 946 } 947 948 public void windowDeactivated(WindowEvent e) { 949 } 950 } 951 } 952 | Popular Tags |