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;