United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 6682046 Mixing code does not always recalculate shapes correctly when resizing components
6682046 : Mixing code does not always recalculate shapes correctly when resizing components

Details
Type:
Bug
Submit Date:
2008-03-31
Status:
Resolved
Updated Date:
2011-03-11
Project Name:
JDK
Resolved Date:
2008-09-23
Component:
client-libs
OS:
windows_vista,linux,generic,windows_xp
Sub-Component:
java.awt
CPU:
x86,generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u7,7
Fixed Versions:
7

Related Reports
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:

Sub Tasks

Description
The following test fails to enlarge the button:

import java.awt.*;

public class Test {

    public static void main(String[] args) {
        Frame f = new Frame();
        Button b = new Button("ok");
        f.add(b);
        f.setExtendedState(Frame.MAXIMIZED_BOTH);
        f.pack();
        f.setVisible(true);
    }
}

This is a regression of the fix for CR 6637796.

                                    

Comments
SUGGESTED FIX

--- old/src/share/classes/java/awt/Button.java	2008-05-22 16:38:35.000000000 +0400
+++ new/src/share/classes/java/awt/Button.java	2008-05-22 16:38:34.000000000 +0400
@@ -213,7 +213,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (testvalid && valid) {
+        if (testvalid && isValid()) {
             invalidate();
         }
     }
--- old/src/share/classes/java/awt/Checkbox.java	2008-05-22 16:38:36.000000000 +0400
+++ new/src/share/classes/java/awt/Checkbox.java	2008-05-22 16:38:35.000000000 +0400
@@ -284,7 +284,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (testvalid && valid) {
+        if (testvalid && isValid()) {
             invalidate();
         }
     }
--- old/src/share/classes/java/awt/Choice.java	2008-05-22 16:38:37.000000000 +0400
+++ new/src/share/classes/java/awt/Choice.java	2008-05-22 16:38:36.000000000 +0400
@@ -207,7 +207,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -269,7 +269,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -299,7 +299,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -323,7 +323,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -367,7 +367,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
--- old/src/share/classes/java/awt/Component.java	2008-05-22 16:38:37.000000000 +0400
+++ new/src/share/classes/java/awt/Component.java	2008-05-22 16:38:37.000000000 +0400
@@ -345,7 +345,7 @@
      * @see #validate
      * @see #invalidate
      */
-    volatile boolean valid = false;
+    private volatile boolean valid = false;
 
     /**
      * The <code>DropTarget</code> associated with this component.
@@ -1061,6 +1061,9 @@
      * @since JDK1.0
      */
     public boolean isValid() {
+        return isValid_NoClientCode();
+    }
+    final boolean isValid_NoClientCode() {
         return (peer != null) && valid;
     }
 
@@ -1699,7 +1702,7 @@
         // This could change the preferred size of the Component.
         // Fix for 6213660. Should compare old and new fonts and do not
         // call invalidate() if they are equal.
