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

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

Reply via email to