Hi discovered another performance related problem, which is the use of Container.getComponents(). This method is required to make a copy of the components array. However, when we want to iterate over the child components of a Container, we can just as well use Container.getComponentCount() and Container.getComponent() to do this without copying the array. I changed this in JComponent as this is very central. Eclipse points out a bunch of other locations where we should eventually fix this.

2006-07-07  Roman Kennke  <[EMAIL PROTECTED]>

       * javax/swing/JComponent.java
       (paintChildrenWithOverlap): Avoid array copying in
       Container.getComponents().
       (paintChildrenOptimized): Avoid array copying in
       Container.getComponents().
       (fireAncestorEvent):  Avoid array copying in
       Container.getComponents().
       (findOverlapFreeParent): Avoid array copying in
       Container.getComponents().


/Roman

Index: javax/swing/JComponent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JComponent.java,v
retrieving revision 1.138
diff -u -1 -2 -r1.138 JComponent.java
--- javax/swing/JComponent.java	30 Jun 2006 09:32:21 -0000	1.138
+++ javax/swing/JComponent.java	7 Jul 2006 12:38:52 -0000
@@ -1952,42 +1952,41 @@
    * is not marked as optimizedDrawingEnabled, that means the container cannot
    * guarantee that it's children are tiled. For this case we must
    * perform a more complex optimization to determine the minimal rectangle
    * to be painted for each child component.
    *
    * @param g the graphics context to use
    */
   private void paintChildrenWithOverlap(Graphics g)
   {
     Shape originalClip = g.getClip();
     Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache);
     g.clipRect(inner.x, inner.y, inner.width, inner.height);
-    Component[] children = getComponents();
 
     // Find the rectangles that need to be painted for each child component.
     // We push on this list arrays that have the Rectangles to be painted as
     // the first elements and the component to be painted as the last one.
     // Later we go through that list in reverse order and paint the rectangles.
-    ArrayList paintRegions = new ArrayList(children.length);
+    int numChildren = getComponentCount();
+    ArrayList paintRegions = new ArrayList(numChildren);
     ArrayList paintRectangles = new ArrayList();
     ArrayList newPaintRects = new ArrayList();
     paintRectangles.add(g.getClipBounds());
     ArrayList componentRectangles = new ArrayList();
 
     // Go through children from top to bottom and find out their paint
     // rectangles.
-    for (int index = 0; paintRectangles.size() > 0 &&
-      index < children.length; index++)
+    for (int index = 0; paintRectangles.size() > 0 && index < numChildren; index++)
       {
-        Component comp = children[index];
+        Component comp = getComponent(index);
         if (! comp.isVisible() || ! comp.isLightweight())
           continue;
 
         Rectangle compBounds = comp.getBounds();
         boolean isOpaque = comp.isOpaque();
 
         // Add all the current paint rectangles that intersect with the
         // component to the component's paint rectangle array.
         for (int i = paintRectangles.size() - 1; i >= 0; i--)
           {
             Rectangle r = (Rectangle) paintRectangles.get(i);
             if (r.intersects(compBounds))
@@ -2128,46 +2127,47 @@
    * Paints the children of this container when it is marked as
    * optimizedDrawingEnabled. In this case the container can guarantee that
    * it's children are tiled, which allows for a much more efficient
    * algorithm to determine the minimum rectangles to be painted for
    * each child.
    *
    * @param g the graphics context to use
    */
   private void paintChildrenOptimized(Graphics g)
   {
     Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache);
     g.clipRect(inner.x, inner.y, inner.width, inner.height);
-    Component[] children = getComponents();
 
     // paintingTile becomes true just before we start painting the component's
     // children.
     paintingTile = true;
-    for (int i = children.length - 1; i >= 0; i--) //children.length; i++)
+    int numChildren = getComponentCount();
+    for (int i = numChildren - 1; i >= 0; i--) //children.length; i++)
       {
+        Component child = getComponent(i);
         // paintingTile must be set to false before we begin to start painting
         // the last tile.
-        if (i == children.length - 1)
+        if (i == numChildren - 1)
           paintingTile = false;
 
-        if (!children[i].isVisible() || ! children[i].isLightweight())
+        if (!child.isVisible() || ! child.isLightweight())
           continue;
 
-        Rectangle bounds = children[i].getBounds(rectCache);
+        Rectangle bounds = child.getBounds(rectCache);
         if (!g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height))
           continue;
 
         Graphics g2 = g.create(bounds.x, bounds.y, bounds.width,
                                bounds.height);
-        children[i].paint(g2);
+        child.paint(g2);
         g2.dispose();
       }
   }
 
   /**
    * Paint the component's body. This usually means calling [EMAIL PROTECTED]
    * ComponentUI#update} on the [EMAIL PROTECTED] #ui} property of the component, if
    * it is non-<code>null</code>. You may override this if you wish to
    * customize the component's body-painting behavior. The component's body
    * is painted first, before the border and children.
    *
    * @param g The graphics context with which to paint the body
@@ -3680,30 +3680,31 @@
                 listeners[i].ancestorMoved(ev);
                 break;
               case AncestorEvent.ANCESTOR_ADDED:
                 listeners[i].ancestorAdded(ev);
                 break;
               case AncestorEvent.ANCESTOR_REMOVED:
                 listeners[i].ancestorRemoved(ev);
                 break;
               }
           }
       }
     // Dispatch event to all children.
-    Component[] children = getComponents();
-    for (int i = 0; i < children.length; i++)
+    int numChildren = getComponentCount();
+    for (int i = 0; i < numChildren; i++)
       {
-        if (!(children[i] instanceof JComponent))
+        Component child = getComponent(i);
+        if (! (child instanceof JComponent))
           continue;
-        JComponent jc = (JComponent) children[i];
+        JComponent jc = (JComponent) child;
         jc.fireAncestorEvent(ancestor, id);
       }
   }
 
   /**
    * Finds a suitable paint root for painting this component. This method first
    * checks if this component is overlapped using
    * [EMAIL PROTECTED] #findOverlapFreeParent(Rectangle)}. The returned paint root is then
    * feeded to [EMAIL PROTECTED] #findOpaqueParent(Component)} to find the nearest opaque
    * component for this paint root. If no paint is necessary, then we return
    * <code>null</code>.
    *
@@ -3768,28 +3769,28 @@
                                                            newParent);
 
         // We have an overlap if either:
         // - The new parent itself doesn't completely cover the clip
         //   (this can be the case with viewports).
         // - If some higher-level (than the current) children of the new parent
         //   intersect the target rectangle.
         Rectangle parentRect = SwingUtilities.getLocalBounds(newParent);
         boolean haveOverlap =
           ! SwingUtilities.isRectangleContainingRectangle(parentRect, target);
         if (! haveOverlap)
           {
-            Component[] children = newParent.getComponents();
-            for (int i = 0; children[i] != parent && !haveOverlap; i++)
+            Component child;
+            for (int i = 0; (child = newParent.getComponent(i)) != parent && !haveOverlap; i++)
               {
-                Rectangle childRect = children[i].getBounds();
+                Rectangle childRect = child.getBounds();
                 haveOverlap = target.intersects(childRect);
               }
           }
         if (haveOverlap)
           {
             found = newParent;
             currentClip = target;
           }
         parent = newParent;
       }
     //System.err.println("overlapfree parent: " + found);
     return found;

Reply via email to