-        if (valid && f != oldFont && (oldFont == null ||
+        if (isValid() && f != oldFont && (oldFont == null ||
                                       !oldFont.equals(f))) {
             invalidate();
         }
@@ -1758,7 +1761,7 @@
         firePropertyChange("locale", oldValue, l);
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -2069,7 +2072,7 @@
                     if (resized) {
                         invalidate();
                     }
-                    if (parent != null && parent.valid) {
+                    if (parent != null && parent.isValid_NoClientCode()) {
                         parent.invalidate();
                     }
                 }
@@ -2639,7 +2642,8 @@
     public void validate() {
         synchronized (getTreeLock()) {
             ComponentPeer peer = this.peer;
-            if (!valid && peer != null) {
+            boolean wasValid = isValid_NoClientCode();
+            if (!isValid && peer != null) {
                 Font newfont = getFont();
                 Font oldfont = peerFont;
                 if (newfont != oldfont && (oldfont == null
@@ -2650,6 +2654,9 @@
                 peer.layout();
             }
             valid = true;
+            if (!wasValid) {
+                mixOnValidating();
+            }
         }
     }
 
@@ -2678,7 +2685,7 @@
             if (!isMaximumSizeSet()) {
                 maxSize = null;
             }
-            if (parent != null && parent.valid) {
+            if (parent != null && parent.isValid_NoClientCode()) {
                 parent.invalidate();
             }
         }
@@ -7691,7 +7698,7 @@
     protected String paramString() {
         String thisName = getName();
         String str = (thisName != null? thisName : "") + "," + x + "," + y + "," + width + "x" + height;
-        if (!valid) {
+        if (!isValid()) {
             str += ",invalid";
         }
         if (!visible) {
@@ -8451,7 +8458,7 @@
         firePropertyChange("componentOrientation", oldValue, o);
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -9295,7 +9302,8 @@
      */
     private boolean areBoundsValid() {
         Container cont = getContainer();
-        return cont == null || cont.isValid() || cont.getLayout() == null;
+        return cont == null || cont.isValid_NoClientCode()
+            || cont.getLayout() == null;
     }
 
     /**
@@ -9566,5 +9574,8 @@
         }
     }
 
+    void mixOnValidating() {
+    }
+
     // ****************** END OF MIXING CODE ********************************
 }
--- old/src/share/classes/java/awt/Container.java	2008-05-22 16:38:39.000000000 +0400
+++ new/src/share/classes/java/awt/Container.java	2008-05-22 16:38:38.000000000 +0400
@@ -500,7 +500,7 @@
                              ncomponents - index - 1);
             component[--ncomponents] = null;
 
-            if (valid) {
+            if (isValid_NoClientCode()) {
                 invalidate();
             }
         } else {
@@ -804,7 +804,7 @@
             }
         }
 
-        if (valid) {
+        if (isValid_NoClientCode()) {
             invalidate();
         }
         if (peer != null) {
@@ -1090,7 +1090,7 @@
                 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
             adjustDescendants(comp.countHierarchyMembers());
 
-            if (valid) {
+            if (isValid_NoClientCode()) {
                 invalidate();
             }
             if (peer != null) {
@@ -1186,7 +1186,7 @@
                              ncomponents - index - 1);
             component[--ncomponents] = null;
 
-            if (valid) {
+            if (isValid_NoClientCode()) {
                 invalidate();
             }
             if (containerListener != null ||
@@ -1286,7 +1286,7 @@
             if (peer != null && layoutMgr == null && isVisible()) {
                 updateCursorImmediately();
             }
-            if (valid) {
+            if (isValid_NoClientCode()) {
                 invalidate();
             }
         }
@@ -1448,7 +1448,7 @@
      */
     public void setLayout(LayoutManager mgr) {
         layoutMgr = mgr;
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
@@ -1522,10 +1522,10 @@
      */
     public void validate() {
         /* Avoid grabbing lock unless really necessary. */
-        if (!valid) {
+        if (!isValid_NoClientCode()) {
             boolean updateCur = false;
             synchronized (getTreeLock()) {
-                if (!valid && peer != null) {
+                if (!isValid_NoClientCode() && peer != null) {
                     ContainerPeer p = null;
                     if (peer instanceof ContainerPeer) {
                         p = (ContainerPeer) peer;
@@ -1534,7 +1534,6 @@
                         p.beginValidate();
                     }
                     validateTree();
-                    valid = true;
                     if (p != null) {
                         p.endValidate();
                         updateCur = isVisible();
@@ -1557,7 +1556,7 @@
      * @see #validate
      */
     protected void validateTree() {
-        if (!valid) {
+        if (!isValid_NoClientCode()) {
             if (peer instanceof ContainerPeer) {
                 ((ContainerPeer)peer).beginLayout();
             }
@@ -1567,7 +1566,7 @@
                 Component comp = component[i];
                 if (   (comp instanceof Container)
                     && !(comp instanceof Window)
-                    && !comp.valid) {
+                    && !comp.isValid_NoClientCode()) {
                     ((Container)comp).validateTree();
                 } else {
                     comp.validate();
@@ -1577,7 +1576,7 @@
                 ((ContainerPeer)peer).endLayout();
             }
         }
-        valid = true;
+        super.validate();
     }
 
     /**
@@ -1592,12 +1591,12 @@
                     ((Container)comp).invalidateTree();
                 }
                 else {
-                    if (comp.valid) {
+                    if (comp.isValid_NoClientCode()) {
                         comp.invalidate();
                     }
                 }
             }
-            if (valid) {
+            if (isValid_NoClientCode()) {
                 invalidate();
             }
         }
@@ -4111,6 +4110,21 @@
         }
     }
 
+    @Override
+    void mixOnValidating() {
+        synchronized (getTreeLock()) {
+            if (mixingLog.isLoggable(Level.FINE)) {
+                mixingLog.fine("this = " + this);
+            }
+
+            if (hasHeavyweightDescendants()) {
+                recursiveApplyCurrentShape();
+            }
+
+            super.mixOnValidating();
+        }
+    }
+
     // ****************** END OF MIXING CODE ********************************
 }
 
--- old/src/share/classes/java/awt/Dialog.java	2008-05-22 16:38:40.000000000 +0400
+++ new/src/share/classes/java/awt/Dialog.java	2008-05-22 16:38:39.000000000 +0400
@@ -1327,7 +1327,7 @@
         // the insets of the Dialog. If we could, we'd call invalidate()
         // from the peer, but we need to guarantee that we're not holding
         // the Dialog lock when we call invalidate().
-        if (testvalid && valid) {
+        if (testvalid && isValid()) {
             invalidate();
         }
     }
--- old/src/share/classes/java/awt/Frame.java	2008-05-22 16:38:41.000000000 +0400
+++ new/src/share/classes/java/awt/Frame.java	2008-05-22 16:38:40.000000000 +0400
@@ -590,7 +590,7 @@
                 if (peer != null) {
                     mbManagement = true;
                     menuBar.addNotify();
-                    if (valid) {
+                    if (isValid_NoClientCode()) {
                         invalidate();
                     }
                     peer.setMenuBar(menuBar);
@@ -633,7 +633,7 @@
         // the insets of the Frame. If we could, we'd call invalidate()
         // from the peer, but we need to guarantee that we're not holding
         // the Frame lock when we call invalidate().
-        if (testvalid && valid) {
+        if (testvalid && isValid()) {
             invalidate();
         }
         firePropertyChange("resizable", oldResizable, resizable);
@@ -907,7 +907,7 @@
                 FramePeer peer = (FramePeer)this.peer;
                 if (peer != null) {
                     mbManagement = true;
-                    if (valid) {
+                    if (isValid_NoClientCode()) {
                         invalidate();
                     }
                     peer.setMenuBar(null);
--- old/src/share/classes/java/awt/Label.java	2008-05-22 16:38:42.000000000 +0400
+++ new/src/share/classes/java/awt/Label.java	2008-05-22 16:38:41.000000000 +0400
@@ -257,7 +257,7 @@
         }
 
         // This could change the preferred size of the Component.
-        if (testvalid && valid) {
+        if (testvalid && isValid()) {
             invalidate();
         }
     }
--- old/src/share/classes/java/awt/TextField.java	2008-05-22 16:38:43.000000000 +0400
+++ new/src/share/classes/java/awt/TextField.java	2008-05-22 16:38:42.000000000 +0400
@@ -296,7 +296,7 @@
         super.setText(t);
 
         // This could change the preferred size of the Component.
-        if (valid) {
+        if (isValid()) {
             invalidate();
         }
     }
--- /dev/null	2008-04-09 14:36:21.096432000 +0400
+++ new/test/java/awt/Mixing/Validating.java	2008-05-22 16:38:43.000000000 +0400
@@ -0,0 +1,382 @@
+/*
+  @test
+  @bug 6682046
+  @summary Mixing code does not always recalculate shapes correctly when resizing components
+  @author anthony.petrov@...: area=awt.mixing
+  @library ../regtesthelpers
+  @build Util
+  @run main Validating
+*/
+
+/**
+ * Validating.java
+ *
+ * summary:  Mixing code does not always recalculate shapes correctly when resizing components
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class Validating
+{
+    static volatile boolean clickPassed = false;
+
+    private static void init()
+    {
+        //*** Create instructions for the user here ***
+
+        String[] instructions =
+        {
+            "This is an AUTOMATIC test, simply wait until it is done.",
+            "The result (passed or failed) will be shown in the",
+            "message window below."
+        };
+        Sysout.createDialog( );
+        Sysout.printInstructions( instructions );
+
+        if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
+            System.out.println("The test environment does not support maximization. The test cannot be performed.");
+            pass();
+            return;
+        }
+
+        // Create the frame with a button.
+        Frame f = new Frame();
+        Button b = new Button("ok");
+        b.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                clickPassed = true;
+            }
+        });
+        f.add(b);
+        // Make the frame maximized
+        f.setExtendedState(Frame.MAXIMIZED_BOTH);
+        f.pack();
+        f.setVisible(true);
+
+        Robot robot = Util.createRobot();
+        robot.setAutoDelay(20);
+
+        Util.waitForIdle(robot);
+
+        // Now let's attempt to click in the middle of the button
+        // (i.e. in the middle of the window).
+        // If the button doesn't receive the click, it means that the test
+        // failed: the shape of the button was not enlarged.
+        Point heavyLoc = b.getLocationOnScreen();
+        robot.mouseMove(heavyLoc.x + b.getWidth() / 2, heavyLoc.y + b.getHeight() / 2);
+
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(robot);
+
+        if (clickPassed) {
+            pass();
+        } else {
+            fail("The button cannot be clicked.");
+        }
+    }//End  init()
+
+
+
+    /*****************************************************
+     * Standard Test Machinery Section
+     * DO NOT modify anything in this section -- it's a
+     * standard chunk of code which has all of the
+     * synchronisation necessary for the test harness.
+     * By keeping it the same in all tests, it is easier
+     * to read and understand someone else's test, as
+     * well as insuring that all tests behave correctly
+     * with the test harness.
+     * There is a section following this for test-
+     * classes
+     ******************************************************/
+    private static boolean theTestPassed = false;
+    private static boolean testGeneratedInterrupt = false;
+    private static String failureMessage = "";
+
+    private static Thread mainThread = null;
+
+    private static int sleepTime = 300000;
+
+    // Not sure about what happens if multiple of this test are
+    //  instantiated in the same VM.  Being static (and using
+    //  static vars), it aint gonna work.  Not worrying about
+    //  it for now.
+    public static void main( String args[] ) throws InterruptedException
+    {
+        mainThread = Thread.currentThread();
+        try
+        {
+            init();
+        }
+        catch( TestPassedException e )
+        {
+            //The test passed, so
                                     
2008-05-13
EVALUATION

It seems that fixing this issue by introducing an additional workaround doesn't make any sense. The root cause of this issue (as well as the 6637796) is the fact that the 'valid' property doesn't throw any notifications upon changes. However, the mixing code needs to handle changes to this property and recalculate the shapes of the effected components.

Which means that in order to fix this issue we need to rearchitect the validate()/invalidate()/isValid() machinery so that it allows to hook into the process of validating/invalidating a component.

The main task would be to identify all the locations of direct accessing of the 'valid' property and change them to use the setter/getter pair. After that, making the valid property private, we may be sure that we can safely hook into the setter and catch all the modifications to this property, and therefore we'll be able to correctly recalculate the shapes of components in appropriate moments of time.
                                     
2008-04-01



Hardware and Software, Engineered to Work Together