36 import java.applet.*;
37
38 import jdk.internal.misc.JavaSecurityAccess;
39 import jdk.internal.misc.SharedSecrets;
40 import sun.awt.AWTAccessor;
41 import sun.awt.AppContext;
42 import sun.awt.DisplayChangedListener;
43 import sun.awt.SunToolkit;
44 import sun.java2d.SunGraphicsEnvironment;
45 import sun.security.action.GetPropertyAction;
46
47 import com.sun.java.swing.SwingUtilities3;
48 import sun.swing.SwingAccessor;
49 import sun.swing.SwingUtilities2.RepaintListener;
50
51 /**
52 * This class manages repaint requests, allowing the number
53 * of repaints to be minimized, for example by collapsing multiple
54 * requests into a single repaint for members of a component tree.
55 * <p>
56 * As of 1.6 <code>RepaintManager</code> handles repaint requests
57 * for Swing's top level components (<code>JApplet</code>,
58 * <code>JWindow</code>, <code>JFrame</code> and <code>JDialog</code>).
59 * Any calls to <code>repaint</code> on one of these will call into the
60 * appropriate <code>addDirtyRegion</code> method.
61 *
62 * @author Arnaud Weber
63 * @since 1.2
64 */
65 public class RepaintManager
66 {
67 /**
68 * Whether or not the RepaintManager should handle paint requests
69 * for top levels.
70 */
71 static final boolean HANDLE_TOP_LEVEL_PAINT;
72
73 private static final short BUFFER_STRATEGY_NOT_SPECIFIED = 0;
74 private static final short BUFFER_STRATEGY_SPECIFIED_ON = 1;
75 private static final short BUFFER_STRATEGY_SPECIFIED_OFF = 2;
76
77 private static final short BUFFER_STRATEGY_TYPE;
78
79 /**
80 * Maps from GraphicsConfiguration to VolatileImage.
122
123 private static final Object repaintManagerKey = RepaintManager.class;
124
125 // Whether or not a VolatileImage should be used for double-buffered painting
126 static boolean volatileImageBufferEnabled = true;
127 /**
128 * Type of VolatileImage which should be used for double-buffered
129 * painting.
130 */
131 private static final int volatileBufferType;
132 /**
133 * Value of the system property awt.nativeDoubleBuffering.
134 */
135 private static boolean nativeDoubleBuffering;
136
137 // The maximum number of times Swing will attempt to use the VolatileImage
138 // buffer during a paint operation.
139 private static final int VOLATILE_LOOP_MAX = 2;
140
141 /**
142 * Number of <code>beginPaint</code> that have been invoked.
143 */
144 private int paintDepth = 0;
145
146 /**
147 * Type of buffer strategy to use. Will be one of the BUFFER_STRATEGY_
148 * constants.
149 */
150 private short bufferStrategyType;
151
152 //
153 // BufferStrategyPaintManager has the unique characteristic that it
154 // must deal with the buffer being lost while painting to it. For
155 // example, if we paint a component and show it and the buffer has
156 // become lost we must repaint the whole window. To deal with that
157 // the PaintManager calls into repaintRoot, and if we're still in
158 // the process of painting the repaintRoot field is set to the JRootPane
159 // and after the current JComponent.paintImmediately call finishes
160 // paintImmediately will be invoked on the repaintRoot. In this
161 // way we don't try to show garbage to the screen.
162 //
163 /**
164 * True if we're in the process of painting the dirty regions. This is
165 * set to true in <code>paintDirtyRegions</code>.
166 */
167 private boolean painting;
168 /**
169 * If the PaintManager calls into repaintRoot during painting this field
170 * will be set to the root.
171 */
172 private JComponent repaintRoot;
173
174 /**
175 * The Thread that has initiated painting. If null it
176 * indicates painting is not currently in progress.
177 */
178 private Thread paintThread;
179
180 /**
181 * Runnable used to process all repaint/revalidate requests.
182 */
183 private final ProcessingRunnable processingRunnable;
184
185 private static final JavaSecurityAccess javaSecurityAccess =
475 * will be unioned with the region that should be redrawn.
476 *
477 * @param c Component to repaint, null results in nothing happening.
478 * @param x X coordinate of the region to repaint
479 * @param y Y coordinate of the region to repaint
480 * @param w Width of the region to repaint
481 * @param h Height of the region to repaint
482 * @see JComponent#repaint
483 */
484 public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
485 {
486 RepaintManager delegate = getDelegate(c);
487 if (delegate != null) {
488 delegate.addDirtyRegion(c, x, y, w, h);
489 return;
490 }
491 addDirtyRegion0(c, x, y, w, h);
492 }
493
494 /**
495 * Adds <code>window</code> to the list of <code>Component</code>s that
496 * need to be repainted.
497 *
498 * @param window Window to repaint, null results in nothing happening.
499 * @param x X coordinate of the region to repaint
500 * @param y Y coordinate of the region to repaint
501 * @param w Width of the region to repaint
502 * @param h Height of the region to repaint
503 * @see JFrame#repaint
504 * @see JWindow#repaint
505 * @see JDialog#repaint
506 * @since 1.6
507 */
508 public void addDirtyRegion(Window window, int x, int y, int w, int h) {
509 addDirtyRegion0(window, x, y, w, h);
510 }
511
512 /**
513 * Adds <code>applet</code> to the list of <code>Component</code>s that
514 * need to be repainted.
515 *
516 * @param applet Applet to repaint, null results in nothing happening.
517 * @param x X coordinate of the region to repaint
518 * @param y Y coordinate of the region to repaint
519 * @param w Width of the region to repaint
520 * @param h Height of the region to repaint
521 * @see JApplet#repaint
522 * @since 1.6
523 */
524 public void addDirtyRegion(Applet applet, int x, int y, int w, int h) {
525 addDirtyRegion0(applet, x, y, w, h);
526 }
527
528 void scheduleHeavyWeightPaints() {
529 Map<Container,Rectangle> hws;
530
531 synchronized(this) {
532 if (hwDirtyComponents.size() == 0) {
533 return;
588 public void run() {
589 AccessControlContext stack = AccessController.getContext();
590 AccessControlContext acc =
591 AWTAccessor.getComponentAccessor().getAccessControlContext(c);
592 javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
593 public Void run() {
594 r.run();
595 return null;
596 }
597 }, stack, acc);
598 }
599 });
600 }
601 scheduleProcessingRunnable(appContext);
602 }
603
604 /**
605 * Extends the dirty region for the specified component to include
606 * the new region.
607 *
608 * @return false if <code>c</code> is not yet marked dirty.
609 */
610 private synchronized boolean extendDirtyRegion(
611 Component c, int x, int y, int w, int h) {
612 Rectangle r = dirtyComponents.get(c);
613 if (r != null) {
614 // A non-null r implies c is already marked as dirty,
615 // and that the parent is valid. Therefore we can
616 // just union the rect and bail.
617 SwingUtilities.computeUnion(x, y, w, h, r);
618 return true;
619 }
620 return false;
621 }
622
623 /**
624 * Return the current dirty region for a component.
625 * Return an empty rectangle if the component is not
626 * dirty.
627 *
628 * @param aComponent a component
989 roots.add(rootDirtyComponent);
990 }
991
992
993 /**
994 * Returns a string that displays and identifies this
995 * object's properties.
996 *
997 * @return a String representation of this object
998 */
999 public synchronized String toString() {
1000 StringBuilder sb = new StringBuilder();
1001 if(dirtyComponents != null)
1002 sb.append("" + dirtyComponents);
1003 return sb.toString();
1004 }
1005
1006
1007 /**
1008 * Return the offscreen buffer that should be used as a double buffer with
1009 * the component <code>c</code>.
1010 * By default there is a double buffer per RepaintManager.
1011 * The buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>
1012 * This happens when the maximum double buffer size as been set for the receiving
1013 * repaint manager.
1014 *
1015 * @param c the component
1016 * @param proposedWidth the width of the buffer
1017 * @param proposedHeight the height of the buffer
1018 *
1019 * @return the image
1020 */
1021 public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) {
1022 RepaintManager delegate = getDelegate(c);
1023 if (delegate != null) {
1024 return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight);
1025 }
1026 return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
1027 }
1028
1029 /**
1030 * Return a volatile offscreen buffer that should be used as a
1031 * double buffer with the specified component <code>c</code>.
1032 * The image returned will be an instance of VolatileImage, or null
1033 * if a VolatileImage object could not be instantiated.
1034 * This buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>.
1035 * This happens when the maximum double buffer size has been set for this
1036 * repaint manager.
1037 *
1038 * @param c the component
1039 * @param proposedWidth the width of the buffer
1040 * @param proposedHeight the height of the buffer
1041 *
1042 * @return the volatile image
1043 * @see java.awt.image.VolatileImage
1044 * @since 1.4
1045 */
1046 public Image getVolatileOffscreenBuffer(Component c,
1047 int proposedWidth,int proposedHeight) {
1048 RepaintManager delegate = getDelegate(c);
1049 if (delegate != null) {
1050 return delegate.getVolatileOffscreenBuffer(c, proposedWidth,
1051 proposedHeight);
1052 }
1053
1054 // If the window is non-opaque, it's double-buffered at peer's level
1203 * Enables or disables double buffering in this RepaintManager.
1204 * CAUTION: The default value for this property is set for optimal
1205 * paint performance on the given platform and it is not recommended
1206 * that programs modify this property directly.
1207 *
1208 * @param aFlag true to activate double buffering
1209 * @see #isDoubleBufferingEnabled
1210 */
1211 public void setDoubleBufferingEnabled(boolean aFlag) {
1212 doubleBufferingEnabled = aFlag;
1213 PaintManager paintManager = getPaintManager();
1214 if (!aFlag && paintManager.getClass() != PaintManager.class) {
1215 setPaintManager(new PaintManager());
1216 }
1217 }
1218
1219 /**
1220 * Returns true if this RepaintManager is double buffered.
1221 * The default value for this property may vary from platform
1222 * to platform. On platforms where native double buffering
1223 * is supported in the AWT, the default value will be <code>false</code>
1224 * to avoid unnecessary buffering in Swing.
1225 * On platforms where native double buffering is not supported,
1226 * the default value will be <code>true</code>.
1227 *
1228 * @return true if this object is double buffered
1229 */
1230 public boolean isDoubleBufferingEnabled() {
1231 return doubleBufferingEnabled;
1232 }
1233
1234 /**
1235 * This resets the double buffer. Actually, it marks the double buffer
1236 * as invalid, the double buffer will then be recreated on the next
1237 * invocation of getOffscreenBuffer.
1238 */
1239 void resetDoubleBuffer() {
1240 if (standardDoubleBuffer != null) {
1241 standardDoubleBuffer.needsReset = true;
1242 }
1243 }
1244
1245 /**
1246 * This resets the volatile double buffer.
1247 */
1248 void resetVolatileDoubleBuffer(GraphicsConfiguration gc) {
1249 Image image = volatileMap.remove(gc);
1250 if (image != null) {
1251 image.flush();
1252 }
1253 }
1254
1255 /**
1256 * Returns true if we should use the <code>Image</code> returned
1257 * from <code>getVolatileOffscreenBuffer</code> to do double buffering.
1258 */
1259 boolean useVolatileDoubleBuffer() {
1260 return volatileImageBufferEnabled;
1261 }
1262
1263 /**
1264 * Returns true if the current thread is the thread painting. This
1265 * will return false if no threads are painting.
1266 */
1267 private synchronized boolean isPaintingThread() {
1268 return (Thread.currentThread() == paintThread);
1269 }
1270 //
1271 // Paint methods. You very, VERY rarely need to invoke these.
1272 // They are invoked directly from JComponent's painting code and
1273 // when painting happens outside the normal flow: DefaultDesktopManager
1274 // and JViewport. If you end up needing these methods in other places be
1275 // careful that you don't get stuck in a paint loop.
1276 //
1277
1329
1330 /**
1331 * Notify the attached repaint listeners that an area of the {@code c} component
1332 * has been immediately repainted, that is without scheduling a repaint runnable,
1333 * due to performing a "blit" (via calling the {@code copyArea} method).
1334 *
1335 * @param c the component
1336 * @param x the x coordinate of the area
1337 * @param y the y coordinate of the area
1338 * @param w the width of the area
1339 * @param h the height of the area
1340 */
1341 void notifyRepaintPerformed(JComponent c, int x, int y, int w, int h) {
1342 for (RepaintListener l : repaintListeners) {
1343 l.repaintPerformed(c, x, y, w, h);
1344 }
1345 }
1346
1347 /**
1348 * Invoked prior to any paint/copyArea method calls. This will
1349 * be followed by an invocation of <code>endPaint</code>.
1350 * <b>WARNING</b>: Callers of this method need to wrap the call
1351 * in a <code>try/finally</code>, otherwise if an exception is thrown
1352 * during the course of painting the RepaintManager may
1353 * be left in a state in which the screen is not updated, eg:
1354 * <pre>
1355 * repaintManager.beginPaint();
1356 * try {
1357 * repaintManager.paint(...);
1358 * } finally {
1359 * repaintManager.endPaint();
1360 * }
1361 * </pre>
1362 */
1363 void beginPaint() {
1364 boolean multiThreadedPaint = false;
1365 int paintDepth;
1366 Thread currentThread = Thread.currentThread();
1367 synchronized(this) {
1368 paintDepth = this.paintDepth;
1369 if (paintThread == null || currentThread == paintThread) {
1370 paintThread = currentThread;
1371 this.paintDepth++;
1372 } else {
1373 multiThreadedPaint = true;
1374 }
1375 }
1376 if (!multiThreadedPaint && paintDepth == 0) {
1377 getPaintManager().beginPaint();
1378 }
1379 }
1380
1381 /**
1382 * Invoked after <code>beginPaint</code> has been invoked.
1383 */
1384 void endPaint() {
1385 if (isPaintingThread()) {
1386 PaintManager paintManager = null;
1387 synchronized(this) {
1388 if (--paintDepth == 0) {
1389 paintManager = getPaintManager();
1390 }
1391 }
1392 if (paintManager != null) {
1393 paintManager.endPaint();
1394 synchronized(this) {
1395 paintThread = null;
1396 }
1397 }
1398 }
1399 }
1400
1401 /**
1402 * If possible this will show a previously rendered portion of
1403 * a Component. If successful, this will return true, otherwise false.
1404 * <p>
1405 * WARNING: This method is invoked from the native toolkit thread, be
1406 * very careful as to what methods this invokes!
1407 */
1408 boolean show(Container c, int x, int y, int w, int h) {
1409 return getPaintManager().show(c, x, y, w, h);
1410 }
1411
1412 /**
1413 * Invoked when the doubleBuffered or useTrueDoubleBuffering
1414 * properties of a JRootPane change. This may come in on any thread.
1415 */
1416 void doubleBufferingChanged(JRootPane rootPane) {
1417 getPaintManager().doubleBufferingChanged(rootPane);
1418 }
1419
1420 /**
1421 * Sets the <code>PaintManager</code> that is used to handle all
1422 * double buffered painting.
1423 *
1424 * @param paintManager The PaintManager to use. Passing in null indicates
1425 * the fallback PaintManager should be used.
1426 */
1427 void setPaintManager(PaintManager paintManager) {
1428 if (paintManager == null) {
1429 paintManager = new PaintManager();
1430 }
1431 PaintManager oldPaintManager;
1432 synchronized(this) {
1433 oldPaintManager = this.paintManager;
1434 this.paintManager = paintManager;
1435 paintManager.repaintManager = this;
1436 }
1437 if (oldPaintManager != null) {
1438 oldPaintManager.dispose();
1439 }
1440 }
1441
1468
1469 private void scheduleProcessingRunnable(AppContext context) {
1470 if (processingRunnable.markPending()) {
1471 Toolkit tk = Toolkit.getDefaultToolkit();
1472 if (tk instanceof SunToolkit) {
1473 SunToolkit.getSystemEventQueueImplPP(context).
1474 postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1475 processingRunnable));
1476 } else {
1477 Toolkit.getDefaultToolkit().getSystemEventQueue().
1478 postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1479 processingRunnable));
1480 }
1481 }
1482 }
1483
1484
1485 /**
1486 * PaintManager is used to handle all double buffered painting for
1487 * Swing. Subclasses should call back into the JComponent method
1488 * <code>paintToOffscreen</code> to handle the actual painting.
1489 */
1490 static class PaintManager {
1491 /**
1492 * RepaintManager the PaintManager has been installed on.
1493 */
1494 protected RepaintManager repaintManager;
1495 boolean isRepaintingRoot;
1496
1497 /**
1498 * Paints a region of a component
1499 *
1500 * @param paintingComponent Component to paint
1501 * @param bufferComponent Component to obtain buffer for
1502 * @param g Graphics to paint to
1503 * @param x X-coordinate
1504 * @param y Y-coordinate
1505 * @param w Width
1506 * @param h Height
1507 * @return true if painting was successful.
1508 */
1610 g.setClip(x, y, bw, bh);
1611 if (volatileBufferType != Transparency.OPAQUE
1612 && g instanceof Graphics2D) {
1613 final Graphics2D g2d = (Graphics2D) g;
1614 final Composite oldComposite = g2d.getComposite();
1615 g2d.setComposite(AlphaComposite.Src);
1616 g2d.drawImage(image, x, y, c);
1617 g2d.setComposite(oldComposite);
1618 } else {
1619 g.drawImage(image, x, y, c);
1620 }
1621 osg.translate(x, y);
1622 }
1623 }
1624 } finally {
1625 osg.dispose();
1626 }
1627 }
1628
1629 /**
1630 * If <code>image</code> is non-null with a positive size it
1631 * is returned, otherwise null is returned.
1632 */
1633 private Image getValidImage(Image image) {
1634 if (image != null && image.getWidth(null) > 0 &&
1635 image.getHeight(null) > 0) {
1636 return image;
1637 }
1638 return null;
1639 }
1640
1641 /**
1642 * Schedules a repaint for the specified component. This differs
1643 * from <code>root.repaint</code> in that if the RepaintManager is
1644 * currently processing paint requests it'll process this request
1645 * with the current set of requests.
1646 */
1647 protected void repaintRoot(JComponent root) {
1648 assert (repaintManager.repaintRoot == null);
1649 if (repaintManager.painting) {
1650 repaintManager.repaintRoot = root;
1651 }
1652 else {
1653 root.repaint();
1654 }
1655 }
1656
1657 /**
1658 * Returns true if the component being painted is the root component
1659 * that was previously passed to <code>repaintRoot</code>.
1660 */
1661 protected boolean isRepaintingRoot() {
1662 return isRepaintingRoot;
1663 }
1664
1665 /**
1666 * Cleans up any state. After invoked the PaintManager will no
1667 * longer be used anymore.
1668 */
1669 protected void dispose() {
1670 }
1671 }
1672
1673
1674 private class DoubleBufferInfo {
1675 public Image image;
1676 public Dimension size;
1677 public boolean needsReset = false;
1678 }
1679
|
36 import java.applet.*;
37
38 import jdk.internal.misc.JavaSecurityAccess;
39 import jdk.internal.misc.SharedSecrets;
40 import sun.awt.AWTAccessor;
41 import sun.awt.AppContext;
42 import sun.awt.DisplayChangedListener;
43 import sun.awt.SunToolkit;
44 import sun.java2d.SunGraphicsEnvironment;
45 import sun.security.action.GetPropertyAction;
46
47 import com.sun.java.swing.SwingUtilities3;
48 import sun.swing.SwingAccessor;
49 import sun.swing.SwingUtilities2.RepaintListener;
50
51 /**
52 * This class manages repaint requests, allowing the number
53 * of repaints to be minimized, for example by collapsing multiple
54 * requests into a single repaint for members of a component tree.
55 * <p>
56 * As of 1.6 {@code RepaintManager} handles repaint requests
57 * for Swing's top level components ({@code JApplet},
58 * {@code JWindow}, {@code JFrame} and {@code JDialog}).
59 * Any calls to {@code repaint} on one of these will call into the
60 * appropriate {@code addDirtyRegion} method.
61 *
62 * @author Arnaud Weber
63 * @since 1.2
64 */
65 public class RepaintManager
66 {
67 /**
68 * Whether or not the RepaintManager should handle paint requests
69 * for top levels.
70 */
71 static final boolean HANDLE_TOP_LEVEL_PAINT;
72
73 private static final short BUFFER_STRATEGY_NOT_SPECIFIED = 0;
74 private static final short BUFFER_STRATEGY_SPECIFIED_ON = 1;
75 private static final short BUFFER_STRATEGY_SPECIFIED_OFF = 2;
76
77 private static final short BUFFER_STRATEGY_TYPE;
78
79 /**
80 * Maps from GraphicsConfiguration to VolatileImage.
122
123 private static final Object repaintManagerKey = RepaintManager.class;
124
125 // Whether or not a VolatileImage should be used for double-buffered painting
126 static boolean volatileImageBufferEnabled = true;
127 /**
128 * Type of VolatileImage which should be used for double-buffered
129 * painting.
130 */
131 private static final int volatileBufferType;
132 /**
133 * Value of the system property awt.nativeDoubleBuffering.
134 */
135 private static boolean nativeDoubleBuffering;
136
137 // The maximum number of times Swing will attempt to use the VolatileImage
138 // buffer during a paint operation.
139 private static final int VOLATILE_LOOP_MAX = 2;
140
141 /**
142 * Number of {@code beginPaint} that have been invoked.
143 */
144 private int paintDepth = 0;
145
146 /**
147 * Type of buffer strategy to use. Will be one of the BUFFER_STRATEGY_
148 * constants.
149 */
150 private short bufferStrategyType;
151
152 //
153 // BufferStrategyPaintManager has the unique characteristic that it
154 // must deal with the buffer being lost while painting to it. For
155 // example, if we paint a component and show it and the buffer has
156 // become lost we must repaint the whole window. To deal with that
157 // the PaintManager calls into repaintRoot, and if we're still in
158 // the process of painting the repaintRoot field is set to the JRootPane
159 // and after the current JComponent.paintImmediately call finishes
160 // paintImmediately will be invoked on the repaintRoot. In this
161 // way we don't try to show garbage to the screen.
162 //
163 /**
164 * True if we're in the process of painting the dirty regions. This is
165 * set to true in {@code paintDirtyRegions}.
166 */
167 private boolean painting;
168 /**
169 * If the PaintManager calls into repaintRoot during painting this field
170 * will be set to the root.
171 */
172 private JComponent repaintRoot;
173
174 /**
175 * The Thread that has initiated painting. If null it
176 * indicates painting is not currently in progress.
177 */
178 private Thread paintThread;
179
180 /**
181 * Runnable used to process all repaint/revalidate requests.
182 */
183 private final ProcessingRunnable processingRunnable;
184
185 private static final JavaSecurityAccess javaSecurityAccess =
475 * will be unioned with the region that should be redrawn.
476 *
477 * @param c Component to repaint, null results in nothing happening.
478 * @param x X coordinate of the region to repaint
479 * @param y Y coordinate of the region to repaint
480 * @param w Width of the region to repaint
481 * @param h Height of the region to repaint
482 * @see JComponent#repaint
483 */
484 public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
485 {
486 RepaintManager delegate = getDelegate(c);
487 if (delegate != null) {
488 delegate.addDirtyRegion(c, x, y, w, h);
489 return;
490 }
491 addDirtyRegion0(c, x, y, w, h);
492 }
493
494 /**
495 * Adds {@code window} to the list of {@code Component}s that
496 * need to be repainted.
497 *
498 * @param window Window to repaint, null results in nothing happening.
499 * @param x X coordinate of the region to repaint
500 * @param y Y coordinate of the region to repaint
501 * @param w Width of the region to repaint
502 * @param h Height of the region to repaint
503 * @see JFrame#repaint
504 * @see JWindow#repaint
505 * @see JDialog#repaint
506 * @since 1.6
507 */
508 public void addDirtyRegion(Window window, int x, int y, int w, int h) {
509 addDirtyRegion0(window, x, y, w, h);
510 }
511
512 /**
513 * Adds {@code applet} to the list of {@code Component}s that
514 * need to be repainted.
515 *
516 * @param applet Applet to repaint, null results in nothing happening.
517 * @param x X coordinate of the region to repaint
518 * @param y Y coordinate of the region to repaint
519 * @param w Width of the region to repaint
520 * @param h Height of the region to repaint
521 * @see JApplet#repaint
522 * @since 1.6
523 */
524 public void addDirtyRegion(Applet applet, int x, int y, int w, int h) {
525 addDirtyRegion0(applet, x, y, w, h);
526 }
527
528 void scheduleHeavyWeightPaints() {
529 Map<Container,Rectangle> hws;
530
531 synchronized(this) {
532 if (hwDirtyComponents.size() == 0) {
533 return;
588 public void run() {
589 AccessControlContext stack = AccessController.getContext();
590 AccessControlContext acc =
591 AWTAccessor.getComponentAccessor().getAccessControlContext(c);
592 javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
593 public Void run() {
594 r.run();
595 return null;
596 }
597 }, stack, acc);
598 }
599 });
600 }
601 scheduleProcessingRunnable(appContext);
602 }
603
604 /**
605 * Extends the dirty region for the specified component to include
606 * the new region.
607 *
608 * @return false if {@code c} is not yet marked dirty.
609 */
610 private synchronized boolean extendDirtyRegion(
611 Component c, int x, int y, int w, int h) {
612 Rectangle r = dirtyComponents.get(c);
613 if (r != null) {
614 // A non-null r implies c is already marked as dirty,
615 // and that the parent is valid. Therefore we can
616 // just union the rect and bail.
617 SwingUtilities.computeUnion(x, y, w, h, r);
618 return true;
619 }
620 return false;
621 }
622
623 /**
624 * Return the current dirty region for a component.
625 * Return an empty rectangle if the component is not
626 * dirty.
627 *
628 * @param aComponent a component
989 roots.add(rootDirtyComponent);
990 }
991
992
993 /**
994 * Returns a string that displays and identifies this
995 * object's properties.
996 *
997 * @return a String representation of this object
998 */
999 public synchronized String toString() {
1000 StringBuilder sb = new StringBuilder();
1001 if(dirtyComponents != null)
1002 sb.append("" + dirtyComponents);
1003 return sb.toString();
1004 }
1005
1006
1007 /**
1008 * Return the offscreen buffer that should be used as a double buffer with
1009 * the component {@code c}.
1010 * By default there is a double buffer per RepaintManager.
1011 * The buffer might be smaller than {@code (proposedWidth,proposedHeight)}
1012 * This happens when the maximum double buffer size as been set for the receiving
1013 * repaint manager.
1014 *
1015 * @param c the component
1016 * @param proposedWidth the width of the buffer
1017 * @param proposedHeight the height of the buffer
1018 *
1019 * @return the image
1020 */
1021 public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) {
1022 RepaintManager delegate = getDelegate(c);
1023 if (delegate != null) {
1024 return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight);
1025 }
1026 return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
1027 }
1028
1029 /**
1030 * Return a volatile offscreen buffer that should be used as a
1031 * double buffer with the specified component {@code c}.
1032 * The image returned will be an instance of VolatileImage, or null
1033 * if a VolatileImage object could not be instantiated.
1034 * This buffer might be smaller than {@code (proposedWidth,proposedHeight)}.
1035 * This happens when the maximum double buffer size has been set for this
1036 * repaint manager.
1037 *
1038 * @param c the component
1039 * @param proposedWidth the width of the buffer
1040 * @param proposedHeight the height of the buffer
1041 *
1042 * @return the volatile image
1043 * @see java.awt.image.VolatileImage
1044 * @since 1.4
1045 */
1046 public Image getVolatileOffscreenBuffer(Component c,
1047 int proposedWidth,int proposedHeight) {
1048 RepaintManager delegate = getDelegate(c);
1049 if (delegate != null) {
1050 return delegate.getVolatileOffscreenBuffer(c, proposedWidth,
1051 proposedHeight);
1052 }
1053
1054 // If the window is non-opaque, it's double-buffered at peer's level
1203 * Enables or disables double buffering in this RepaintManager.
1204 * CAUTION: The default value for this property is set for optimal
1205 * paint performance on the given platform and it is not recommended
1206 * that programs modify this property directly.
1207 *
1208 * @param aFlag true to activate double buffering
1209 * @see #isDoubleBufferingEnabled
1210 */
1211 public void setDoubleBufferingEnabled(boolean aFlag) {
1212 doubleBufferingEnabled = aFlag;
1213 PaintManager paintManager = getPaintManager();
1214 if (!aFlag && paintManager.getClass() != PaintManager.class) {
1215 setPaintManager(new PaintManager());
1216 }
1217 }
1218
1219 /**
1220 * Returns true if this RepaintManager is double buffered.
1221 * The default value for this property may vary from platform
1222 * to platform. On platforms where native double buffering
1223 * is supported in the AWT, the default value will be {@code false}
1224 * to avoid unnecessary buffering in Swing.
1225 * On platforms where native double buffering is not supported,
1226 * the default value will be {@code true}.
1227 *
1228 * @return true if this object is double buffered
1229 */
1230 public boolean isDoubleBufferingEnabled() {
1231 return doubleBufferingEnabled;
1232 }
1233
1234 /**
1235 * This resets the double buffer. Actually, it marks the double buffer
1236 * as invalid, the double buffer will then be recreated on the next
1237 * invocation of getOffscreenBuffer.
1238 */
1239 void resetDoubleBuffer() {
1240 if (standardDoubleBuffer != null) {
1241 standardDoubleBuffer.needsReset = true;
1242 }
1243 }
1244
1245 /**
1246 * This resets the volatile double buffer.
1247 */
1248 void resetVolatileDoubleBuffer(GraphicsConfiguration gc) {
1249 Image image = volatileMap.remove(gc);
1250 if (image != null) {
1251 image.flush();
1252 }
1253 }
1254
1255 /**
1256 * Returns true if we should use the {@code Image} returned
1257 * from {@code getVolatileOffscreenBuffer} to do double buffering.
1258 */
1259 boolean useVolatileDoubleBuffer() {
1260 return volatileImageBufferEnabled;
1261 }
1262
1263 /**
1264 * Returns true if the current thread is the thread painting. This
1265 * will return false if no threads are painting.
1266 */
1267 private synchronized boolean isPaintingThread() {
1268 return (Thread.currentThread() == paintThread);
1269 }
1270 //
1271 // Paint methods. You very, VERY rarely need to invoke these.
1272 // They are invoked directly from JComponent's painting code and
1273 // when painting happens outside the normal flow: DefaultDesktopManager
1274 // and JViewport. If you end up needing these methods in other places be
1275 // careful that you don't get stuck in a paint loop.
1276 //
1277
1329
1330 /**
1331 * Notify the attached repaint listeners that an area of the {@code c} component
1332 * has been immediately repainted, that is without scheduling a repaint runnable,
1333 * due to performing a "blit" (via calling the {@code copyArea} method).
1334 *
1335 * @param c the component
1336 * @param x the x coordinate of the area
1337 * @param y the y coordinate of the area
1338 * @param w the width of the area
1339 * @param h the height of the area
1340 */
1341 void notifyRepaintPerformed(JComponent c, int x, int y, int w, int h) {
1342 for (RepaintListener l : repaintListeners) {
1343 l.repaintPerformed(c, x, y, w, h);
1344 }
1345 }
1346
1347 /**
1348 * Invoked prior to any paint/copyArea method calls. This will
1349 * be followed by an invocation of {@code endPaint}.
1350 * <b>WARNING</b>: Callers of this method need to wrap the call
1351 * in a {@code try/finally}, otherwise if an exception is thrown
1352 * during the course of painting the RepaintManager may
1353 * be left in a state in which the screen is not updated, eg:
1354 * <pre>
1355 * repaintManager.beginPaint();
1356 * try {
1357 * repaintManager.paint(...);
1358 * } finally {
1359 * repaintManager.endPaint();
1360 * }
1361 * </pre>
1362 */
1363 void beginPaint() {
1364 boolean multiThreadedPaint = false;
1365 int paintDepth;
1366 Thread currentThread = Thread.currentThread();
1367 synchronized(this) {
1368 paintDepth = this.paintDepth;
1369 if (paintThread == null || currentThread == paintThread) {
1370 paintThread = currentThread;
1371 this.paintDepth++;
1372 } else {
1373 multiThreadedPaint = true;
1374 }
1375 }
1376 if (!multiThreadedPaint && paintDepth == 0) {
1377 getPaintManager().beginPaint();
1378 }
1379 }
1380
1381 /**
1382 * Invoked after {@code beginPaint} has been invoked.
1383 */
1384 void endPaint() {
1385 if (isPaintingThread()) {
1386 PaintManager paintManager = null;
1387 synchronized(this) {
1388 if (--paintDepth == 0) {
1389 paintManager = getPaintManager();
1390 }
1391 }
1392 if (paintManager != null) {
1393 paintManager.endPaint();
1394 synchronized(this) {
1395 paintThread = null;
1396 }
1397 }
1398 }
1399 }
1400
1401 /**
1402 * If possible this will show a previously rendered portion of
1403 * a Component. If successful, this will return true, otherwise false.
1404 * <p>
1405 * WARNING: This method is invoked from the native toolkit thread, be
1406 * very careful as to what methods this invokes!
1407 */
1408 boolean show(Container c, int x, int y, int w, int h) {
1409 return getPaintManager().show(c, x, y, w, h);
1410 }
1411
1412 /**
1413 * Invoked when the doubleBuffered or useTrueDoubleBuffering
1414 * properties of a JRootPane change. This may come in on any thread.
1415 */
1416 void doubleBufferingChanged(JRootPane rootPane) {
1417 getPaintManager().doubleBufferingChanged(rootPane);
1418 }
1419
1420 /**
1421 * Sets the {@code PaintManager} that is used to handle all
1422 * double buffered painting.
1423 *
1424 * @param paintManager The PaintManager to use. Passing in null indicates
1425 * the fallback PaintManager should be used.
1426 */
1427 void setPaintManager(PaintManager paintManager) {
1428 if (paintManager == null) {
1429 paintManager = new PaintManager();
1430 }
1431 PaintManager oldPaintManager;
1432 synchronized(this) {
1433 oldPaintManager = this.paintManager;
1434 this.paintManager = paintManager;
1435 paintManager.repaintManager = this;
1436 }
1437 if (oldPaintManager != null) {
1438 oldPaintManager.dispose();
1439 }
1440 }
1441
1468
1469 private void scheduleProcessingRunnable(AppContext context) {
1470 if (processingRunnable.markPending()) {
1471 Toolkit tk = Toolkit.getDefaultToolkit();
1472 if (tk instanceof SunToolkit) {
1473 SunToolkit.getSystemEventQueueImplPP(context).
1474 postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1475 processingRunnable));
1476 } else {
1477 Toolkit.getDefaultToolkit().getSystemEventQueue().
1478 postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1479 processingRunnable));
1480 }
1481 }
1482 }
1483
1484
1485 /**
1486 * PaintManager is used to handle all double buffered painting for
1487 * Swing. Subclasses should call back into the JComponent method
1488 * {@code paintToOffscreen} to handle the actual painting.
1489 */
1490 static class PaintManager {
1491 /**
1492 * RepaintManager the PaintManager has been installed on.
1493 */
1494 protected RepaintManager repaintManager;
1495 boolean isRepaintingRoot;
1496
1497 /**
1498 * Paints a region of a component
1499 *
1500 * @param paintingComponent Component to paint
1501 * @param bufferComponent Component to obtain buffer for
1502 * @param g Graphics to paint to
1503 * @param x X-coordinate
1504 * @param y Y-coordinate
1505 * @param w Width
1506 * @param h Height
1507 * @return true if painting was successful.
1508 */
1610 g.setClip(x, y, bw, bh);
1611 if (volatileBufferType != Transparency.OPAQUE
1612 && g instanceof Graphics2D) {
1613 final Graphics2D g2d = (Graphics2D) g;
1614 final Composite oldComposite = g2d.getComposite();
1615 g2d.setComposite(AlphaComposite.Src);
1616 g2d.drawImage(image, x, y, c);
1617 g2d.setComposite(oldComposite);
1618 } else {
1619 g.drawImage(image, x, y, c);
1620 }
1621 osg.translate(x, y);
1622 }
1623 }
1624 } finally {
1625 osg.dispose();
1626 }
1627 }
1628
1629 /**
1630 * If {@code image} is non-null with a positive size it
1631 * is returned, otherwise null is returned.
1632 */
1633 private Image getValidImage(Image image) {
1634 if (image != null && image.getWidth(null) > 0 &&
1635 image.getHeight(null) > 0) {
1636 return image;
1637 }
1638 return null;
1639 }
1640
1641 /**
1642 * Schedules a repaint for the specified component. This differs
1643 * from {@code root.repaint} in that if the RepaintManager is
1644 * currently processing paint requests it'll process this request
1645 * with the current set of requests.
1646 */
1647 protected void repaintRoot(JComponent root) {
1648 assert (repaintManager.repaintRoot == null);
1649 if (repaintManager.painting) {
1650 repaintManager.repaintRoot = root;
1651 }
1652 else {
1653 root.repaint();
1654 }
1655 }
1656
1657 /**
1658 * Returns true if the component being painted is the root component
1659 * that was previously passed to {@code repaintRoot}.
1660 */
1661 protected boolean isRepaintingRoot() {
1662 return isRepaintingRoot;
1663 }
1664
1665 /**
1666 * Cleans up any state. After invoked the PaintManager will no
1667 * longer be used anymore.
1668 */
1669 protected void dispose() {
1670 }
1671 }
1672
1673
1674 private class DoubleBufferInfo {
1675 public Image image;
1676 public Dimension size;
1677 public boolean needsReset = false;
1678 }
1679
|