8338103: Stabilize and open source a Swing OGL ButtonResizeTest
Reviewed-by: abhiscxk, prr, tr
This commit is contained in:
parent
0c2b175898
commit
3d49fb8a17
@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Robot;
|
||||||
|
import java.awt.event.FocusAdapter;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.ColorModel;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8338103
|
||||||
|
* @key headful
|
||||||
|
* @summary Verifies that the OpenGL pipeline does not create artifacts
|
||||||
|
* with swing components after window is zoomed to maximum size and then
|
||||||
|
* resized back to normal. The test case simulates this operation using
|
||||||
|
* a JButton. A file image of the component will be saved before and after
|
||||||
|
* the window resize if the test fails. The test passes if both the button
|
||||||
|
* images are the same.
|
||||||
|
* @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=false SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=true SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm -Dsun.java2d.opengl=false SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm SwingButtonResizeTestWithOpenGL
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @key headful
|
||||||
|
* @requires (os.family == "windows")
|
||||||
|
* @run main/othervm -Dsun.java2d.d3d=false SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm -Dsun.java2d.d3d=true SwingButtonResizeTestWithOpenGL
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @key headful
|
||||||
|
* @requires (os.family == "linux")
|
||||||
|
* @run main/othervm -Dsun.java2d.xrender=false SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm -Dsun.java2d.xrender=true SwingButtonResizeTestWithOpenGL
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @key headful
|
||||||
|
* @requires (os.family == "mac")
|
||||||
|
* @run main/othervm -Dsun.java2d.metal=false SwingButtonResizeTestWithOpenGL
|
||||||
|
* @run main/othervm -Dsun.java2d.metal=true SwingButtonResizeTestWithOpenGL
|
||||||
|
*/
|
||||||
|
public class SwingButtonResizeTestWithOpenGL {
|
||||||
|
private static Robot robot;
|
||||||
|
private static CountDownLatch focusGainedLatch;
|
||||||
|
private JFrame frame;
|
||||||
|
private JButton button;
|
||||||
|
|
||||||
|
public SwingButtonResizeTestWithOpenGL() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
SwingUtilities.invokeAndWait(() -> createGUI());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Problems creating GUI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGUI() {
|
||||||
|
frame = new JFrame("SwingButtonResizeTestWithOpenGL");
|
||||||
|
button = new JButton("Button A");
|
||||||
|
frame.setLocation(200, 200);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
button.setPreferredSize(new Dimension(300, 300));
|
||||||
|
button.addFocusListener(new FocusAdapter() {
|
||||||
|
public void focusGained(FocusEvent fe) {
|
||||||
|
focusGainedLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frame.getContentPane().setLayout(new FlowLayout());
|
||||||
|
frame.getContentPane().add(button);
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.toFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
focusGainedLatch = new CountDownLatch(1);
|
||||||
|
SwingButtonResizeTestWithOpenGL test =
|
||||||
|
new SwingButtonResizeTestWithOpenGL();
|
||||||
|
test.runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
BufferedImage bimage1;
|
||||||
|
BufferedImage bimage2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
robot = new Robot();
|
||||||
|
robot.setAutoWaitForIdle(true);
|
||||||
|
robot.setAutoDelay(200);
|
||||||
|
|
||||||
|
if (focusGainedLatch.await(3, TimeUnit.SECONDS)) {
|
||||||
|
System.out.println("Button focus gained...");
|
||||||
|
} else {
|
||||||
|
System.out.println("Button focus not gained...");
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Can't gain focus on button even after waiting " +
|
||||||
|
"too long..");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Getting initial button image..image1");
|
||||||
|
bimage1 = getButtonImage();
|
||||||
|
|
||||||
|
// some platforms may not support maximize frame
|
||||||
|
if (frame.getToolkit().isFrameStateSupported(
|
||||||
|
JFrame.MAXIMIZED_BOTH)) {
|
||||||
|
robot.waitForIdle();
|
||||||
|
// maximize frame from normal size
|
||||||
|
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||||
|
System.out.println("Frame is maximized");
|
||||||
|
robot.waitForIdle();
|
||||||
|
|
||||||
|
if (frame.getToolkit().isFrameStateSupported(JFrame.NORMAL)) {
|
||||||
|
System.out.println("Frame is back to normal");
|
||||||
|
// resize from maximum size to normal
|
||||||
|
frame.setExtendedState(JFrame.NORMAL);
|
||||||
|
|
||||||
|
// capture image of JButton after resize
|
||||||
|
System.out.println(
|
||||||
|
"Getting image of JButton after resize..image2");
|
||||||
|
bimage2 = getButtonImage();
|
||||||
|
|
||||||
|
// compare button images from before and after frame resize
|
||||||
|
DiffImage di = new DiffImage(bimage1.getWidth(),
|
||||||
|
bimage1.getHeight());
|
||||||
|
System.out.println(
|
||||||
|
"Taking the diff of two images, image1 and image2");
|
||||||
|
if (!di.compare(bimage1, bimage2)) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Button renderings are different after window "
|
||||||
|
+ "resize, num of Diff Pixels="
|
||||||
|
+ di.getNumDiffPixels());
|
||||||
|
} else {
|
||||||
|
System.out.println("Test passed...");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
System.out.println(
|
||||||
|
"Test skipped: JFrame.NORMAL resize is " +
|
||||||
|
"not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
System.out.println(
|
||||||
|
"Test skipped: JFrame.MAXIMIZED_BOTH resize is " +
|
||||||
|
"not supported");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
SwingUtilities.invokeAndWait(() -> disposeFrame());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture button rendering as a BufferedImage
|
||||||
|
private BufferedImage getButtonImage() {
|
||||||
|
try {
|
||||||
|
robot.waitForIdle();
|
||||||
|
robot.delay(500);
|
||||||
|
|
||||||
|
AtomicReference<Point> buttonLocRef = new AtomicReference<>();
|
||||||
|
SwingUtilities.invokeAndWait(
|
||||||
|
() -> buttonLocRef.set(button.getLocationOnScreen()));
|
||||||
|
Point buttonLoc = buttonLocRef.get();
|
||||||
|
System.out.println("Button loc: " + buttonLoc);
|
||||||
|
return robot.createScreenCapture(
|
||||||
|
new Rectangle(buttonLoc.x, buttonLoc.y, button.getWidth(),
|
||||||
|
button.getHeight()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Problems capturing button image from Robot", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeFrame() {
|
||||||
|
if (frame != null) {
|
||||||
|
frame.dispose();
|
||||||
|
frame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save BufferedImage to PNG file
|
||||||
|
private void saveButtonImage(BufferedImage image, File file) {
|
||||||
|
if (image != null) {
|
||||||
|
try {
|
||||||
|
System.out.println(
|
||||||
|
"Saving button image to " + file.getAbsolutePath());
|
||||||
|
ImageIO.write(image, "PNG", file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Could not write image file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("BufferedImage was set to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DiffImage extends BufferedImage {
|
||||||
|
|
||||||
|
public boolean diff = false;
|
||||||
|
public int nDiff = -1;
|
||||||
|
|
||||||
|
Color bgColor;
|
||||||
|
|
||||||
|
int threshold = 0;
|
||||||
|
|
||||||
|
public DiffImage(int w, int h) {
|
||||||
|
super(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
bgColor = Color.LIGHT_GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumDiffPixels() {
|
||||||
|
return nDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean compare(BufferedImage img1, BufferedImage img2)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
int minx1 = img1.getMinX();
|
||||||
|
int minx2 = img2.getMinX();
|
||||||
|
int miny1 = img1.getMinY();
|
||||||
|
int miny2 = img2.getMinY();
|
||||||
|
|
||||||
|
int w1 = img1.getWidth();
|
||||||
|
int w2 = img2.getWidth();
|
||||||
|
int h1 = img1.getHeight();
|
||||||
|
int h2 = img2.getHeight();
|
||||||
|
|
||||||
|
if ((minx1 != minx2) || (miny1 != miny2) || (w1 != w2)
|
||||||
|
|| (h1 != h2)) {
|
||||||
|
// image sizes are different
|
||||||
|
throw new RuntimeException(
|
||||||
|
"img1: <" + minx1 + "," + miny1 + "," + w1 + "x" + h1
|
||||||
|
+ ">" + " img2: " + minx2 + "," + miny2 + "," + w2 + "x"
|
||||||
|
+ h2 + ">" + " are different sizes");
|
||||||
|
}
|
||||||
|
// Get the actual data behind the images
|
||||||
|
Raster ras1 = img1.getData();
|
||||||
|
Raster ras2 = img2.getData();
|
||||||
|
|
||||||
|
ColorModel cm1 = img1.getColorModel();
|
||||||
|
ColorModel cm2 = img2.getColorModel();
|
||||||
|
|
||||||
|
int r1, r2; // red
|
||||||
|
int g1, g2; // green
|
||||||
|
int b1, b2; // blue
|
||||||
|
|
||||||
|
Object o1 = null;
|
||||||
|
Object o2 = null;
|
||||||
|
nDiff = 0;
|
||||||
|
for (int x = minx1; x < (minx1 + w1); x++) {
|
||||||
|
for (int y = miny1; y < (miny1 + h1); y++) {
|
||||||
|
// Causes rasters to allocate data
|
||||||
|
o1 = ras1.getDataElements(x, y, o1);
|
||||||
|
// and we reuse the data on every loop
|
||||||
|
o2 = ras2.getDataElements(x, y, o2);
|
||||||
|
|
||||||
|
r1 = cm1.getRed(o1);
|
||||||
|
r2 = cm2.getRed(o2);
|
||||||
|
g1 = cm1.getGreen(o1);
|
||||||
|
g2 = cm2.getGreen(o2);
|
||||||
|
b1 = cm1.getBlue(o1);
|
||||||
|
b2 = cm2.getBlue(o2);
|
||||||
|
|
||||||
|
int redAbs = Math.abs(r1 - r2);
|
||||||
|
int greenAbs = Math.abs(g1 - g2);
|
||||||
|
int blueAbs = Math.abs(b1 - b2);
|
||||||
|
if ((redAbs > threshold)
|
||||||
|
|| (greenAbs > threshold)
|
||||||
|
|| (blueAbs > threshold)) {
|
||||||
|
// pixel is different
|
||||||
|
setDiffPixel(x, y, redAbs, greenAbs, blueAbs);
|
||||||
|
nDiff++;
|
||||||
|
} else {
|
||||||
|
setSamePixel(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nDiff != 0) {
|
||||||
|
ImageIO.write(this, "png",
|
||||||
|
new File("diffImage.png"));
|
||||||
|
saveButtonImage(img1, new File("image1.png"));
|
||||||
|
saveButtonImage(img2, new File("image2.png"));
|
||||||
|
}
|
||||||
|
return nDiff == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDiffPixel(int x, int y, int r, int g, int b) {
|
||||||
|
diff = true;
|
||||||
|
setPixelValue(x, y, 255, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamePixel(int x, int y) {
|
||||||
|
if (bgColor != null) {
|
||||||
|
setPixelValue(x, y, 255, bgColor.getRed(),
|
||||||
|
bgColor.getGreen(),
|
||||||
|
bgColor.getBlue());
|
||||||
|
} else {
|
||||||
|
setPixelValue(x, y, 255, Color.black.getRed(),
|
||||||
|
Color.black.getGreen(), Color.black.getBlue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPixelValue(int x, int y, int a, int r, int g, int b) {
|
||||||
|
// setRGB uses BufferedImage.TYPE_INT_ARGB format
|
||||||
|
int pixel =
|
||||||
|
((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8)
|
||||||
|
+ ((b & 0xff));
|
||||||
|
setRGB(x, y, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user