src/share/classes/javax/swing/BufferStrategyPaintManager.java

Print this page




 198         // invokeLater.
 199         SwingUtilities.invokeLater(new Runnable() {
 200             public void run() {
 201                 java.util.List<BufferInfo> bufferInfos;
 202                 synchronized(BufferStrategyPaintManager.this) {
 203                     while (showing) {
 204                         try {
 205                             BufferStrategyPaintManager.this.wait();
 206                         } catch (InterruptedException ie) {
 207                         }
 208                     }
 209                     bufferInfos = BufferStrategyPaintManager.this.bufferInfos;
 210                     BufferStrategyPaintManager.this.bufferInfos = null;
 211                 }
 212                 dispose(bufferInfos);
 213             }
 214         });
 215     }
 216 
 217     private void dispose(java.util.List<BufferInfo> bufferInfos) {
 218         if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 219             LOGGER.finer("BufferStrategyPaintManager disposed",
 220                          new RuntimeException());
 221         }
 222         if (bufferInfos != null) {
 223             for (BufferInfo bufferInfo : bufferInfos) {
 224                 bufferInfo.dispose();
 225             }
 226         }
 227     }
 228 
 229     /**
 230      * Shows the specified region of the back buffer.  This will return
 231      * true if successful, false otherwise.  This is invoked on the
 232      * toolkit thread in response to an expose event.
 233      */
 234     public boolean show(Container c, int x, int y, int w, int h) {
 235         synchronized(this) {
 236             if (painting) {
 237                 // Don't show from backbuffer while in the process of
 238                 // painting.


 283                 int cy = ((SunGraphics2D)bsg).constrainY;
 284                 if (cx != 0 || cy != 0) {
 285                     bsg.translate(-cx, -cy);
 286                 }
 287                 ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,
 288                                                x + w, y + h);
 289                 bsg.setClip(x, y, w, h);
 290                 paintingComponent.paintToOffscreen(bsg, x, y, w, h,
 291                                                    x + w, y + h);
 292                 accumulate(xOffset + x, yOffset + y, w, h);
 293                 return true;
 294             } else {
 295                 // Assume they are going to eventually render to the screen.
 296                 // This disables showing from backbuffer until a complete
 297                 // repaint occurs.
 298                 bufferInfo.setInSync(false);
 299                 // Fall through to old rendering.
 300             }
 301         }
 302         // Invalid root, do what Swing has always done.
 303         if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 304             LOGGER.finer("prepare failed");
 305         }
 306         return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);
 307     }
 308 
 309     public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,
 310                          int deltaX, int deltaY, boolean clip) {
 311         // Note: this method is only called internally and we know that
 312         // g is from a heavyweight Component, so no check is necessary as
 313         // it is in paint() above.
 314         //
 315         // If the buffer isn't in sync there is no point in doing a copyArea,
 316         // it has garbage.
 317         Container root = fetchRoot(c);
 318 
 319         if (prepare(c, root, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {
 320             if (clip) {
 321                 Rectangle cBounds = c.getVisibleRect();
 322                 int relX = xOffset + x;
 323                 int relY = yOffset + y;
 324                 bsg.clipRect(xOffset + cBounds.x,
 325                              yOffset + cBounds.y,
 326                              cBounds.width, cBounds.height);
 327                 bsg.copyArea(relX, relY, w, h, deltaX, deltaY);
 328             }
 329             else {
 330                 bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,
 331                              deltaY);
 332             }
 333             accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);
 334         } else {
 335             if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 336                 LOGGER.finer("copyArea: prepare failed or not in sync");
 337             }
 338             // Prepare failed, or not in sync. By calling super.copyArea
 339             // we'll copy on screen. We need to flush any pending paint to
 340             // the screen otherwise we'll do a copyArea on the wrong thing.
 341             if (!flushAccumulatedRegion()) {
 342                 // Flush failed, copyArea will be copying garbage,
 343                 // force repaint of all.
 344                 rootJ.repaint();
 345             } else {
 346                 super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);
 347             }
 348         }
 349     }
 350 
 351     public void beginPaint() {
 352         synchronized(this) {
 353             painting = true;
 354             // Make sure another thread isn't attempting to show from
 355             // the back buffer.
 356             while(showing) {
 357                 try {
 358                     wait();
 359                 } catch (InterruptedException ie) {
 360                 }
 361             }
 362         }
 363         if (LOGGER.isLoggable(PlatformLogger.FINEST)) {
 364             LOGGER.finest("beginPaint");
 365         }
 366         // Reset the area that needs to be painted.
 367         resetAccumulated();
 368     }
 369 
 370     public void endPaint() {
 371         if (LOGGER.isLoggable(PlatformLogger.FINEST)) {
 372             LOGGER.finest("endPaint: region " + accumulatedX + " " +
 373                        accumulatedY + " " +  accumulatedMaxX + " " +
 374                        accumulatedMaxY);
 375         }
 376         if (painting) {
 377             if (!flushAccumulatedRegion()) {
 378                 if (!isRepaintingRoot()) {
 379                     repaintRoot(rootJ);
 380                 }
 381                 else {
 382                     // Contents lost twice in a row, punt.
 383                     resetDoubleBufferPerWindow();
 384                     // In case we've left junk on the screen, force a repaint.
 385                     rootJ.repaint();
 386                 }
 387             }
 388         }
 389 
 390         BufferInfo toDispose = null;
 391         synchronized(this) {


 400             toDispose.dispose();
 401         }
 402     }
 403 
 404     /**
 405      * Renders the BufferStrategy to the screen.
 406      *
 407      * @return true if successful, false otherwise.
 408      */
 409     private boolean flushAccumulatedRegion() {
 410         boolean success = true;
 411         if (accumulatedX != Integer.MAX_VALUE) {
 412             SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;
 413             boolean contentsLost = bufferStrategy.contentsLost();
 414             if (!contentsLost) {
 415                 bsSubRegion.show(accumulatedX, accumulatedY,
 416                                  accumulatedMaxX, accumulatedMaxY);
 417                 contentsLost = bufferStrategy.contentsLost();
 418             }
 419             if (contentsLost) {
 420                 if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 421                     LOGGER.finer("endPaint: contents lost");
 422                 }
 423                 // Shown region was bogus, mark buffer as out of sync.
 424                 bufferInfo.setInSync(false);
 425                 success = false;
 426             }
 427         }
 428         resetAccumulated();
 429         return success;
 430     }
 431 
 432     private void resetAccumulated() {
 433         accumulatedX = Integer.MAX_VALUE;
 434         accumulatedY = Integer.MAX_VALUE;
 435         accumulatedMaxX = 0;
 436         accumulatedMaxY = 0;
 437     }
 438 
 439     /**
 440      * Invoked when the double buffering or useTrueDoubleBuffering


 494 
 495     /**
 496      * Calculates information common to paint/copyArea.
 497      *
 498      * @return true if should use buffering per window in painting.
 499      */
 500     private boolean prepare(JComponent c, Container root, boolean isPaint, int x, int y,
 501                             int w, int h) {
 502         if (bsg != null) {
 503             bsg.dispose();
 504             bsg = null;
 505         }
 506         bufferStrategy = null;
 507         if (root != null) {
 508             boolean contentsLost = false;
 509             BufferInfo bufferInfo = getBufferInfo(root);
 510             if (bufferInfo == null) {
 511                 contentsLost = true;
 512                 bufferInfo = new BufferInfo(root);
 513                 bufferInfos.add(bufferInfo);
 514                 if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 515                     LOGGER.finer("prepare: new BufferInfo: " + root);
 516                 }
 517             }
 518             this.bufferInfo = bufferInfo;
 519             if (!bufferInfo.hasBufferStrategyChanged()) {
 520                 bufferStrategy = bufferInfo.getBufferStrategy(true);
 521                 if (bufferStrategy != null) {
 522                     bsg = bufferStrategy.getDrawGraphics();
 523                     if (bufferStrategy.contentsRestored()) {
 524                         contentsLost = true;
 525                         if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 526                             LOGGER.finer("prepare: contents restored in prepare");
 527                         }
 528                     }
 529                 }
 530                 else {
 531                     // Couldn't create BufferStrategy, fallback to normal
 532                     // painting.
 533                     return false;
 534                 }
 535                 if (bufferInfo.getContentsLostDuringExpose()) {
 536                     contentsLost = true;
 537                     bufferInfo.setContentsLostDuringExpose(false);
 538                     if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 539                         LOGGER.finer("prepare: contents lost on expose");
 540                     }
 541                 }
 542                 if (isPaint && c == rootJ && x == 0 && y == 0 &&
 543                       c.getWidth() == w && c.getHeight() == h) {
 544                     bufferInfo.setInSync(true);
 545                 }
 546                 else if (contentsLost) {
 547                     // We either recreated the BufferStrategy, or the contents
 548                     // of the buffer strategy were restored.  We need to
 549                     // repaint the root pane so that the back buffer is in sync
 550                     // again.
 551                     bufferInfo.setInSync(false);
 552                     if (!isRepaintingRoot()) {
 553                         repaintRoot(rootJ);
 554                     }
 555                     else {
 556                         // Contents lost twice in a row, punt
 557                         resetDoubleBufferPerWindow();
 558                     }


 621      */
 622     private void resetDoubleBufferPerWindow() {
 623         if (bufferInfos != null) {
 624             dispose(bufferInfos);
 625             bufferInfos = null;
 626             repaintManager.setPaintManager(null);
 627         }
 628     }
 629 
 630     /**
 631      * Returns the BufferInfo for the specified root or null if one
 632      * hasn't been created yet.
 633      */
 634     private BufferInfo getBufferInfo(Container root) {
 635         for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {
 636             BufferInfo bufferInfo = bufferInfos.get(counter);
 637             Container biRoot = bufferInfo.getRoot();
 638             if (biRoot == null) {
 639                 // Window gc'ed
 640                 bufferInfos.remove(counter);
 641                 if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 642                     LOGGER.finer("BufferInfo pruned, root null");
 643                 }
 644             }
 645             else if (biRoot == root) {
 646                 return bufferInfo;
 647             }
 648         }
 649         return null;
 650     }
 651 
 652     private void accumulate(int x, int y, int w, int h) {
 653         accumulatedX = Math.min(x, accumulatedX);
 654         accumulatedY = Math.min(y, accumulatedY);
 655         accumulatedMaxX = Math.max(accumulatedMaxX, x + w);
 656         accumulatedMaxY = Math.max(accumulatedMaxY, y + h);
 657     }
 658 
 659 
 660 
 661     /**


 727         public Container getRoot() {
 728             return (root == null) ? null : root.get();
 729         }
 730 
 731         /**
 732          * Returns the BufferStartegy.  This will return null if
 733          * the BufferStartegy hasn't been created and <code>create</code> is
 734          * false, or if there is a problem in creating the
 735          * <code>BufferStartegy</code>.
 736          *
 737          * @param create If true, and the BufferStartegy is currently null,
 738          *               one will be created.
 739          */
 740         public BufferStrategy getBufferStrategy(boolean create) {
 741             BufferStrategy bs = (weakBS == null) ? null : weakBS.get();
 742             if (bs == null && create) {
 743                 bs = createBufferStrategy();
 744                 if (bs != null) {
 745                     weakBS = new WeakReference<BufferStrategy>(bs);
 746                 }
 747                 if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 748                     LOGGER.finer("getBufferStrategy: created bs: " + bs);
 749                 }
 750             }
 751             return bs;
 752         }
 753 
 754         /**
 755          * Returns true if the buffer strategy of the component differs
 756          * from current buffer strategy.
 757          */
 758         public boolean hasBufferStrategyChanged() {
 759             Container root = getRoot();
 760             if (root != null) {
 761                 BufferStrategy ourBS = null;
 762                 BufferStrategy componentBS = null;
 763 
 764                 ourBS = getBufferStrategy(false);
 765                 if (root instanceof Window) {
 766                     componentBS = ((Window)root).getBufferStrategy();
 767                 }


 785                     weakBS = null;
 786                     return true;
 787                 }
 788             }
 789             return false;
 790         }
 791 
 792         /**
 793          * Creates the BufferStrategy.  If the appropriate system property
 794          * has been set we'll try for flip first and then we'll try for
 795          * blit.
 796          */
 797         private BufferStrategy createBufferStrategy() {
 798             Container root = getRoot();
 799             if (root == null) {
 800                 return null;
 801             }
 802             BufferStrategy bs = null;
 803             if (SwingUtilities3.isVsyncRequested(root)) {
 804                 bs = createBufferStrategy(root, true);
 805                 if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 806                     LOGGER.finer("createBufferStrategy: using vsynced strategy");
 807                 }
 808             }
 809             if (bs == null) {
 810                 bs = createBufferStrategy(root, false);
 811             }
 812             if (!(bs instanceof SubRegionShowable)) {
 813                 // We do this for two reasons:
 814                 // 1. So that we know we can cast to SubRegionShowable and
 815                 //    invoke show with the minimal region to update
 816                 // 2. To avoid the possibility of invoking client code
 817                 //    on the toolkit thread.
 818                 bs = null;
 819             }
 820             return bs;
 821         }
 822 
 823         // Creates and returns a buffer strategy.  If
 824         // there is a problem creating the buffer strategy this will
 825         // eat the exception and return null.


 827                 boolean isVsynced) {
 828             BufferCapabilities caps;
 829             if (isVsynced) {
 830                 caps = new ExtendedBufferCapabilities(
 831                     new ImageCapabilities(true), new ImageCapabilities(true),
 832                     BufferCapabilities.FlipContents.COPIED,
 833                     ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
 834             } else {
 835                 caps = new BufferCapabilities(
 836                     new ImageCapabilities(true), new ImageCapabilities(true),
 837                     null);
 838             }
 839             BufferStrategy bs = null;
 840             if (SunToolkit.isInstanceOf(root, "java.applet.Applet")) {
 841                 try {
 842                     getCreateBufferStrategyMethod().invoke(root, 2, caps);
 843                     bs = (BufferStrategy)getGetBufferStrategyMethod().
 844                                             invoke(root);
 845                 } catch (InvocationTargetException ite) {
 846                     // Type is not supported
 847                     if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 848                         LOGGER.finer("createBufferStratety failed",
 849                                      ite);
 850                     }
 851                 } catch (IllegalArgumentException iae) {
 852                     assert false;
 853                 } catch (IllegalAccessException iae2) {
 854                     assert false;
 855                 }
 856             }
 857             else {
 858                 try {
 859                     ((Window)root).createBufferStrategy(2, caps);
 860                     bs = ((Window)root).getBufferStrategy();
 861                 } catch (AWTException e) {
 862                     // Type not supported
 863                     if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 864                         LOGGER.finer("createBufferStratety failed",
 865                                      e);
 866                     }
 867                 }
 868             }
 869             return bs;
 870         }
 871 
 872         /**
 873          * Cleans up and removes any references.
 874          */
 875         public void dispose() {
 876             Container root = getRoot();
 877             if (LOGGER.isLoggable(PlatformLogger.FINER)) {
 878                 LOGGER.finer("disposed BufferInfo for: " + root);
 879             }
 880             if (root != null) {
 881                 root.removeComponentListener(this);
 882                 if (root instanceof Window) {
 883                     ((Window)root).removeWindowListener(this);
 884                 }
 885                 BufferStrategy bs = getBufferStrategy(false);
 886                 if (bs != null) {
 887                     bs.dispose();
 888                 }
 889             }
 890             this.root = null;
 891             weakBS = null;
 892         }
 893 
 894         // We mark the buffer as needing to be painted on a hide/iconify
 895         // because the developer may have conditionalized painting based on
 896         // visibility.
 897         // Ideally we would also move to having the BufferStrategy being




 198         // invokeLater.
 199         SwingUtilities.invokeLater(new Runnable() {
 200             public void run() {
 201                 java.util.List<BufferInfo> bufferInfos;
 202                 synchronized(BufferStrategyPaintManager.this) {
 203                     while (showing) {
 204                         try {
 205                             BufferStrategyPaintManager.this.wait();
 206                         } catch (InterruptedException ie) {
 207                         }
 208                     }
 209                     bufferInfos = BufferStrategyPaintManager.this.bufferInfos;
 210                     BufferStrategyPaintManager.this.bufferInfos = null;
 211                 }
 212                 dispose(bufferInfos);
 213             }
 214         });
 215     }
 216 
 217     private void dispose(java.util.List<BufferInfo> bufferInfos) {
 218         if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 219             LOGGER.finer("BufferStrategyPaintManager disposed",
 220                          new RuntimeException());
 221         }
 222         if (bufferInfos != null) {
 223             for (BufferInfo bufferInfo : bufferInfos) {
 224                 bufferInfo.dispose();
 225             }
 226         }
 227     }
 228 
 229     /**
 230      * Shows the specified region of the back buffer.  This will return
 231      * true if successful, false otherwise.  This is invoked on the
 232      * toolkit thread in response to an expose event.
 233      */
 234     public boolean show(Container c, int x, int y, int w, int h) {
 235         synchronized(this) {
 236             if (painting) {
 237                 // Don't show from backbuffer while in the process of
 238                 // painting.


 283                 int cy = ((SunGraphics2D)bsg).constrainY;
 284                 if (cx != 0 || cy != 0) {
 285                     bsg.translate(-cx, -cy);
 286                 }
 287                 ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,
 288                                                x + w, y + h);
 289                 bsg.setClip(x, y, w, h);
 290                 paintingComponent.paintToOffscreen(bsg, x, y, w, h,
 291                                                    x + w, y + h);
 292                 accumulate(xOffset + x, yOffset + y, w, h);
 293                 return true;
 294             } else {
 295                 // Assume they are going to eventually render to the screen.
 296                 // This disables showing from backbuffer until a complete
 297                 // repaint occurs.
 298                 bufferInfo.setInSync(false);
 299                 // Fall through to old rendering.
 300             }
 301         }
 302         // Invalid root, do what Swing has always done.
 303         if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 304             LOGGER.finer("prepare failed");
 305         }
 306         return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);
 307     }
 308 
 309     public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,
 310                          int deltaX, int deltaY, boolean clip) {
 311         // Note: this method is only called internally and we know that
 312         // g is from a heavyweight Component, so no check is necessary as
 313         // it is in paint() above.
 314         //
 315         // If the buffer isn't in sync there is no point in doing a copyArea,
 316         // it has garbage.
 317         Container root = fetchRoot(c);
 318 
 319         if (prepare(c, root, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {
 320             if (clip) {
 321                 Rectangle cBounds = c.getVisibleRect();
 322                 int relX = xOffset + x;
 323                 int relY = yOffset + y;
 324                 bsg.clipRect(xOffset + cBounds.x,
 325                              yOffset + cBounds.y,
 326                              cBounds.width, cBounds.height);
 327                 bsg.copyArea(relX, relY, w, h, deltaX, deltaY);
 328             }
 329             else {
 330                 bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,
 331                              deltaY);
 332             }
 333             accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);
 334         } else {
 335             if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 336                 LOGGER.finer("copyArea: prepare failed or not in sync");
 337             }
 338             // Prepare failed, or not in sync. By calling super.copyArea
 339             // we'll copy on screen. We need to flush any pending paint to
 340             // the screen otherwise we'll do a copyArea on the wrong thing.
 341             if (!flushAccumulatedRegion()) {
 342                 // Flush failed, copyArea will be copying garbage,
 343                 // force repaint of all.
 344                 rootJ.repaint();
 345             } else {
 346                 super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);
 347             }
 348         }
 349     }
 350 
 351     public void beginPaint() {
 352         synchronized(this) {
 353             painting = true;
 354             // Make sure another thread isn't attempting to show from
 355             // the back buffer.
 356             while(showing) {
 357                 try {
 358                     wait();
 359                 } catch (InterruptedException ie) {
 360                 }
 361             }
 362         }
 363         if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
 364             LOGGER.finest("beginPaint");
 365         }
 366         // Reset the area that needs to be painted.
 367         resetAccumulated();
 368     }
 369 
 370     public void endPaint() {
 371         if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
 372             LOGGER.finest("endPaint: region " + accumulatedX + " " +
 373                        accumulatedY + " " +  accumulatedMaxX + " " +
 374                        accumulatedMaxY);
 375         }
 376         if (painting) {
 377             if (!flushAccumulatedRegion()) {
 378                 if (!isRepaintingRoot()) {
 379                     repaintRoot(rootJ);
 380                 }
 381                 else {
 382                     // Contents lost twice in a row, punt.
 383                     resetDoubleBufferPerWindow();
 384                     // In case we've left junk on the screen, force a repaint.
 385                     rootJ.repaint();
 386                 }
 387             }
 388         }
 389 
 390         BufferInfo toDispose = null;
 391         synchronized(this) {


 400             toDispose.dispose();
 401         }
 402     }
 403 
 404     /**
 405      * Renders the BufferStrategy to the screen.
 406      *
 407      * @return true if successful, false otherwise.
 408      */
 409     private boolean flushAccumulatedRegion() {
 410         boolean success = true;
 411         if (accumulatedX != Integer.MAX_VALUE) {
 412             SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;
 413             boolean contentsLost = bufferStrategy.contentsLost();
 414             if (!contentsLost) {
 415                 bsSubRegion.show(accumulatedX, accumulatedY,
 416                                  accumulatedMaxX, accumulatedMaxY);
 417                 contentsLost = bufferStrategy.contentsLost();
 418             }
 419             if (contentsLost) {
 420                 if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 421                     LOGGER.finer("endPaint: contents lost");
 422                 }
 423                 // Shown region was bogus, mark buffer as out of sync.
 424                 bufferInfo.setInSync(false);
 425                 success = false;
 426             }
 427         }
 428         resetAccumulated();
 429         return success;
 430     }
 431 
 432     private void resetAccumulated() {
 433         accumulatedX = Integer.MAX_VALUE;
 434         accumulatedY = Integer.MAX_VALUE;
 435         accumulatedMaxX = 0;
 436         accumulatedMaxY = 0;
 437     }
 438 
 439     /**
 440      * Invoked when the double buffering or useTrueDoubleBuffering


 494 
 495     /**
 496      * Calculates information common to paint/copyArea.
 497      *
 498      * @return true if should use buffering per window in painting.
 499      */
 500     private boolean prepare(JComponent c, Container root, boolean isPaint, int x, int y,
 501                             int w, int h) {
 502         if (bsg != null) {
 503             bsg.dispose();
 504             bsg = null;
 505         }
 506         bufferStrategy = null;
 507         if (root != null) {
 508             boolean contentsLost = false;
 509             BufferInfo bufferInfo = getBufferInfo(root);
 510             if (bufferInfo == null) {
 511                 contentsLost = true;
 512                 bufferInfo = new BufferInfo(root);
 513                 bufferInfos.add(bufferInfo);
 514                 if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 515                     LOGGER.finer("prepare: new BufferInfo: " + root);
 516                 }
 517             }
 518             this.bufferInfo = bufferInfo;
 519             if (!bufferInfo.hasBufferStrategyChanged()) {
 520                 bufferStrategy = bufferInfo.getBufferStrategy(true);
 521                 if (bufferStrategy != null) {
 522                     bsg = bufferStrategy.getDrawGraphics();
 523                     if (bufferStrategy.contentsRestored()) {
 524                         contentsLost = true;
 525                         if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 526                             LOGGER.finer("prepare: contents restored in prepare");
 527                         }
 528                     }
 529                 }
 530                 else {
 531                     // Couldn't create BufferStrategy, fallback to normal
 532                     // painting.
 533                     return false;
 534                 }
 535                 if (bufferInfo.getContentsLostDuringExpose()) {
 536                     contentsLost = true;
 537                     bufferInfo.setContentsLostDuringExpose(false);
 538                     if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 539                         LOGGER.finer("prepare: contents lost on expose");
 540                     }
 541                 }
 542                 if (isPaint && c == rootJ && x == 0 && y == 0 &&
 543                       c.getWidth() == w && c.getHeight() == h) {
 544                     bufferInfo.setInSync(true);
 545                 }
 546                 else if (contentsLost) {
 547                     // We either recreated the BufferStrategy, or the contents
 548                     // of the buffer strategy were restored.  We need to
 549                     // repaint the root pane so that the back buffer is in sync
 550                     // again.
 551                     bufferInfo.setInSync(false);
 552                     if (!isRepaintingRoot()) {
 553                         repaintRoot(rootJ);
 554                     }
 555                     else {
 556                         // Contents lost twice in a row, punt
 557                         resetDoubleBufferPerWindow();
 558                     }


 621      */
 622     private void resetDoubleBufferPerWindow() {
 623         if (bufferInfos != null) {
 624             dispose(bufferInfos);
 625             bufferInfos = null;
 626             repaintManager.setPaintManager(null);
 627         }
 628     }
 629 
 630     /**
 631      * Returns the BufferInfo for the specified root or null if one
 632      * hasn't been created yet.
 633      */
 634     private BufferInfo getBufferInfo(Container root) {
 635         for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {
 636             BufferInfo bufferInfo = bufferInfos.get(counter);
 637             Container biRoot = bufferInfo.getRoot();
 638             if (biRoot == null) {
 639                 // Window gc'ed
 640                 bufferInfos.remove(counter);
 641                 if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 642                     LOGGER.finer("BufferInfo pruned, root null");
 643                 }
 644             }
 645             else if (biRoot == root) {
 646                 return bufferInfo;
 647             }
 648         }
 649         return null;
 650     }
 651 
 652     private void accumulate(int x, int y, int w, int h) {
 653         accumulatedX = Math.min(x, accumulatedX);
 654         accumulatedY = Math.min(y, accumulatedY);
 655         accumulatedMaxX = Math.max(accumulatedMaxX, x + w);
 656         accumulatedMaxY = Math.max(accumulatedMaxY, y + h);
 657     }
 658 
 659 
 660 
 661     /**


 727         public Container getRoot() {
 728             return (root == null) ? null : root.get();
 729         }
 730 
 731         /**
 732          * Returns the BufferStartegy.  This will return null if
 733          * the BufferStartegy hasn't been created and <code>create</code> is
 734          * false, or if there is a problem in creating the
 735          * <code>BufferStartegy</code>.
 736          *
 737          * @param create If true, and the BufferStartegy is currently null,
 738          *               one will be created.
 739          */
 740         public BufferStrategy getBufferStrategy(boolean create) {
 741             BufferStrategy bs = (weakBS == null) ? null : weakBS.get();
 742             if (bs == null && create) {
 743                 bs = createBufferStrategy();
 744                 if (bs != null) {
 745                     weakBS = new WeakReference<BufferStrategy>(bs);
 746                 }
 747                 if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 748                     LOGGER.finer("getBufferStrategy: created bs: " + bs);
 749                 }
 750             }
 751             return bs;
 752         }
 753 
 754         /**
 755          * Returns true if the buffer strategy of the component differs
 756          * from current buffer strategy.
 757          */
 758         public boolean hasBufferStrategyChanged() {
 759             Container root = getRoot();
 760             if (root != null) {
 761                 BufferStrategy ourBS = null;
 762                 BufferStrategy componentBS = null;
 763 
 764                 ourBS = getBufferStrategy(false);
 765                 if (root instanceof Window) {
 766                     componentBS = ((Window)root).getBufferStrategy();
 767                 }


 785                     weakBS = null;
 786                     return true;
 787                 }
 788             }
 789             return false;
 790         }
 791 
 792         /**
 793          * Creates the BufferStrategy.  If the appropriate system property
 794          * has been set we'll try for flip first and then we'll try for
 795          * blit.
 796          */
 797         private BufferStrategy createBufferStrategy() {
 798             Container root = getRoot();
 799             if (root == null) {
 800                 return null;
 801             }
 802             BufferStrategy bs = null;
 803             if (SwingUtilities3.isVsyncRequested(root)) {
 804                 bs = createBufferStrategy(root, true);
 805                 if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 806                     LOGGER.finer("createBufferStrategy: using vsynced strategy");
 807                 }
 808             }
 809             if (bs == null) {
 810                 bs = createBufferStrategy(root, false);
 811             }
 812             if (!(bs instanceof SubRegionShowable)) {
 813                 // We do this for two reasons:
 814                 // 1. So that we know we can cast to SubRegionShowable and
 815                 //    invoke show with the minimal region to update
 816                 // 2. To avoid the possibility of invoking client code
 817                 //    on the toolkit thread.
 818                 bs = null;
 819             }
 820             return bs;
 821         }
 822 
 823         // Creates and returns a buffer strategy.  If
 824         // there is a problem creating the buffer strategy this will
 825         // eat the exception and return null.


 827                 boolean isVsynced) {
 828             BufferCapabilities caps;
 829             if (isVsynced) {
 830                 caps = new ExtendedBufferCapabilities(
 831                     new ImageCapabilities(true), new ImageCapabilities(true),
 832                     BufferCapabilities.FlipContents.COPIED,
 833                     ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
 834             } else {
 835                 caps = new BufferCapabilities(
 836                     new ImageCapabilities(true), new ImageCapabilities(true),
 837                     null);
 838             }
 839             BufferStrategy bs = null;
 840             if (SunToolkit.isInstanceOf(root, "java.applet.Applet")) {
 841                 try {
 842                     getCreateBufferStrategyMethod().invoke(root, 2, caps);
 843                     bs = (BufferStrategy)getGetBufferStrategyMethod().
 844                                             invoke(root);
 845                 } catch (InvocationTargetException ite) {
 846                     // Type is not supported
 847                     if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 848                         LOGGER.finer("createBufferStratety failed",
 849                                      ite);
 850                     }
 851                 } catch (IllegalArgumentException iae) {
 852                     assert false;
 853                 } catch (IllegalAccessException iae2) {
 854                     assert false;
 855                 }
 856             }
 857             else {
 858                 try {
 859                     ((Window)root).createBufferStrategy(2, caps);
 860                     bs = ((Window)root).getBufferStrategy();
 861                 } catch (AWTException e) {
 862                     // Type not supported
 863                     if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 864                         LOGGER.finer("createBufferStratety failed",
 865                                      e);
 866                     }
 867                 }
 868             }
 869             return bs;
 870         }
 871 
 872         /**
 873          * Cleans up and removes any references.
 874          */
 875         public void dispose() {
 876             Container root = getRoot();
 877             if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
 878                 LOGGER.finer("disposed BufferInfo for: " + root);
 879             }
 880             if (root != null) {
 881                 root.removeComponentListener(this);
 882                 if (root instanceof Window) {
 883                     ((Window)root).removeWindowListener(this);
 884                 }
 885                 BufferStrategy bs = getBufferStrategy(false);
 886                 if (bs != null) {
 887                     bs.dispose();
 888                 }
 889             }
 890             this.root = null;
 891             weakBS = null;
 892         }
 893 
 894         // We mark the buffer as needing to be painted on a hide/iconify
 895         // because the developer may have conditionalized painting based on
 896         // visibility.
 897         // Ideally we would also move to having the BufferStrategy being