Skip to content

Commit b99011f

Browse files
author
duke
committed
Backport 3d49fb8
1 parent 69d97e0 commit b99011f

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
/*
2+
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.Color;
25+
import java.awt.Dimension;
26+
import java.awt.FlowLayout;
27+
import java.awt.Point;
28+
import java.awt.Rectangle;
29+
import java.awt.Robot;
30+
import java.awt.event.FocusAdapter;
31+
import java.awt.event.FocusEvent;
32+
import java.awt.image.BufferedImage;
33+
import java.awt.image.ColorModel;
34+
import java.awt.image.Raster;
35+
import java.io.File;
36+
import java.io.IOException;
37+
import java.util.concurrent.CountDownLatch;
38+
import java.util.concurrent.TimeUnit;
39+
import java.util.concurrent.atomic.AtomicReference;
40+
import javax.imageio.ImageIO;
41+
import javax.swing.JButton;
42+
import javax.swing.JFrame;
43+
import javax.swing.SwingUtilities;
44+
45+
/*
46+
* @test
47+
* @bug 8338103
48+
* @key headful
49+
* @summary Verifies that the OpenGL pipeline does not create artifacts
50+
* with swing components after window is zoomed to maximum size and then
51+
* resized back to normal. The test case simulates this operation using
52+
* a JButton. A file image of the component will be saved before and after
53+
* the window resize if the test fails. The test passes if both the button
54+
* images are the same.
55+
* @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=false SwingButtonResizeTestWithOpenGL
56+
* @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=true SwingButtonResizeTestWithOpenGL
57+
* @run main/othervm -Dsun.java2d.opengl=false SwingButtonResizeTestWithOpenGL
58+
* @run main/othervm SwingButtonResizeTestWithOpenGL
59+
*/
60+
/*
61+
* @test
62+
* @key headful
63+
* @requires (os.family == "windows")
64+
* @run main/othervm -Dsun.java2d.d3d=false SwingButtonResizeTestWithOpenGL
65+
* @run main/othervm -Dsun.java2d.d3d=true SwingButtonResizeTestWithOpenGL
66+
*/
67+
/*
68+
* @test
69+
* @key headful
70+
* @requires (os.family == "linux")
71+
* @run main/othervm -Dsun.java2d.xrender=false SwingButtonResizeTestWithOpenGL
72+
* @run main/othervm -Dsun.java2d.xrender=true SwingButtonResizeTestWithOpenGL
73+
*/
74+
/*
75+
* @test
76+
* @key headful
77+
* @requires (os.family == "mac")
78+
* @run main/othervm -Dsun.java2d.metal=false SwingButtonResizeTestWithOpenGL
79+
* @run main/othervm -Dsun.java2d.metal=true SwingButtonResizeTestWithOpenGL
80+
*/
81+
public class SwingButtonResizeTestWithOpenGL {
82+
private static Robot robot;
83+
private static CountDownLatch focusGainedLatch;
84+
private JFrame frame;
85+
private JButton button;
86+
87+
public SwingButtonResizeTestWithOpenGL() {
88+
89+
try {
90+
SwingUtilities.invokeAndWait(() -> createGUI());
91+
} catch (Exception e) {
92+
throw new RuntimeException("Problems creating GUI");
93+
}
94+
}
95+
96+
private void createGUI() {
97+
frame = new JFrame("SwingButtonResizeTestWithOpenGL");
98+
button = new JButton("Button A");
99+
frame.setLocation(200, 200);
100+
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
101+
button.setPreferredSize(new Dimension(300, 300));
102+
button.addFocusListener(new FocusAdapter() {
103+
public void focusGained(FocusEvent fe) {
104+
focusGainedLatch.countDown();
105+
}
106+
});
107+
frame.getContentPane().setLayout(new FlowLayout());
108+
frame.getContentPane().add(button);
109+
frame.pack();
110+
frame.setVisible(true);
111+
frame.toFront();
112+
}
113+
114+
public static void main(String[] args) throws Exception {
115+
focusGainedLatch = new CountDownLatch(1);
116+
SwingButtonResizeTestWithOpenGL test =
117+
new SwingButtonResizeTestWithOpenGL();
118+
test.runTest();
119+
}
120+
121+
public void runTest() throws Exception {
122+
BufferedImage bimage1;
123+
BufferedImage bimage2;
124+
125+
try {
126+
robot = new Robot();
127+
robot.setAutoWaitForIdle(true);
128+
robot.setAutoDelay(200);
129+
130+
if (focusGainedLatch.await(3, TimeUnit.SECONDS)) {
131+
System.out.println("Button focus gained...");
132+
} else {
133+
System.out.println("Button focus not gained...");
134+
throw new RuntimeException(
135+
"Can't gain focus on button even after waiting " +
136+
"too long..");
137+
}
138+
139+
System.out.println("Getting initial button image..image1");
140+
bimage1 = getButtonImage();
141+
142+
// some platforms may not support maximize frame
143+
if (frame.getToolkit().isFrameStateSupported(
144+
JFrame.MAXIMIZED_BOTH)) {
145+
robot.waitForIdle();
146+
// maximize frame from normal size
147+
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
148+
System.out.println("Frame is maximized");
149+
robot.waitForIdle();
150+
151+
if (frame.getToolkit().isFrameStateSupported(JFrame.NORMAL)) {
152+
System.out.println("Frame is back to normal");
153+
// resize from maximum size to normal
154+
frame.setExtendedState(JFrame.NORMAL);
155+
156+
// capture image of JButton after resize
157+
System.out.println(
158+
"Getting image of JButton after resize..image2");
159+
bimage2 = getButtonImage();
160+
161+
// compare button images from before and after frame resize
162+
DiffImage di = new DiffImage(bimage1.getWidth(),
163+
bimage1.getHeight());
164+
System.out.println(
165+
"Taking the diff of two images, image1 and image2");
166+
if (!di.compare(bimage1, bimage2)) {
167+
throw new RuntimeException(
168+
"Button renderings are different after window "
169+
+ "resize, num of Diff Pixels="
170+
+ di.getNumDiffPixels());
171+
} else {
172+
System.out.println("Test passed...");
173+
}
174+
175+
} else {
176+
System.out.println(
177+
"Test skipped: JFrame.NORMAL resize is " +
178+
"not supported");
179+
}
180+
181+
} else {
182+
System.out.println(
183+
"Test skipped: JFrame.MAXIMIZED_BOTH resize is " +
184+
"not supported");
185+
}
186+
} finally {
187+
SwingUtilities.invokeAndWait(() -> disposeFrame());
188+
}
189+
}
190+
191+
// Capture button rendering as a BufferedImage
192+
private BufferedImage getButtonImage() {
193+
try {
194+
robot.waitForIdle();
195+
robot.delay(500);
196+
197+
AtomicReference<Point> buttonLocRef = new AtomicReference<>();
198+
SwingUtilities.invokeAndWait(
199+
() -> buttonLocRef.set(button.getLocationOnScreen()));
200+
Point buttonLoc = buttonLocRef.get();
201+
System.out.println("Button loc: " + buttonLoc);
202+
return robot.createScreenCapture(
203+
new Rectangle(buttonLoc.x, buttonLoc.y, button.getWidth(),
204+
button.getHeight()));
205+
} catch (Exception e) {
206+
throw new RuntimeException(
207+
"Problems capturing button image from Robot", e);
208+
}
209+
}
210+
211+
private void disposeFrame() {
212+
if (frame != null) {
213+
frame.dispose();
214+
frame = null;
215+
}
216+
}
217+
218+
// Save BufferedImage to PNG file
219+
private void saveButtonImage(BufferedImage image, File file) {
220+
if (image != null) {
221+
try {
222+
System.out.println(
223+
"Saving button image to " + file.getAbsolutePath());
224+
ImageIO.write(image, "PNG", file);
225+
} catch (Exception e) {
226+
throw new RuntimeException("Could not write image file");
227+
}
228+
} else {
229+
throw new RuntimeException("BufferedImage was set to null");
230+
}
231+
}
232+
233+
private class DiffImage extends BufferedImage {
234+
235+
public boolean diff = false;
236+
public int nDiff = -1;
237+
238+
Color bgColor;
239+
240+
int threshold = 0;
241+
242+
public DiffImage(int w, int h) {
243+
super(w, h, BufferedImage.TYPE_INT_ARGB);
244+
bgColor = Color.LIGHT_GRAY;
245+
}
246+
247+
public int getNumDiffPixels() {
248+
return nDiff;
249+
}
250+
251+
public boolean compare(BufferedImage img1, BufferedImage img2)
252+
throws IOException {
253+
254+
int minx1 = img1.getMinX();
255+
int minx2 = img2.getMinX();
256+
int miny1 = img1.getMinY();
257+
int miny2 = img2.getMinY();
258+
259+
int w1 = img1.getWidth();
260+
int w2 = img2.getWidth();
261+
int h1 = img1.getHeight();
262+
int h2 = img2.getHeight();
263+
264+
if ((minx1 != minx2) || (miny1 != miny2) || (w1 != w2)
265+
|| (h1 != h2)) {
266+
// image sizes are different
267+
throw new RuntimeException(
268+
"img1: <" + minx1 + "," + miny1 + "," + w1 + "x" + h1
269+
+ ">" + " img2: " + minx2 + "," + miny2 + "," + w2 + "x"
270+
+ h2 + ">" + " are different sizes");
271+
}
272+
// Get the actual data behind the images
273+
Raster ras1 = img1.getData();
274+
Raster ras2 = img2.getData();
275+
276+
ColorModel cm1 = img1.getColorModel();
277+
ColorModel cm2 = img2.getColorModel();
278+
279+
int r1, r2; // red
280+
int g1, g2; // green
281+
int b1, b2; // blue
282+
283+
Object o1 = null;
284+
Object o2 = null;
285+
nDiff = 0;
286+
for (int x = minx1; x < (minx1 + w1); x++) {
287+
for (int y = miny1; y < (miny1 + h1); y++) {
288+
// Causes rasters to allocate data
289+
o1 = ras1.getDataElements(x, y, o1);
290+
// and we reuse the data on every loop
291+
o2 = ras2.getDataElements(x, y, o2);
292+
293+
r1 = cm1.getRed(o1);
294+
r2 = cm2.getRed(o2);
295+
g1 = cm1.getGreen(o1);
296+
g2 = cm2.getGreen(o2);
297+
b1 = cm1.getBlue(o1);
298+
b2 = cm2.getBlue(o2);
299+
300+
int redAbs = Math.abs(r1 - r2);
301+
int greenAbs = Math.abs(g1 - g2);
302+
int blueAbs = Math.abs(b1 - b2);
303+
if ((redAbs > threshold)
304+
|| (greenAbs > threshold)
305+
|| (blueAbs > threshold)) {
306+
// pixel is different
307+
setDiffPixel(x, y, redAbs, greenAbs, blueAbs);
308+
nDiff++;
309+
} else {
310+
setSamePixel(x, y);
311+
}
312+
313+
}
314+
}
315+
if (nDiff != 0) {
316+
ImageIO.write(this, "png",
317+
new File("diffImage.png"));
318+
saveButtonImage(img1, new File("image1.png"));
319+
saveButtonImage(img2, new File("image2.png"));
320+
}
321+
return nDiff == 0;
322+
}
323+
324+
void setDiffPixel(int x, int y, int r, int g, int b) {
325+
diff = true;
326+
setPixelValue(x, y, 255, r, g, b);
327+
}
328+
329+
void setSamePixel(int x, int y) {
330+
if (bgColor != null) {
331+
setPixelValue(x, y, 255, bgColor.getRed(),
332+
bgColor.getGreen(),
333+
bgColor.getBlue());
334+
} else {
335+
setPixelValue(x, y, 255, Color.black.getRed(),
336+
Color.black.getGreen(), Color.black.getBlue());
337+
}
338+
}
339+
340+
void setPixelValue(int x, int y, int a, int r, int g, int b) {
341+
// setRGB uses BufferedImage.TYPE_INT_ARGB format
342+
int pixel =
343+
((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8)
344+
+ ((b & 0xff));
345+
setRGB(x, y, pixel);
346+
}
347+
348+
}
349+
350+
}
351+
352+

0 commit comments

Comments
 (0)