From 5914150956b8e5ec75182a46f950ac1d1e4cc46e Mon Sep 17 00:00:00 2001 From: Satyen Subramaniam Date: Tue, 14 Oct 2025 19:46:14 +0000 Subject: [PATCH] Backport 8270cd0ad2e0df72f063f36853328a935595f71f --- test/jdk/ProblemList.txt | 1 + .../Graphics/GDIResourceExhaustionTest.java | 121 ++++++++++ .../awt/Graphics/RepeatedRepaintTest.java | 137 +++++++++++ .../java/awt/Graphics/SmallPrimitives.java | 224 ++++++++++++++++++ test/jdk/java/awt/Graphics/TextAfterXor.java | 123 ++++++++++ 5 files changed, 606 insertions(+) create mode 100644 test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java create mode 100644 test/jdk/java/awt/Graphics/RepeatedRepaintTest.java create mode 100644 test/jdk/java/awt/Graphics/SmallPrimitives.java create mode 100644 test/jdk/java/awt/Graphics/TextAfterXor.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index a642fd35f3f..4df6d489712 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -144,6 +144,7 @@ java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all java/awt/Focus/FocusPolicyTest.java 7160904 linux-all java/awt/event/KeyEvent/CorrectTime/CorrectTime.java 6626492 generic-all +java/awt/Graphics/SmallPrimitives.java 8047070 macosx-all,linux-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java 8024034 generic-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all diff --git a/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java b/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java new file mode 100644 index 00000000000..b8ba155da60 --- /dev/null +++ b/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1999, 2025, 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 javax.imageio.ImageIO; +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4191297 + * @summary Tests that unreferenced GDI resources are correctly + * destroyed when no longer needed. + * @key headful + * @run main GDIResourceExhaustionTest + */ + +public class GDIResourceExhaustionTest extends Frame { + public void initUI() { + setSize(200, 200); + setUndecorated(true); + setLocationRelativeTo(null); + Panel labelPanel = new Panel(); + Label label = new Label("Red label"); + label.setBackground(Color.red); + labelPanel.add(label); + labelPanel.setLocation(20, 50); + add(labelPanel); + setVisible(true); + } + + public void paint(Graphics graphics) { + super.paint(graphics); + for (int rgb = 0; rgb <= 0xfff; rgb++) { + graphics.setColor(new Color(rgb)); + graphics.fillRect(0, 0, 5, 5); + } + } + + public void requestCoordinates(Rectangle r) { + Insets insets = getInsets(); + Point location = getLocationOnScreen(); + Dimension size = getSize(); + r.x = location.x + insets.left; + r.y = location.y + insets.top; + r.width = size.width - (insets.left + insets.right); + r.height = size.height - (insets.top + insets.bottom); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException, IOException { + GDIResourceExhaustionTest test = new GDIResourceExhaustionTest(); + try { + EventQueue.invokeAndWait(test::initUI); + Robot robot = new Robot(); + robot.delay(2000); + Rectangle coords = new Rectangle(); + EventQueue.invokeAndWait(() -> { + test.requestCoordinates(coords); + }); + robot.mouseMove(coords.x - 50, coords.y - 50); + robot.waitForIdle(); + robot.delay(5000); + BufferedImage capture = robot.createScreenCapture(coords); + robot.delay(500); + boolean redFound = false; + int redRGB = Color.red.getRGB(); + for (int y = 0; y < capture.getHeight(); y++) { + for (int x = 0; x < capture.getWidth(); x++) { + if (capture.getRGB(x, y) == redRGB) { + redFound = true; + break; + } + if (redFound) { + break; + } + } + } + if (!redFound) { + File errorImage = new File("screenshot.png"); + ImageIO.write(capture, "png", errorImage); + throw new RuntimeException("Red label is not detected, possibly GDI resources exhausted"); + } + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java b/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java new file mode 100644 index 00000000000..140cb48630d --- /dev/null +++ b/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1998, 2025, 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.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4081126 4129709 + * @summary Test for proper repainting on multiprocessor systems. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RepeatedRepaintTest + */ +public class RepeatedRepaintTest extends Frame { + private Font font = null; + private Image background; + + static String INSTRUCTIONS = """ + The frame next to this window called "AWT Draw Test" has + some elements drawn on it. Move this window partially outside of the + screen bounds and then drag it back. Repeat it couple of times. + Drag the instructions window over the frame partially obscuring it. + If after number of attempts the frame content stops repainting + press "Fail", otherwise press "Pass". + """; + + public RepeatedRepaintTest() { + setTitle("AWT Draw Test"); + setSize(300, 300); + background = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB); + Graphics g = background.getGraphics(); + g.setColor(Color.black); + g.fillRect(0, 0, 300, 300); + g.dispose(); + } + + public void paint(Graphics g) { + Dimension dim = this.getSize(); + super.paint(g); + g.drawImage(background, 0, 0, dim.width, dim.height, null); + g.setColor(Color.white); + if (font == null) { + font = new Font("SansSerif", Font.PLAIN, 24); + } + g.setFont(font); + FontMetrics metrics = g.getFontMetrics(); + String message = "Draw Test"; + g.drawString(message, (dim.width / 2) - (metrics.stringWidth(message) / 2), + (dim.height / 2) + (metrics.getHeight() / 2)); + + int counter = 50; + for (int i = 0; i < 50; i++) { + counter += 4; + g.drawOval(counter, 50, i, i); + } + + counter = 20; + for (int i = 0; i < 100; i++) { + counter += 4; + g.drawOval(counter, 150, i, i); + } + g.setColor(Color.black); + g.drawLine(0, dim.height - 25, dim.width, dim.height - 25); + g.setColor(Color.gray); + g.drawLine(0, dim.height - 24, dim.width, dim.height - 24); + g.setColor(Color.lightGray); + g.drawLine(0, dim.height - 23, dim.width, dim.height - 23); + g.fillRect(0, dim.height - 22, dim.width, dim.height); + + + g.setXORMode(Color.blue); + g.fillRect(0, 0, 25, dim.height - 26); + g.setColor(Color.red); + g.fillRect(0, 0, 25, dim.height - 26); + g.setColor(Color.green); + g.fillRect(0, 0, 25, dim.height - 26); + g.setPaintMode(); + + Image img = createImage(50, 50); + Graphics imgGraphics = img.getGraphics(); + imgGraphics.setColor(Color.magenta); + imgGraphics.fillRect(0, 0, 50, 50); + imgGraphics.setColor(Color.yellow); + imgGraphics.drawString("offscreen", 0, 20); + imgGraphics.drawString("image", 0, 30); + + g.drawImage(img, dim.width - 100, dim.height - 100, Color.blue, null); + + g.setXORMode(Color.white); + drawAt(g, 100, 100, 50, 50); + drawAt(g, 105, 105, 50, 50); + drawAt(g, 110, 110, 50, 50); + } + + public void drawAt(Graphics g, int x, int y, int width, int height) { + g.setColor(Color.magenta); + g.fillRect(x, y, width, height); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repeated Repaint Test Instructions") + .instructions(INSTRUCTIONS) + .testUI(RepeatedRepaintTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Graphics/SmallPrimitives.java b/test/jdk/java/awt/Graphics/SmallPrimitives.java new file mode 100644 index 00000000000..7eb267cf0b9 --- /dev/null +++ b/test/jdk/java/awt/Graphics/SmallPrimitives.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2002, 2025, 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.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Polygon; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4411814 4298688 4205762 4524760 4067534 + * @summary Check that Graphics rendering primitives function + * correctly when fed small and degenerate shapes + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SmallPrimitives + */ + + +public class SmallPrimitives extends Panel { + + static String INSTRUCTIONS = """ + In the borderless frame next to this window there should be a + set of tiny narrow blue polygons painted next to the green rectangles. + If rectangle is vertical the corresponding polygon is painted to the right of it, + if rectangle is horizontal the polygon is painted below it. + The length of the polygon should be roughly the same as the length of the + green rectangle next to it. If size is significantly different or any of the + polygons is not painted press "Fail" otherwise press "Pass". + Note: one may consider using screen magnifier to compare sizes. + """; + + public void paint(Graphics g) { + Dimension d = getSize(); + Polygon p; + GeneralPath gp; + + g.setColor(Color.white); + g.fillRect(0, 0, d.width, d.height); + + // Reposition for horizontal tests (below) + g.translate(0, 20); + + // Reference shapes + g.setColor(Color.green); + g.fillRect(10, 7, 11, 1); + g.fillRect(10, 17, 11, 2); + g.fillRect(10, 27, 11, 1); + g.fillRect(10, 37, 11, 1); + g.fillRect(10, 47, 11, 2); + g.fillRect(10, 57, 11, 2); + g.fillRect(10, 67, 11, 1); + g.fillRect(10, 77, 11, 2); + g.fillRect(10, 87, 11, 1); + g.fillRect(10, 97, 11, 1); + g.fillRect(10, 107, 11, 1); + g.fillRect(10, 117, 6, 1); g.fillRect(20, 117, 6, 1); + + // Potentially problematic test shapes + g.setColor(Color.blue); + g.drawRect(10, 10, 10, 0); + g.drawRect(10, 20, 10, 1); + g.drawRoundRect(10, 30, 10, 0, 0, 0); + g.drawRoundRect(10, 40, 10, 0, 4, 4); + g.drawRoundRect(10, 50, 10, 1, 0, 0); + g.drawRoundRect(10, 60, 10, 1, 4, 4); + g.drawOval(10, 70, 10, 0); + g.drawOval(10, 80, 10, 1); + p = new Polygon(); + p.addPoint(10, 90); + p.addPoint(20, 90); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + p = new Polygon(); + p.addPoint(10, 100); + p.addPoint(20, 100); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + ((Graphics2D) g).draw(new Line2D.Double(10, 110, 20, 110)); + gp = new GeneralPath(); + gp.moveTo(10, 120); + gp.lineTo(15, 120); + gp.moveTo(20, 120); + gp.lineTo(25, 120); + ((Graphics2D) g).draw(gp); + + // Polygon limit tests + p = new Polygon(); + trypoly(g, p); + p.addPoint(10, 120); + trypoly(g, p); + + // Reposition for vertical tests (below) + g.translate(20, -20); + + // Reference shapes + g.setColor(Color.green); + g.fillRect(7, 10, 1, 11); + g.fillRect(17, 10, 2, 11); + g.fillRect(27, 10, 1, 11); + g.fillRect(37, 10, 1, 11); + g.fillRect(47, 10, 2, 11); + g.fillRect(57, 10, 2, 11); + g.fillRect(67, 10, 1, 11); + g.fillRect(77, 10, 2, 11); + g.fillRect(87, 10, 1, 11); + g.fillRect(97, 10, 1, 11); + g.fillRect(107, 10, 1, 11); + g.fillRect(117, 10, 1, 6); g.fillRect(117, 20, 1, 6); + + // Potentially problematic test shapes + g.setColor(Color.blue); + g.drawRect(10, 10, 0, 10); + g.drawRect(20, 10, 1, 10); + g.drawRoundRect(30, 10, 0, 10, 0, 0); + g.drawRoundRect(40, 10, 0, 10, 4, 4); + g.drawRoundRect(50, 10, 1, 10, 0, 0); + g.drawRoundRect(60, 10, 1, 10, 4, 4); + g.drawOval(70, 10, 0, 10); + g.drawOval(80, 10, 1, 10); + p = new Polygon(); + p.addPoint(90, 10); + p.addPoint(90, 20); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + p = new Polygon(); + p.addPoint(100, 10); + p.addPoint(100, 20); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + ((Graphics2D) g).draw(new Line2D.Double(110, 10, 110, 20)); + gp = new GeneralPath(); + gp.moveTo(120, 10); + gp.lineTo(120, 15); + gp.moveTo(120, 20); + gp.lineTo(120, 25); + ((Graphics2D) g).draw(gp); + + // Polygon limit tests + p = new Polygon(); + trypoly(g, p); + p.addPoint(110, 10); + trypoly(g, p); + + // Reposition for oval tests + g.translate(0, 20); + + for (int i = 0, xy = 8; i < 11; i++) { + g.setColor(Color.green); + g.fillRect(xy, 5, i, 1); + g.fillRect(5, xy, 1, i); + g.setColor(Color.blue); + g.fillOval(xy, 8, i, 1); + g.fillOval(8, xy, 1, i); + xy += i + 2; + } + + g.translate(10, 10); + for (int i = 0, xy = 9; i < 6; i++) { + g.setColor(Color.green); + g.fillRect(xy, 5, i, 2); + g.fillRect(5, xy, 2, i); + g.setColor(Color.blue); + g.fillOval(xy, 8, i, 2); + g.fillOval(8, xy, 2, i); + xy += i + 2; + } + } + + public static void trypoly(Graphics g, Polygon p) { + g.drawPolygon(p); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + g.fillPolygon(p); + g.fillPolygon(p.xpoints, p.ypoints, p.npoints); + } + + public Dimension getPreferredSize() { + return new Dimension(150, 150); + } + + public static Frame createFrame() { + Frame f = new Frame(); + SmallPrimitives sp = new SmallPrimitives(); + sp.setLocation(0, 0); + f.add(sp); + f.setUndecorated(true); + f.pack(); + return f; + } + + public static void main(String argv[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Small Primitives Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(SmallPrimitives::createFrame) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Graphics/TextAfterXor.java b/test/jdk/java/awt/Graphics/TextAfterXor.java new file mode 100644 index 00000000000..c9dc56d8b80 --- /dev/null +++ b/test/jdk/java/awt/Graphics/TextAfterXor.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002, 2025, 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.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.image.VolatileImage; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4505650 + * @summary Check that you can render solid text after doing XOR mode + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAfterXor + */ + +public class TextAfterXor extends Panel { + public static final int TESTW = 300; + public static final int TESTH = 100; + static String INSTRUCTIONS = """ + In the window called "Text After XOR Test" there should be two + composite components, at the bottom of each component the green text + "Test passes if this is green!" should be visible. + + On the top component this text should be green on all platforms. + On the bottom component it is possible that on non-Windows + platforms text can be of other color or not visible at all. + That does not constitute a problem. + + So if platform is Windows and green text appears twice or on any + other platform green text appears at least once press "Pass", + otherwise press "Fail". + """; + + VolatileImage vimg; + + public void paint(Graphics g) { + render(g); + g.drawString("(Drawing to screen)", 10, 60); + if (vimg == null) { + vimg = createVolatileImage(TESTW, TESTH); + } + do { + vimg.validate(null); + Graphics g2 = vimg.getGraphics(); + render(g2); + String not = vimg.getCapabilities().isAccelerated() ? "" : "not "; + g2.drawString("Image was " + not + "accelerated", 10, 55); + g2.drawString("(only matters on Windows)", 10, 65); + g2.dispose(); + g.drawImage(vimg, 0, TESTH, null); + } while (vimg.contentsLost()); + } + + public void render(Graphics g) { + g.setColor(Color.black); + g.fillRect(0, 0, TESTW, TESTH); + g.setColor(Color.white); + g.fillRect(5, 5, TESTW-10, TESTH-10); + + g.setColor(Color.black); + g.drawString("Test only passes if green string appears", 10, 20); + + g.setColor(Color.white); + g.setXORMode(Color.blue); + g.drawRect(30, 30, 10, 10); + g.setPaintMode(); + g.setColor(Color.green); + + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.drawString("Test passes if this is green!", 10, 80); + + g.setColor(Color.black); + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH*2); + } + + public static Frame createFrame() { + Frame f = new Frame("Text After XOR Test"); + f.add(new TextAfterXor()); + f.pack(); + return f; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Text After XOR Instructions") + .instructions(INSTRUCTIONS) + .testUI(TextAfterXor::createFrame) + .build() + .awaitAndCheck(); + } +}