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
|