-
Bug
-
Resolution: Fixed
-
P2
-
1.4.0
-
beta2
-
generic
-
solaris_2.5
Apple is failing JCK 1.3 test api/java_awt/Layout/GridBagLayoutTests.html[GridBagLayoutTest0003] due to the bug in jdk GridBagLayout resizing code (when downsizing components).
Here's the message from Apple:
--------------------------------
The basic problem is that when the GridBagLayout manager needs to shrink
components it deals poorly with sizes which don't divide into integer
values over a size delta. And since Aqua buttons are somewhat largish we
are hitting this case. The problem being components are then laid out
partly outside their container and Container.getComponentAt(
xCompOrigin, yCompOrigin ) can't find them.
Here is the code:
diffw = parent.width - r.width;
if (diffw != 0) {
weight = 0.0;
for (i = 0; i < info.width; i++)
weight += info.weightX[i];
if (weight > 0.0) {
for (i = 0; i < info.width; i++) {
int dx = (int)(( ((double)diffw) * info.weightX[i]) /
weight); // Here's the problem
info.minWidth[i] += dx;
r.width += dx;
if (info.minWidth[i] < 0) {
r.width -= info.minWidth[i];
info.minWidth[i] = 0;
}
}
}
diffw = parent.width - r.width;
}
The problem occurs when the 'diffw' value computed in the first line is
negative. The computation for dx truncates non-integer values making,
for example, -12.5 into -12, so that the components are adjusted by
slightly less than needed for them to fit in the container. The final
value of diffw is then negative (-2 in our case), so when the components
are laid out, they are put slightly outside the container, and the JCK
test fails to find them using getComponentAt while passing the
out-of-bounds location.
We hit this problem on MacOS X because the Aqua look and feel provides a
larger preferred size for buttons than is common on other platforms, or
on earlier versions of the Mac OS.
----------------------------------
Here is the testcase that I created to reproduce the failure on solaris:
---------------------------------
import java.awt.*;
import java.io.*;
import java.util.*;
public class test1 {
static GridBagLayout gridbag1 = null;
public static void main(String[] argv) {
Frame f = CreateContainer();
for (int i = 0; i < 1000; i++) {
f.setSize(new Dimension(50 + (new Random()).nextInt(400), 50 + (new Random().nextInt(400))));
f.validate();
Component one = f.getComponent(0);
Point oLocation = one.getLocation();
Component oComponent = f.getComponentAt(oLocation.x, oLocation.y);
Object oObject = (Object) one;
boolean result = oComponent==oObject;
if (!result) {
System.out.println("Component not found at its location");
System.out.println("oLocation=" + oLocation);
System.out.println(result);
}
}
}
static Frame CreateContainer() {
Frame c = new Frame();
gridbag1 = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1.0;
c.setLayout(gridbag1);
Button [] buttons = new Button[16];
for (int i = 0; i <= 14; i++) {
buttons[i] = new Button("Button" + i);
gridbag1.setConstraints(buttons[i], constraints);
c.add(buttons[i]);
}
constraints.weightx = 0.0;
buttons[15] = new Button("one more");
gridbag1.setConstraints(buttons[15], constraints);
c.add(buttons[15]);
c.setLocation(100, 100);
c.setVisible(true);
c.doLayout();
while (!c.isShowing()) {}
return c;
}
}
-------------------------------------
Test output under jdk 1.3:
bash-2.00$ /export/tmp/java/jdk1.3/solaris/bin/java test1
Component not found at its location
oLocation=java.awt.Point[x=-1,y=177]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=-1,y=154]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
and so forth .......
--------------------------------------
This needs to be fixed.
Here's the message from Apple:
--------------------------------
The basic problem is that when the GridBagLayout manager needs to shrink
components it deals poorly with sizes which don't divide into integer
values over a size delta. And since Aqua buttons are somewhat largish we
are hitting this case. The problem being components are then laid out
partly outside their container and Container.getComponentAt(
xCompOrigin, yCompOrigin ) can't find them.
Here is the code:
diffw = parent.width - r.width;
if (diffw != 0) {
weight = 0.0;
for (i = 0; i < info.width; i++)
weight += info.weightX[i];
if (weight > 0.0) {
for (i = 0; i < info.width; i++) {
int dx = (int)(( ((double)diffw) * info.weightX[i]) /
weight); // Here's the problem
info.minWidth[i] += dx;
r.width += dx;
if (info.minWidth[i] < 0) {
r.width -= info.minWidth[i];
info.minWidth[i] = 0;
}
}
}
diffw = parent.width - r.width;
}
The problem occurs when the 'diffw' value computed in the first line is
negative. The computation for dx truncates non-integer values making,
for example, -12.5 into -12, so that the components are adjusted by
slightly less than needed for them to fit in the container. The final
value of diffw is then negative (-2 in our case), so when the components
are laid out, they are put slightly outside the container, and the JCK
test fails to find them using getComponentAt while passing the
out-of-bounds location.
We hit this problem on MacOS X because the Aqua look and feel provides a
larger preferred size for buttons than is common on other platforms, or
on earlier versions of the Mac OS.
----------------------------------
Here is the testcase that I created to reproduce the failure on solaris:
---------------------------------
import java.awt.*;
import java.io.*;
import java.util.*;
public class test1 {
static GridBagLayout gridbag1 = null;
public static void main(String[] argv) {
Frame f = CreateContainer();
for (int i = 0; i < 1000; i++) {
f.setSize(new Dimension(50 + (new Random()).nextInt(400), 50 + (new Random().nextInt(400))));
f.validate();
Component one = f.getComponent(0);
Point oLocation = one.getLocation();
Component oComponent = f.getComponentAt(oLocation.x, oLocation.y);
Object oObject = (Object) one;
boolean result = oComponent==oObject;
if (!result) {
System.out.println("Component not found at its location");
System.out.println("oLocation=" + oLocation);
System.out.println(result);
}
}
}
static Frame CreateContainer() {
Frame c = new Frame();
gridbag1 = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1.0;
c.setLayout(gridbag1);
Button [] buttons = new Button[16];
for (int i = 0; i <= 14; i++) {
buttons[i] = new Button("Button" + i);
gridbag1.setConstraints(buttons[i], constraints);
c.add(buttons[i]);
}
constraints.weightx = 0.0;
buttons[15] = new Button("one more");
gridbag1.setConstraints(buttons[15], constraints);
c.add(buttons[15]);
c.setLocation(100, 100);
c.setVisible(true);
c.doLayout();
while (!c.isShowing()) {}
return c;
}
}
-------------------------------------
Test output under jdk 1.3:
bash-2.00$ /export/tmp/java/jdk1.3/solaris/bin/java test1
Component not found at its location
oLocation=java.awt.Point[x=-1,y=177]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=-1,y=154]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
Component not found at its location
oLocation=java.awt.Point[x=0,y=0]
false
and so forth .......
--------------------------------------
This needs to be fixed.