Hi there,

on the way back from FOSDEM I was able to fix an annoying issue with the
RepaintManager. Sometimes when scrolling a JList or some other big
component, the painting acted kindof funny, which resulted in
scaled/shifted window content. This is caused by a bug (I think) in the
GtkImage implementation which doesn't play well, when a region partly
outside of the image is painted. I aligned the drawImage() parameters,
so that the region is guaranteed to be inside the offscreen image.

Also, I added some optimized handling of Rectangle objects, so we don't
produce so many throwaway Rectangles.

2006-02-27  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/RepaintManager.java
        (currentRepaintManagers): Made field private.
        (rectCache): New field.
        (addDirtyRegion): Clip dirty rectangle with visible rectangle of
        component. Changed Rectangle handling to avoid unnecessary new
        Rectangle instances.
        (getOffscreenBuffer): Create buffer with size of the root window.
        Respect the maximum buffer size here.
        (commitBuffer): Align the regions so that they are inside the
buffer
        image and inside the clip. This avoids problems with a bug in
GTKImage.
        Fixed Rectangle handling to avoid creation of new Rectangle
instances.

/Roman
Index: javax/swing/RepaintManager.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/RepaintManager.java,v
retrieving revision 1.26
diff -u -r1.26 RepaintManager.java
--- javax/swing/RepaintManager.java	23 Feb 2006 14:48:57 -0000	1.26
+++ javax/swing/RepaintManager.java	27 Feb 2006 12:44:46 -0000
@@ -43,6 +43,7 @@
 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;
@@ -73,8 +74,13 @@
   /**
    * The current repaint managers, indexed by their ThreadGroups.
    */
-  static WeakHashMap currentRepaintManagers;
-  
+  private 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
@@ -409,19 +415,30 @@
     if (w <= 0 || h <= 0 || !component.isShowing())
       return;
 
-    Rectangle r = new Rectangle(x, y, w, h);
-    if (dirtyComponents.containsKey(component))
-      r = r.union((Rectangle) dirtyComponents.get(component));
+    component.computeVisibleRect(rectCache);
+    SwingUtilities.computeIntersection(x, y, w, h, rectCache);
 
-    synchronized (dirtyComponents)
+    if (! rectCache.isEmpty())
       {
-        dirtyComponents.put(component, r);
-      }
+        if (dirtyComponents.containsKey(component))
+          {
+            SwingUtilities.computeUnion(rectCache.x, rectCache.y,
+                                        rectCache.width, rectCache.height,
+                                   (Rectangle) dirtyComponents.get(component));
+          }
+        else
+          {
+            synchronized (dirtyComponents)
+              {
+                dirtyComponents.put(component, rectCache.getBounds());
+              }
+          }
 
-    if (! repaintWorker.isLive())
-      {
-        repaintWorker.setLive(true);
-        SwingUtilities.invokeLater(repaintWorker);
+        if (! repaintWorker.isLive())
+          {
+            repaintWorker.setLive(true);
+            SwingUtilities.invokeLater(repaintWorker);
+          }
       }
   }
 
@@ -583,12 +600,14 @@
     Component root = SwingUtilities.getRoot(component);
     Image buffer = (Image) offscreenBuffers.get(root);
     if (buffer == null 
-        || ((buffer.getWidth(null) < proposedWidth 
-             || buffer.getHeight(null) < proposedHeight)
-            && proposedWidth < doubleBufferMaximumSize.width
-            && proposedHeight < doubleBufferMaximumSize.height))
+        || buffer.getWidth(null) < proposedWidth 
+        || buffer.getHeight(null) < proposedHeight)
       {
-        buffer = component.createImage(proposedWidth, proposedHeight);
+        int width = Math.max(proposedWidth, root.getWidth());
+        width = Math.min(doubleBufferMaximumSize.width, width);
+        int height = Math.max(proposedHeight, root.getHeight());
+        height = Math.min(doubleBufferMaximumSize.height, height);
+        buffer = component.createImage(width, height);
         offscreenBuffers.put(root, buffer);
       }
     return buffer;
@@ -624,20 +643,39 @@
             int dy1 = area.y;
             int dx2 = area.x + area.width;
             int dy2 = area.y + area.height;
+            // Make sure we have a sane clip at this point.
+            g.clipRect(area.x, area.y, area.width, area.height);
+
+            // Make sure the coordinates are inside the buffer, everything else
+            // might lead to problems.
+            // TODO: This code should not really be necessary, however, in fact
+            // we have two issues here:
+            // 1. We shouldn't get repaint requests in areas outside the buffer
+            //    region in the first place. This still happens for example
+            //    when a component is inside a JViewport, and the component has
+            //    a size that would reach beyond the window size.
+            // 2. Graphics.drawImage() should not behave strange when trying
+            //    to draw regions outside the image.
+            int bufferWidth = buffer.getWidth(root);
+            int bufferHeight = buffer.getHeight(root);
+            dx1 = Math.min(bufferWidth, dx1);
+            dy1 = Math.min(bufferHeight, dy1);
+            dx2 = Math.min(bufferWidth, dx2);
+            dy2 = Math.min(bufferHeight, dy2);
             g.drawImage(buffer, dx1, dy1, dx2, dy2,
-                        dx1, dy1, dx2, dy2, root);
+                                dx1, dy1, dx2, dy2, root);
             g.dispose();
           }
         // Otherwise queue this request up, until all the RepaintManager work
         // is done.
         else
           {
-            Rectangle commitArea;
             if (commitRequests.containsKey(root))
-              commitArea = area.union((Rectangle) commitRequests.get(root));
+              SwingUtilities.computeUnion(area.x, area.y, area.width,
+                                          area.height,
+                                         (Rectangle) commitRequests.get(root));
             else
-              commitArea = area;
-            commitRequests.put(root, commitArea);
+              commitRequests.put(root, area);
           }
       }
   }

Reply via email to