I realised than immediate going to the highest possible root breaks Roman's scrolling optimizations in JViewport. To fix this, I moved the redundant repaint avoidance from addDirtyRegion to paintDirtyRegions, where all regions to be painted are already known and it is possible to pick the lowest possible root. The algorithm is now more complex.

My previous change, however, was not the only reason why the blitting is broken. To restore blitting completely, the JComponent.findOverlapFreeParents must stop iteration after reaching the JViewport and not proceed upward. Otherwise JViewport becomes no longer a painting root.

2006-05-15  Audrius Meskauskas  <[EMAIL PROTECTED]>

   * javax/swing/JComponent.java (findOverlapParent): Stop loop at
    JViewport's.
   * javax/swing/RepaintManager.java (addDirtyRegion): Always add the given
   region. (paintDirtyRegions): Rewritten.
Index: javax/swing/JComponent.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/JComponent.java,v
retrieving revision 1.119
diff -u -r1.119 JComponent.java
--- javax/swing/JComponent.java	4 May 2006 13:20:44 -0000	1.119
+++ javax/swing/JComponent.java	15 May 2006 16:56:47 -0000
@@ -3554,7 +3554,10 @@
     Rectangle currentClip = clip;
     Component found = this;
     Container parent = this; 
-    while (parent != null && !(parent instanceof Window))
+    // Path up is stopped at viewports, allowing to use viewport
+    // painting optimizations.
+    while (parent != null && !(parent instanceof Window) 
+        && !(parent instanceof JViewport))
       {
         Container newParent = parent.getParent();
         if (newParent == null || newParent instanceof Window)
Index: javax/swing/RepaintManager.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/RepaintManager.java,v
retrieving revision 1.32
diff -u -r1.32 RepaintManager.java
--- javax/swing/RepaintManager.java	15 May 2006 10:14:18 -0000	1.32
+++ javax/swing/RepaintManager.java	15 May 2006 16:56:48 -0000
@@ -50,6 +50,7 @@
 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;
@@ -424,13 +425,6 @@
       return;
     
     Component parent = component.getParent();
-    if (parent instanceof JComponent)
-      {
-        // If there is a delegateable parent, add the parent region instead.
-        addDirtyRegion((JComponent) parent, x + component.getX(),
-                       y + component.getY(), w, h);
-        return;
-      }
     
     component.computeVisibleRect(rectCache);
     SwingUtilities.computeIntersection(x, y, w, h, rectCache);
@@ -564,8 +558,8 @@
   }
 
   /**
-   * Repaint all regions of all components which have been marked dirty in
-   * the [EMAIL PROTECTED] #dirtyComponents} table.
+   * Repaint all regions of all components which have been marked dirty in the
+   * [EMAIL PROTECTED] #dirtyComponents} table.
    */
   public void paintDirtyRegions()
   {
@@ -581,17 +575,57 @@
         dirtyComponentsWork = swap;
       }
 
-    ArrayList repaintOrder = new ArrayList(dirtyComponentsWork.size());;
-    // We sort the components by their size here. This way we have a good
-    // chance that painting the bigger components also paints the smaller
-    // components and we don't need to paint them twice.
-    repaintOrder.addAll(dirtyComponentsWork.keySet());
-
-    if (comparator == null)
-      comparator = new ComponentComparator();
-    Collections.sort(repaintOrder, comparator);
+    HashSet components = new HashSet(dirtyComponentsWork.keySet());
+    boolean someRemoved;
+    boolean cRemoved;
+
+    do
+      {
+        Iterator en = components.iterator();
+        someRemoved = false;
+        // Where possible, do not repaint the component, extending the
+        // parent repaint region instead.
+        en = components.iterator();
+        while (en.hasNext())
+          {
+            Component c = (Component) en.next();
+            cRemoved = false;
+            Component p = c.getParent();
+            int x = c.getX();
+            int y = c.getY();
+
+            while (p instanceof JComponent)
+              if (components.contains(p))
+                {
+                  // The parent of this component is already marked for
+                  // repainting.
+                  // We will not repaint this component.
+                  if (!cRemoved)
+                    {
+                      en.remove();
+                      cRemoved = true;
+                    }
+                  en = components.iterator();
+                  // 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);
+                  someRemoved = true;
+                  p = p.getParent();
+                }
+              else
+                {
+                  x += p.getX();
+                  y += p.getY();
+                  p = p.getParent();
+                }
+          }
+      }
+    while (someRemoved);
+
     repaintUnderway = true;
-    for (Iterator i = repaintOrder.iterator(); i.hasNext();)
+    for (Iterator i = components.iterator(); i.hasNext();)
       {
         JComponent comp = (JComponent) i.next();
         // If a component is marked completely clean in the meantime, then skip
@@ -601,6 +635,8 @@
           continue;
         comp.paintImmediately(damaged);
       }
+
+    dirtyComponentsWork.clear();
     repaintUnderway = false;
     commitRemainingBuffers();
   }

Reply via email to