Hi, Am Donnerstag, den 18.05.2006, 16:11 +0200 schrieb Audrius Meskauskas: > Roman Kennke wrote: > > >Hi list, hi Audrius, > > > >I looked a little over the recent JComponent/RepaintManager changes. > > > Surely, this patch is great. There are no redundant repaints, so the > frame moving and resizing remains fast. The algorithm is now more > sophisticated than the previously uses force approach. From the general > impression, it works faster than the recent version. Great to commit!
Done.
2006-05-18 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/JComponent.java
(isCompletelyDirty): Removed.
(paint): Don't mark children as clean, this is no longer
necessary.
(findOverlapFreeParent): Don't stop at Viewports, this breaks
painting when something overlaps the viewport (like a
popup/menu).
* javax/swing/RepaintManager.java
(currentRepaintManagers): Made package private to avoid accessor
methods.
(dirtyComponents): Made private.
(dirtyComponentsWork): Made private.
(markCompletelyDirty): Fixed bounds of dirtyrect to be
component-local not parent-local. Do not set flag in JComponent.
(markCompletelyClean): Don't set JComponent flag.
(isCompletelyDirty): Rewritten to return true when the complete
component is marked dirty.
(paintDirtyRegions): Improved parent-merging so that the
merged-in
components don't get painted too. 'Outsourced' the compilation
of the repaint root components.
(compileRepaintRoots): New helper method.
/Roman
--
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/JComponent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JComponent.java,v
retrieving revision 1.120
diff -u -1 -0 -r1.120 JComponent.java
--- javax/swing/JComponent.java 15 May 2006 17:03:05 -0000 1.120
+++ javax/swing/JComponent.java 18 May 2006 13:34:09 -0000
@@ -753,27 +753,20 @@
/**
* Constant used to indicate that an action should be performed only when
* the component is in the window which has focus.
*
* @see #registerKeyboardAction(ActionListener, KeyStroke, int)
*/
public static final int WHEN_IN_FOCUSED_WINDOW = 2;
/**
- * Indicates if this component is completely dirty or not. This is used
- * by the RepaintManager's
- * [EMAIL PROTECTED] RepaintManager#isCompletelyDirty(JComponent)} method.
- */
- boolean isCompletelyDirty = false;
-
- /**
* Indicates if the opaque property has been set by a client program or by
* the UI.
*
* @see #setUIProperty(String, Object)
* @see LookAndFeel#installProperty(JComponent, String, Object)
*/
private boolean clientOpaqueSet = false;
/**
* Indicates if the autoscrolls property has been set by a client program or
@@ -1756,25 +1749,20 @@
if (dragBuffer != null && dragBufferInitialized)
{
g.drawImage(dragBuffer, 0, 0, this);
}
else
{
Graphics g2 = getComponentGraphics(g);
paintComponent(g2);
paintBorder(g2);
paintChildren(g2);
- Rectangle clip = g2.getClipBounds();
- if (clip == null
- || (clip.x == 0 && clip.y == 0 && clip.width == getWidth()
- && clip.height == getHeight()))
- RepaintManager.currentManager(this).markCompletelyClean(this);
}
}
}
/**
* Initializes the drag buffer by creating a new image and painting this
* component into it.
*/
private void initializeDragBuffer()
{
@@ -3549,22 +3537,21 @@
*
* @return the paint root, or <code>null</code> if no paint is necessary
*/
private Component findOverlapFreeParent(Rectangle clip)
{
Rectangle currentClip = clip;
Component found = this;
Container parent = this;
// Path up is stopped at viewports, allowing to use viewport
// painting optimizations.
- while (parent != null && !(parent instanceof Window)
- && !(parent instanceof JViewport))
+ while (parent != null && !(parent instanceof Window))
{
Container newParent = parent.getParent();
if (newParent == null || newParent instanceof Window)
break;
// If the parent is optimizedDrawingEnabled, then its children are
// tiled and cannot have an overlapping child. Go directly to next
// parent.
if ((newParent instanceof JComponent
&& ((JComponent) newParent).isOptimizedDrawingEnabled()))
Index: javax/swing/RepaintManager.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/RepaintManager.java,v
retrieving revision 1.35
diff -u -1 -0 -r1.35 RepaintManager.java
--- javax/swing/RepaintManager.java 15 May 2006 19:43:19 -0000 1.35
+++ javax/swing/RepaintManager.java 18 May 2006 13:34:09 -0000
@@ -40,22 +40,20 @@
import java.applet.Applet;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.image.VolatileImage;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* <p>The repaint manager holds a set of dirty regions, invalid components,
* and a double buffer surface. The dirty regions and invalid components
@@ -70,21 +68,21 @@
*
* @author Roman Kennke ([EMAIL PROTECTED])
* @author Graydon Hoare ([EMAIL PROTECTED])
* @author Audrius Meskauskas ([EMAIL PROTECTED])
*/
public class RepaintManager
{
/**
* The current repaint managers, indexed by their ThreadGroups.
*/
- private static WeakHashMap currentRepaintManagers;
+ static WeakHashMap currentRepaintManagers;
/**
* A rectangle object to be reused in damaged regions calculation.
*/
private static Rectangle rectCache = new Rectangle();
/**
* <p>A helper class which is placed into the system event queue at
* various times in order to facilitate repainting and layout. There is
* typically only one of these objects active at any time. When the
@@ -144,27 +142,27 @@
*
* This is package private to avoid a synthetic accessor method in inner
* class.
*
* @see #addDirtyRegion
* @see #getDirtyRegion
* @see #isCompletelyDirty
* @see #markCompletelyClean
* @see #markCompletelyDirty
*/
- HashMap dirtyComponents;
+ private HashMap dirtyComponents;
/**
* The dirtyComponents which is used in paintDiryRegions to avoid unnecessary
* locking.
*/
- HashMap dirtyComponentsWork;
+ private HashMap dirtyComponentsWork;
/**
* A single, shared instance of the helper class. Any methods which mark
* components as invalid or dirty eventually activate this instance. It
* is added to the event queue if it is not already active, otherwise
* reused.
*
* @see #addDirtyRegion
* @see #addInvalidComponent
*/
@@ -440,63 +438,65 @@
*
* @see #dirtyComponents
* @see #addDirtyRegion
* @see #getDirtyRegion
* @see #isCompletelyDirty
* @see #markCompletelyClean
*/
public void markCompletelyDirty(JComponent component)
{
Rectangle r = component.getBounds();
- addDirtyRegion(component, r.x, r.y, r.width, r.height);
- component.isCompletelyDirty = true;
+ addDirtyRegion(component, 0, 0, r.width, r.height);
}
/**
* Remove all dirty regions for a specified component
*
* @param component The component to mark as clean
*
* @see #dirtyComponents
* @see #addDirtyRegion
* @see #getDirtyRegion
* @see #isCompletelyDirty
* @see #markCompletelyDirty
*/
public void markCompletelyClean(JComponent component)
{
synchronized (dirtyComponents)
{
dirtyComponents.remove(component);
}
- component.isCompletelyDirty = false;
}
/**
* Return <code>true</code> if the specified component is completely
* contained within its dirty region, otherwise <code>false</code>
*
* @param component The component to check for complete dirtyness
*
* @return Whether the component is completely dirty
*
* @see #dirtyComponents
* @see #addDirtyRegion
* @see #getDirtyRegion
* @see #isCompletelyDirty
* @see #markCompletelyClean
*/
public boolean isCompletelyDirty(JComponent component)
{
- if (! dirtyComponents.containsKey(component))
- return false;
- return component.isCompletelyDirty;
+ boolean retVal = false;
+ if (dirtyComponents.containsKey(component))
+ {
+ Rectangle dirtyRegion = (Rectangle) dirtyComponents.get(component);
+ retVal = dirtyRegion.equals(SwingUtilities.getLocalBounds(component));
+ }
+ return retVal;
}
/**
* Validate all components which have been marked invalid in the [EMAIL PROTECTED]
* #invalidComponents} vector.
*/
public void validateInvalidComponents()
{
// We don't use an iterator here because that would fail when there are
// components invalidated during the validation of others, which happens
@@ -526,91 +526,89 @@
return;
// Swap dirtyRegions with dirtyRegionsWork to avoid locking.
synchronized (dirtyComponents)
{
HashMap swap = dirtyComponents;
dirtyComponents = dirtyComponentsWork;
dirtyComponentsWork = swap;
}
- Object[] components = dirtyComponentsWork.keySet().toArray();
- boolean someRemoved;
- do
- {
- someRemoved = false;
- // Where possible, do not repaint the component, extending the
- // parent repaint region instead.
- Components: for (int i = 0; i < components.length; i++)
- if (components[i] != null)
- {
- Component c = (Component) components[i];
- Component p = c.getParent();
- int x = c.getX();
- int y = c.getY();
-
- while (p instanceof JComponent)
- if (contains(components, p))
- {
- // The parent of this component is already marked for
- // repainting.
- // We will not repaint this component.
- components[i] = null;
- someRemoved = true;
- // We will repaint the parent instead.
- Rectangle prect = (Rectangle) dirtyComponentsWork.get(p);
- Rectangle crect = (Rectangle) dirtyComponentsWork.get(c);
- crect.translate(x, y);
- prect.add(crect);
- continue Components;
- }
- else
- {
- x += p.getX();
- y += p.getY();
- p = p.getParent();
- }
- }
+ // Compile a set of repaint roots.
+ HashSet repaintRoots = new HashSet();
+ Set components = dirtyComponentsWork.keySet();
+ for (Iterator i = components.iterator(); i.hasNext();)
+ {
+ JComponent dirty = (JComponent) i.next();
+ compileRepaintRoots(dirtyComponentsWork, dirty, repaintRoots);
}
- while (someRemoved);
repaintUnderway = true;
- for (int i = 0; i < components.length; i++)
+ for (Iterator i = repaintRoots.iterator(); i.hasNext();)
{
- JComponent comp = (JComponent) components[i];
- if (comp != null)
- {
- // If a component is marked completely clean in the meantime, then
- // skip it.
- Rectangle damaged = (Rectangle) dirtyComponentsWork.remove(comp);
- if (damaged == null || damaged.isEmpty())
- continue;
- comp.paintImmediately(damaged);
- }
+ JComponent comp = (JComponent) i.next();
+ Rectangle damaged = (Rectangle) dirtyComponentsWork.remove(comp);
+ if (damaged == null || damaged.isEmpty())
+ continue;
+ comp.paintImmediately(damaged);
}
-
dirtyComponentsWork.clear();
repaintUnderway = false;
commitRemainingBuffers();
}
/**
- * The simple search of the object inside the array.
- */
- private static boolean contains(Object [] array, Object x)
- {
- for (int i = 0; i < array.length; i++)
- {
- if (array [i] == x)
- return true;
+ * Compiles a list of components that really get repainted. This is called
+ * once for each component in the dirtyComponents HashMap, each time with
+ * another <code>dirty</code> parameter. This searches up the component
+ * hierarchy of <code>dirty</code> to find the highest parent that is also
+ * marked dirty and merges the dirty regions.
+ *
+ * @param dirtyRegions the dirty regions
+ * @param dirty the component for which to find the repaint root
+ * @param roots the list to which new repaint roots get appended
+ */
+ private void compileRepaintRoots(HashMap dirtyRegions, JComponent dirty,
+ HashSet roots)
+ {
+ Component current = dirty;
+ Component root = dirty;
+
+ // Search the highest component that is also marked dirty.
+ Component parent;
+ while (true)
+ {
+ parent = current.getParent();
+ if (parent == null || !(parent instanceof JComponent))
+ break;
+
+ current = parent;
+ // We can skip to the next up when this parent is not dirty.
+ if (dirtyRegions.containsKey(parent))
+ {
+ root = current;
+ }
}
- return false;
+
+ // Merge the rectangles of the root and the requested component if
+ // the are different.
+ if (root != dirty)
+ {
+ Rectangle dirtyRect = (Rectangle) dirtyRegions.get(dirty);
+ dirtyRect = SwingUtilities.convertRectangle(dirty, dirtyRect, root);
+ Rectangle rootRect = (Rectangle) dirtyRegions.get(root);
+ SwingUtilities.computeUnion(dirtyRect.x, dirtyRect.y, dirtyRect.width,
+ dirtyRect.height, rootRect);
+ }
+
+ // Adds the root to the roots set.
+ roots.add(root);
}
/**
* Get an offscreen buffer for painting a component's image. This image
* may be smaller than the proposed dimensions, depending on the value of
* the [EMAIL PROTECTED] #doubleBufferMaximumSize} property.
*
* @param component The component to return an offscreen buffer for
* @param proposedWidth The proposed width of the offscreen buffer
* @param proposedHeight The proposed height of the offscreen buffer
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil
