summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2006-08-23 22:03:22 +0000
committerRoman Kennke <roman@kennke.org>2006-08-23 22:03:22 +0000
commit16cbf77124e2ee77b17ff95816777f805c61d511 (patch)
tree32b5fb0384cd12a08a2b9ad9ffe5b4b3f42c687b
parent5586796c5ca3abc7f1248682f61700f983a8601b (diff)
downloadclasspath-16cbf77124e2ee77b17ff95816777f805c61d511.tar.gz
2006-08-23 Roman Kennke <kennke@aicas.com>
* javax/swing/JComponent.java (isRepainting): Made package private. (paintChild): New field. (findOpaqueParent): Removed method. This is now in paintImmediately(). (findOverlapFreeParent): Removed method. This is now in paintImmediately2(). (findPaintRoot): Removed method. This is now in paintImmediately2(). (isCompletelyObscured): Changed to take rectangle as single ints as argument. (isPaintingDoubleBuffered): Removed method. This is now in paintImmediately2(). (isPartiallyObscured): New helper method. (onTop): New helper method for optimization. (paintChildren): Paint only to specific child when requested like this from paintImmediately2(). (paintDoubleBuffered): Changed to take rectangle as single int arguments. (paintImmediately2): Changed to take rectangle as single int arguments. Optimized determination of paint root. (paintImmediately(Rectangle)): Change to delegate to paintImmediately(int,int,int,int). (paintImmediately(int,int,int,int)): Look for opaque ancestor and start painting there. (paint): Call paintDoubleBuffered() with int arguments. Only paint component, when not completely occupied by opaque child. (processKeyBinding): Removed unnecessary cast. (isOccupiedByChild): New helper method. * javax/swing/RepaintManager.java (repaintUnderway): Removed obsolete field. (commitRequests): Removed obsolete field. (RepaintManager): Removed initialization of obsolete fields. (addDirtyRegion): Removed unused statement. (commitBuffer): Changed to take plain ints as argument. (compileRepaintRoots): Optimized to avoid use of Rectangle. Compute offsets in place, rather than using SwingUtilities. (paintDirtyRegions): Removed unused field. * javax/swing/JMenuItem.java (onTop): Return true when not descendant of JInternalFrame. * javax/swing/JPopupMenu.java (onTop): Return true. * javax/swing/JToolTip.java (onTop): Return true. * javax/swing/JViewport.java (paintImmediately2): Change signature to match the corresponding JComponent method.
-rw-r--r--ChangeLog50
-rw-r--r--javax/swing/JComponent.java469
-rw-r--r--javax/swing/JMenuItem.java16
-rw-r--r--javax/swing/JPopupMenu.java14
-rw-r--r--javax/swing/JToolTip.java14
-rw-r--r--javax/swing/JViewport.java4
-rw-r--r--javax/swing/RepaintManager.java91
7 files changed, 447 insertions, 211 deletions
diff --git a/ChangeLog b/ChangeLog
index cf660111d..4c541bcbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2006-08-23 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/JComponent.java
+ (isRepainting): Made package private.
+ (paintChild): New field.
+ (findOpaqueParent): Removed method. This is now in
+ paintImmediately().
+ (findOverlapFreeParent): Removed method. This is now
+ in paintImmediately2().
+ (findPaintRoot): Removed method. This is now
+ in paintImmediately2().
+ (isCompletelyObscured): Changed to take rectangle as single
+ ints as argument.
+ (isPaintingDoubleBuffered): Removed method. This is now
+ in paintImmediately2().
+ (isPartiallyObscured): New helper method.
+ (onTop): New helper method for optimization.
+ (paintChildren): Paint only to specific child when
+ requested like this from paintImmediately2().
+ (paintDoubleBuffered): Changed to take rectangle as single int
+ arguments.
+ (paintImmediately2): Changed to take rectangle as single int
+ arguments. Optimized determination of paint root.
+ (paintImmediately(Rectangle)): Change to delegate to
+ paintImmediately(int,int,int,int).
+ (paintImmediately(int,int,int,int)): Look for opaque ancestor
+ and start painting there.
+ (paint): Call paintDoubleBuffered() with int arguments. Only
+ paint component, when not completely occupied by opaque child.
+ (processKeyBinding): Removed unnecessary cast.
+ (isOccupiedByChild): New helper method.
+ * javax/swing/RepaintManager.java
+ (repaintUnderway): Removed obsolete field.
+ (commitRequests): Removed obsolete field.
+ (RepaintManager): Removed initialization of obsolete fields.
+ (addDirtyRegion): Removed unused statement.
+ (commitBuffer): Changed to take plain ints as argument.
+ (compileRepaintRoots): Optimized to avoid use of Rectangle.
+ Compute offsets in place, rather than using SwingUtilities.
+ (paintDirtyRegions): Removed unused field.
+ * javax/swing/JMenuItem.java
+ (onTop): Return true when not descendant of JInternalFrame.
+ * javax/swing/JPopupMenu.java
+ (onTop): Return true.
+ * javax/swing/JToolTip.java
+ (onTop): Return true.
+ * javax/swing/JViewport.java
+ (paintImmediately2): Change signature to match the
+ corresponding JComponent method.
+
2006-08-23 Tania Bento <tbento@redhat.com>
* java/awt/Color.java
diff --git a/javax/swing/JComponent.java b/javax/swing/JComponent.java
index fc9353e06..91bb5428f 100644
--- a/javax/swing/JComponent.java
+++ b/javax/swing/JComponent.java
@@ -69,6 +69,7 @@ import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.EventListener;
import java.util.Hashtable;
import java.util.Locale;
@@ -666,7 +667,7 @@ public abstract class JComponent extends Container implements Serializable
* Indicates whether we are calling paintDoubleBuffered() from
* paintImmadiately (RepaintManager) or from paint() (AWT refresh).
*/
- static private boolean isRepainting = false;
+ static boolean isRepainting = false;
/**
* Listeners for events other than {@link PropertyChangeEvent} are
@@ -762,6 +763,13 @@ public abstract class JComponent extends Container implements Serializable
*/
public static final int WHEN_IN_FOCUSED_WINDOW = 2;
+
+ /**
+ * Used to optimize painting. This is set in paintImmediately2() to specify
+ * the exact component path to be painted by paintChildren.
+ */
+ Component paintChild;
+
/**
* Indicates if the opaque property has been set by a client program or by
* the UI.
@@ -1790,7 +1798,7 @@ public abstract class JComponent extends Container implements Serializable
&& rm.isDoubleBufferingEnabled())
{
Rectangle clip = g.getClipBounds();
- paintDoubleBuffered(clip);
+ paintDoubleBuffered(clip.x, clip.y, clip.width, clip.height);
}
else
{
@@ -1805,8 +1813,22 @@ public abstract class JComponent extends Container implements Serializable
dragBuffer = null;
}
- if (g.getClip() == null)
- g.setClip(0, 0, getWidth(), getHeight());
+ Rectangle clip = g.getClipBounds();
+ int clipX, clipY, clipW, clipH;
+ if (clip == null)
+ {
+ clipX = 0;
+ clipY = 0;
+ clipW = getWidth();
+ clipH = getHeight();
+ }
+ else
+ {
+ clipX = clip.x;
+ clipY = clip.y;
+ clipW = clip.width;
+ clipH = clip.height;
+ }
if (dragBuffer != null && dragBufferInitialized)
{
g.drawImage(dragBuffer, 0, 0, this);
@@ -1814,14 +1836,51 @@ public abstract class JComponent extends Container implements Serializable
else
{
Graphics g2 = getComponentGraphics(g);
- paintComponent(g2);
- paintBorder(g2);
+ if (! isOccupiedByChild(clipX, clipY, clipW, clipH))
+ {
+ paintComponent(g2);
+ paintBorder(g2);
+ }
paintChildren(g2);
}
}
}
/**
+ * Determines if a region of this component is completely occupied by
+ * an opaque child component, in which case we don't need to bother
+ * painting this component at all.
+ *
+ * @param x the area, x coordinate
+ * @param y the area, y coordinate
+ * @param w the area, width
+ * @param h the area, height
+ *
+ * @return <code>true</code> if the specified area is completely covered
+ * by a child component, <code>false</code> otherwise
+ */
+ private boolean isOccupiedByChild(int x, int y, int w, int h)
+ {
+ boolean occupied = false;
+ int count = getComponentCount();
+ for (int i = 0; i < count; i++)
+ {
+ Component child = getComponent(i);
+ int cx = child.getX();
+ int cy = child.getY();
+ int cw = child.getWidth();
+ int ch = child.getHeight();
+ if (child.isVisible() && x >= cx && x + w <= cx + cw && y >= cy
+ && y + h <= cy + ch)
+ {
+ occupied = child.isOpaque();
+ break;
+ }
+ }
+ return occupied;
+ }
+
+ /**
* Initializes the drag buffer by creating a new image and painting this
* component into it.
*/
@@ -1880,7 +1939,14 @@ public abstract class JComponent extends Container implements Serializable
// Need to lock the tree to avoid problems with AWT and concurrency.
synchronized (getTreeLock())
{
- for (int i = getComponentCount() - 1; i >= 0; i--)
+ // Fast forward to the child to paint, if set by
+ // paintImmediately2()
+ int i = getComponentCount() - 1;
+ if (paintChild != null && paintChild.isOpaque())
+ {
+ for (; i >= 0 && getComponent(i) != paintChild; i--);
+ }
+ for (; i >= 0; i--)
{
Component child = getComponent(i);
if (child != null && child.isLightweight()
@@ -1898,7 +1964,8 @@ public abstract class JComponent extends Container implements Serializable
Rectangle clip = g.getClipBounds(); // A copy.
SwingUtilities.computeIntersection(cx, cy, cw, ch,
clip);
- if (isCompletelyObscured(i, clip))
+ if (isCompletelyObscured(i, clip.x, clip.y,
+ clip.width, clip.height))
continue; // Continues the for-loop.
}
Graphics cg = g.create(cx, cy, cw, ch);
@@ -1924,12 +1991,15 @@ public abstract class JComponent extends Container implements Serializable
* of its siblings.
*
* @param index the index of the child component
- * @param rect the region to check
+ * @param x the region to check, x coordinate
+ * @param y the region to check, y coordinate
+ * @param w the region to check, width
+ * @param h the region to check, height
*
* @return <code>true</code> if the region is completely obscured by a
* sibling, <code>false</code> otherwise
*/
- private boolean isCompletelyObscured(int index, Rectangle rect)
+ private boolean isCompletelyObscured(int index, int x, int y, int w, int h)
{
boolean obscured = false;
for (int i = index - 1; i >= 0 && obscured == false; i--)
@@ -1938,10 +2008,10 @@ public abstract class JComponent extends Container implements Serializable
if (sib.isVisible())
{
Rectangle sibRect = sib.getBounds(rectCache);
- if (sib.isOpaque() && rect.x >= sibRect.x
- && (rect.x + rect.width) <= (sibRect.x + sibRect.width)
- && rect.y >= sibRect.y
- && (rect.y + rect.height) <= (sibRect.y + sibRect.height))
+ if (sib.isOpaque() && x >= sibRect.x
+ && (x + w) <= (sibRect.x + sibRect.width)
+ && y >= sibRect.y
+ && (y + h) <= (sibRect.y + sibRect.height))
{
obscured = true;
}
@@ -1951,6 +2021,39 @@ public abstract class JComponent extends Container implements Serializable
}
/**
+ * Checks if a component/rectangle is partially obscured by one of its
+ * siblings.
+ * Note that this doesn't check for completely obscured, this is
+ * done by isCompletelyObscured() and should probably also be checked.
+ *
+ * @param i the component index from which to start searching
+ * @param x the x coordinate of the rectangle to check
+ * @param y the y coordinate of the rectangle to check
+ * @param w the width of the rectangle to check
+ * @param h the height of the rectangle to check
+ *
+ * @return <code>true</code> if the rectangle is partially obscured
+ */
+ private boolean isPartiallyObscured(int i, int x, int y, int w, int h)
+ {
+ boolean obscured = false;
+ for (int j = i - 1; j >= 0 && ! obscured; j--)
+ {
+ Component sibl = getComponent(j);
+ if (sibl.isVisible())
+ {
+ Rectangle rect = sibl.getBounds(rectCache);
+ if (!(x + w <= rect.x)
+ || (y + h <= rect.y)
+ || (x >= rect.x + rect.width)
+ || (y >= rect.y + rect.height))
+ obscured = true;
+ }
+ }
+ return obscured;
+ }
+
+ /**
* Paint the component's body. This usually means calling {@link
* ComponentUI#update} on the {@link #ui} property of the component, if
* it is non-<code>null</code>. You may override this if you wish to
@@ -1990,7 +2093,26 @@ public abstract class JComponent extends Container implements Serializable
*/
public void paintImmediately(int x, int y, int w, int h)
{
- paintImmediately(new Rectangle(x, y, w, h));
+ // Find opaque parent and call paintImmediately2() on it.
+ if (isShowing())
+ {
+ Component c = this;
+ Component p;
+ while (c != null && ! c.isOpaque())
+ {
+ p = c.getParent();
+ if (p != null)
+ {
+ x += c.getX();
+ y += c.getY();
+ c = p;
+ }
+ }
+ if (c instanceof JComponent)
+ ((JComponent) c).paintImmediately2(x, y, w, h);
+ else
+ c.repaint(x, y, w, h);
+ }
}
/**
@@ -2013,60 +2135,177 @@ public abstract class JComponent extends Container implements Serializable
*/
public void paintImmediately(Rectangle r)
{
- // Try to find a root pane for this component.
- //Component root = findPaintRoot(r);
- Component root = findPaintRoot(r);
- // If no paint root is found, then this component is completely overlapped
- // by another component and we don't need repainting.
- if (root == null|| !root.isShowing())
- return;
- SwingUtilities.convertRectangleToAncestor(this, r, root);
- if (root instanceof JComponent)
- ((JComponent) root).paintImmediately2(r);
- else
- root.repaint(r.x, r.y, r.width, r.height);
+ paintImmediately(r.x, r.y, r.width, r.height);
}
/**
* Performs the actual work of paintImmediatly on the repaint root.
*
- * @param r the area to be repainted
+ * @param x the area to be repainted, X coordinate
+ * @param y the area to be repainted, Y coordinate
*/
- void paintImmediately2(Rectangle r)
+ void paintImmediately2(int x, int y, int w, int h)
{
- isRepainting = true;
+ // Optimization for components that are always painted on top.
+ boolean onTop = onTop() && isOpaque();
+
+ // Fetch the RepaintManager.
RepaintManager rm = RepaintManager.currentManager(this);
- if (rm.isDoubleBufferingEnabled() && isPaintingDoubleBuffered())
- paintDoubleBuffered(r);
- else
- paintSimple(r);
- isRepainting = false;
+
+ // The painting clip;
+ int paintX = x;
+ int paintY = y;
+ int paintW = w;
+ int paintH = h;
+
+ // If we should paint buffered or not.
+ boolean haveBuffer = false;
+
+ // The component that is finally triggered for painting.
+ JComponent paintRoot = this;
+
+ // Stores the component and all its parents. This will be used to limit
+ // the actually painted components in paintChildren by setting
+ // the field paintChild.
+ int pIndex = -1;
+ int pCount = 0;
+ ArrayList components = new ArrayList();
+
+ // Offset to subtract from the paintRoot rectangle when painting.
+ int offsX = 0;
+ int offsY = 0;
+
+ // The current component and its child.
+ Component child;
+ Container c;
+
+ // Find appropriate paint root.
+ for (c = this, child = null;
+ c != null && ! (c instanceof Window) && ! (c instanceof Applet);
+ child = c, c = c.getParent())
+ {
+ JComponent jc = c instanceof JComponent ? (JComponent) c : null;
+ components.add(c);
+ if (! onTop && jc != null && ! jc.isOptimizedDrawingEnabled())
+ {
+ // Check obscured state of the child.
+ // Generally, we have 3 cases here:
+ // 1. Not obscured. No need to paint from the parent.
+ // 2. Partially obscured. Paint from the parent.
+ // 3. Completely obscured. No need to paint anything.
+ if (c != this)
+ {
+ int count = c.getComponentCount();
+ int i = 0;
+ for (; i < count && c.getComponent(i) != child; i++);
+
+ if (jc.isCompletelyObscured(i, paintX, paintY, paintW, paintH))
+ return; // No need to paint anything.
+ else if (jc.isPartiallyObscured(i, paintX, paintY, paintW,
+ paintH))
+ {
+ // Paint from parent.
+ paintRoot = jc;
+ pIndex = pCount;
+ offsX = 0;
+ offsY = 0;
+ haveBuffer = false;
+ }
+ }
+ }
+ pCount++;
+ // Check if component is double buffered.
+ if (rm.isDoubleBufferingEnabled() && jc != null
+ && jc.isDoubleBuffered())
+ {
+ haveBuffer = true;
+ }
+
+ // Clip the paint region with the parent.
+ if (! onTop)
+ {
+ paintX = Math.max(0, paintX);
+ paintY = Math.max(0, paintY);
+ paintW = Math.min(c.getWidth(), paintW + paintX) - paintX;
+ paintH = Math.min(c.getHeight(), paintH + paintY) - paintY;
+ int dx = c.getX();
+ int dy = c.getY();
+ paintX += dx;
+ paintY += dy;
+ offsX += dx;
+ offsY += dy;
+ }
+ }
+ if (c != null && c.getPeer() != null && paintW > 0 && paintH > 0)
+ {
+ isRepainting = true;
+ paintX -= offsX;
+ paintY -= offsY;
+
+ // Set the painting path so that paintChildren paints only what we
+ // want.
+ if (paintRoot != this)
+ {
+ for (int i = pIndex; i > 0; i--)
+ {
+ Component paintParent = (Component) components.get(i);
+ if (paintParent instanceof JComponent)
+ ((JComponent) paintParent).paintChild =
+ (Component) components.get(i - 1);
+ }
+ }
+
+ // Actually trigger painting.
+ if (haveBuffer)
+ paintRoot.paintDoubleBuffered(paintX, paintY, paintW,
+ paintH);
+ else
+ {
+ Graphics g = paintRoot.getGraphics();
+ try
+ {
+ g.setClip(paintX, paintY, paintW, paintH);
+ paintRoot.paint(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ // Reset the painting path.
+ if (paintRoot != this)
+ {
+ for (int i = pIndex; i > 0; i--)
+ {
+ Component paintParent = (Component) components.get(i);
+ if (paintParent instanceof JComponent)
+ ((JComponent) paintParent).paintChild = null;
+ }
+ }
+
+ isRepainting = false;
+ }
}
/**
- * Returns true if we must paint double buffered, that is, when this
- * component or any of it's ancestors are double buffered.
+ * Returns <code>true</code> if the component is guaranteed to be painted
+ * on top of others. This returns false by default and is overridden by
+ * components like JMenuItem, JPopupMenu and JToolTip to return true for
+ * added efficiency.
*
- * @return true if we must paint double buffered, that is, when this
- * component or any of it's ancestors are double buffered
+ * @return <code>true</code> if the component is guaranteed to be painted
+ * on top of others
*/
- private boolean isPaintingDoubleBuffered()
+ boolean onTop()
{
- boolean doubleBuffered = isDoubleBuffered();
- Component parent = getParent();
- while (! doubleBuffered && parent != null)
- {
- doubleBuffered = parent instanceof JComponent
- && ((JComponent) parent).isDoubleBuffered();
- parent = parent.getParent();
- }
- return doubleBuffered;
+ return false;
}
/**
* Performs double buffered repainting.
*/
- private void paintDoubleBuffered(Rectangle r)
+ private void paintDoubleBuffered(int x, int y, int w, int h)
{
RepaintManager rm = RepaintManager.currentManager(this);
@@ -2083,7 +2322,7 @@ public abstract class JComponent extends Container implements Serializable
//Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root);
Graphics g2 = buffer.getGraphics();
clipAndTranslateGraphics(root, this, g2);
- g2.clipRect(r.x, r.y, r.width, r.height);
+ g2.clipRect(x, y, w, h);
g2 = getComponentGraphics(g2);
paintingDoubleBuffered = true;
try
@@ -2104,7 +2343,7 @@ public abstract class JComponent extends Container implements Serializable
}
// Paint the buffer contents on screen.
- rm.commitBuffer(this, r);
+ rm.commitBuffer(this, x, y, w, h);
}
/**
@@ -2531,7 +2770,7 @@ public abstract class JComponent extends Container implements Serializable
if (cmd instanceof ActionListenerProxy)
act = (Action) cmd;
else
- act = (Action) getActionMap().get(cmd);
+ act = getActionMap().get(cmd);
}
}
if (act != null && act.isEnabled())
@@ -3476,130 +3715,6 @@ public abstract class JComponent extends Container implements Serializable
jc.fireAncestorEvent(ancestor, id);
}
}
-
- /**
- * Finds a suitable paint root for painting this component. This method first
- * checks if this component is overlapped using
- * {@link #findOverlapFreeParent(Rectangle)}. The returned paint root is then
- * feeded to {@link #findOpaqueParent(Component)} to find the nearest opaque
- * component for this paint root. If no paint is necessary, then we return
- * <code>null</code>.
- *
- * @param c the clip of this component
- *
- * @return the paint root or <code>null</code> if no painting is necessary
- */
- private Component findPaintRoot(Rectangle c)
- {
- Component p = findOverlapFreeParent(c);
- if (p == null)
- return null;
- Component root = findOpaqueParent(p);
- return root;
- }
-
- /**
- * Scans the containment hierarchy upwards for components that overlap the
- * this component in the specified clip. This method returns
- * <code>this</code>, if no component overlaps this component. It returns
- * <code>null</code> if another component completely covers this component
- * in the specified clip (no repaint necessary). If another component partly
- * overlaps this component in the specified clip, then the parent of this
- * component is returned (this is the component that must be used as repaint
- * root). For efficient lookup, the method
- * {@link #isOptimizedDrawingEnabled()} is used.
- *
- * @param clip the clip of this component
- *
- * @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;
-
- 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()))
-
- {
- parent = newParent;
- continue;
- }
-
- // If the parent is not optimizedDrawingEnabled, we must check if the
- // parent or some neighbor overlaps the current clip.
-
- // This is the current clip converted to the parent's coordinate
- // system. TODO: We can do this more efficiently by succesively
- // cumulating the parent-child translations.
- Rectangle target = SwingUtilities.convertRectangle(found,
- currentClip,
- 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 child;
- for (int i = 0; (child = newParent.getComponent(i)) != parent && !haveOverlap; i++)
- {
- Rectangle childRect = child.getBounds();
- haveOverlap = target.intersects(childRect);
- }
- }
- if (haveOverlap)
- {
- found = newParent;
- currentClip = target;
- }
- parent = newParent;
- }
- //System.err.println("overlapfree parent: " + found);
- return found;
- }
-
- /**
- * Finds the nearest component to <code>c</code> (upwards in the containment
- * hierarchy), that is opaque. If <code>c</code> itself is opaque,
- * this returns <code>c</code> itself.
- *
- * @param c the start component for the search
- * @return the nearest component to <code>c</code> (upwards in the containment
- * hierarchy), that is opaque; If <code>c</code> itself is opaque,
- * this returns <code>c</code> itself
- */
- private Component findOpaqueParent(Component c)
- {
- Component found = c;
- while (true)
- {
- if ((found instanceof JComponent) && ((JComponent) found).isOpaque())
- break;
- else if (!(found instanceof JComponent) && !found.isLightweight())
- break;
- Container p = found.getParent();
- if (p == null)
- break;
- else
- found = p;
- }
- return found;
- }
/**
* This is the method that gets called when the WHEN_IN_FOCUSED_WINDOW map
diff --git a/javax/swing/JMenuItem.java b/javax/swing/JMenuItem.java
index f7f93bf00..324d61cd4 100644
--- a/javax/swing/JMenuItem.java
+++ b/javax/swing/JMenuItem.java
@@ -833,4 +833,20 @@ public class JMenuItem extends AbstractButton implements Accessible,
return AccessibleRole.MENU_ITEM;
}
}
+
+ /**
+ * Returns <code>true</code> if the component is guaranteed to be painted
+ * on top of others. This returns false by default and is overridden by
+ * components like JMenuItem, JPopupMenu and JToolTip to return true for
+ * added efficiency.
+ *
+ * @return <code>true</code> if the component is guaranteed to be painted
+ * on top of others
+ */
+ boolean onTop()
+ {
+ return SwingUtilities.getAncestorOfClass(JInternalFrame.class, this)
+ == null;
+ }
+
}
diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java
index 2e59d4767..1ae8adad0 100644
--- a/javax/swing/JPopupMenu.java
+++ b/javax/swing/JPopupMenu.java
@@ -902,6 +902,20 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement
}
}
+ /**
+ * Returns <code>true</code> if the component is guaranteed to be painted
+ * on top of others. This returns false by default and is overridden by
+ * components like JMenuItem, JPopupMenu and JToolTip to return true for
+ * added efficiency.
+ *
+ * @return <code>true</code> if the component is guaranteed to be painted
+ * on top of others
+ */
+ boolean onTop()
+ {
+ return true;
+ }
+
protected class AccessibleJPopupMenu extends AccessibleJComponent
{
private static final long serialVersionUID = 7423261328879849768L;
diff --git a/javax/swing/JToolTip.java b/javax/swing/JToolTip.java
index 836c122c6..3153894da 100644
--- a/javax/swing/JToolTip.java
+++ b/javax/swing/JToolTip.java
@@ -225,4 +225,18 @@ public class JToolTip extends JComponent implements Accessible
{
setUI((ToolTipUI) UIManager.getUI(this));
}
+
+ /**
+ * Returns <code>true</code> if the component is guaranteed to be painted
+ * on top of others. This returns false by default and is overridden by
+ * components like JMenuItem, JPopupMenu and JToolTip to return true for
+ * added efficiency.
+ *
+ * @return <code>true</code> if the component is guaranteed to be painted
+ * on top of others
+ */
+ boolean onTop()
+ {
+ return true;
+ }
}
diff --git a/javax/swing/JViewport.java b/javax/swing/JViewport.java
index 7cf393996..babffb7ce 100644
--- a/javax/swing/JViewport.java
+++ b/javax/swing/JViewport.java
@@ -942,10 +942,10 @@ public class JViewport extends JComponent implements Accessible
*
* @param r the rectangle to paint
*/
- void paintImmediately2(Rectangle r)
+ void paintImmediately2(int x, int y, int w, int h)
{
isPaintRoot = true;
- super.paintImmediately2(r);
+ super.paintImmediately2(x, y, w, h);
isPaintRoot = false;
}
}
diff --git a/javax/swing/RepaintManager.java b/javax/swing/RepaintManager.java
index 51f0f9b6a..99a733a5a 100644
--- a/javax/swing/RepaintManager.java
+++ b/javax/swing/RepaintManager.java
@@ -197,19 +197,6 @@ public class RepaintManager
private WeakHashMap offscreenBuffers;
/**
- * Indicates if the RepaintManager is currently repainting an area.
- */
- private boolean repaintUnderway;
-
- /**
- * This holds buffer commit requests when the RepaintManager is working.
- * This maps Component objects (the top level components) to Rectangle
- * objects (the area of the corresponding buffer that must be blitted on
- * the component).
- */
- private HashMap commitRequests;
-
- /**
* The maximum width and height to allocate as a double buffer. Requests
* beyond this size are ignored.
*
@@ -232,8 +219,6 @@ public class RepaintManager
doubleBufferMaximumSize = new Dimension(2000,2000);
doubleBufferingEnabled = true;
offscreenBuffers = new WeakHashMap();
- repaintUnderway = false;
- commitRequests = new HashMap();
}
/**
@@ -398,8 +383,6 @@ public class RepaintManager
if (w <= 0 || h <= 0 || !component.isShowing())
return;
- Component parent = component.getParent();
-
component.computeVisibleRect(rectCache);
SwingUtilities.computeIntersection(x, y, w, h, rectCache);
@@ -557,7 +540,6 @@ public class RepaintManager
compileRepaintRoots(dirtyComponentsWork, dirty, repaintRoots);
}
- repaintUnderway = true;
for (Iterator i = repaintRoots.iterator(); i.hasNext();)
{
JComponent comp = (JComponent) i.next();
@@ -567,12 +549,11 @@ public class RepaintManager
comp.paintImmediately(damaged);
}
dirtyComponentsWork.clear();
- repaintUnderway = false;
}
-
+
/**
* Compiles a list of components that really get repainted. This is called
- * once for each component in the dirtyComponents HashMap, each time with
+ * once for each component in the dirtyRegions 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.
@@ -587,6 +568,29 @@ public class RepaintManager
Component current = dirty;
Component root = dirty;
+ // This will contain the dirty region in the root coordinate system,
+ // possibly clipped by ancestor's bounds.
+ Rectangle originalDirtyRect = (Rectangle) dirtyRegions.get(dirty);
+ rectCache.setBounds(originalDirtyRect);
+
+ // The bounds of the current component.
+ int x = dirty.getX();
+ int y = dirty.getY();
+ int w = dirty.getWidth();
+ int h = dirty.getHeight();
+
+ // Do nothing if dirty region is clipped away by the component's bounds.
+ rectCache = SwingUtilities.computeIntersection(0, 0, w, h, rectCache);
+ if (rectCache.isEmpty())
+ return;
+
+ // The cumulated offsets.
+ int dx = 0;
+ int dy = 0;
+ // The actual offset for the found root.
+ int rootDx = 0;
+ int rootDy = 0;
+
// Search the highest component that is also marked dirty.
Component parent;
while (true)
@@ -596,10 +600,29 @@ public class RepaintManager
break;
current = parent;
+ // Update the offset.
+ dx += x;
+ dy += y;
+ rectCache.x += x;
+ rectCache.y += y;
+
+ x = current.getX();
+ y = current.getY();
+ w = current.getWidth();
+ h = current.getHeight();
+ rectCache = SwingUtilities.computeIntersection(0, 0, w, h, rectCache);
+
+ // Don't paint if the dirty regions is clipped away by any of
+ // its ancestors.
+ if (rectCache.isEmpty())
+ return;
+
// We can skip to the next up when this parent is not dirty.
if (dirtyRegions.containsKey(parent))
{
root = current;
+ rootDx = dx;
+ rootDy = dy;
}
}
@@ -607,15 +630,16 @@ public class RepaintManager
// 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);
+ rectCache.x += rootDx - dx;
+ rectCache.y += rootDy - dy;
+ Rectangle dirtyRect = (Rectangle) dirtyRegions.get(root);
+ SwingUtilities.computeUnion(rectCache.x, rectCache.y, rectCache.width,
+ rectCache.height, dirtyRect);
}
// Adds the root to the roots set.
- roots.add(root);
+ if (! roots.contains(root))
+ roots.add(root);
}
/**
@@ -653,16 +677,19 @@ public class RepaintManager
* This is package private because it must get called by JComponent.
*
* @param comp the component to be painted
- * @param area the area to paint on screen, in comp coordinates
+ * @param x the area to paint on screen, in comp coordinates
+ * @param y the area to paint on screen, in comp coordinates
+ * @param w the area to paint on screen, in comp coordinates
+ * @param h the area to paint on screen, in comp coordinates
*/
- void commitBuffer(Component comp, Rectangle area)
+ void commitBuffer(Component comp, int x, int y, int w, int h)
{
Component root = comp;
while (root != null
&& ! (root instanceof Window || root instanceof Applet))
{
- area.x += root.getX();
- area.y += root.getY();
+ x += root.getX();
+ y += root.getY();
root = root.getParent();
}
@@ -670,7 +697,7 @@ public class RepaintManager
Image buffer = (Image) offscreenBuffers.get(root);
// Make sure we have a sane clip at this point.
- g.clipRect(area.x, area.y, area.width, area.height);
+ g.clipRect(x, y, w, h);
g.drawImage(buffer, 0, 0, root);
g.dispose();
}