diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index b23d94ea6e8..e8ad37bf33c 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1705,7 +1705,7 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n // pre-loop, the main-loop may not execute at all. Later in life this // zero-trip guard will become the minimum-trip guard when we unroll // the main-loop. - Node *min_opaq = new OpaqueZeroTripGuardNode(C, limit); + Node *min_opaq = new OpaqueZeroTripGuardNode(C, limit, b_test); Node *min_cmp = new CmpINode(pre_incr, min_opaq); Node *min_bol = new BoolNode(min_cmp, b_test); register_new_node(min_opaq, new_pre_exit); @@ -1994,7 +1994,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, // (the previous loop trip-counter exit value) because we will be changing // the exit value (via additional unrolling) so we cannot constant-fold away the zero // trip guard until all unrolling is done. - Node *zer_opaq = new OpaqueZeroTripGuardNode(C, incr); + Node *zer_opaq = new OpaqueZeroTripGuardNode(C, incr, main_end->test_trip()); Node *zer_cmp = new CmpINode(zer_opaq, limit); Node *zer_bol = new BoolNode(zer_cmp, main_end->test_trip()); register_new_node(zer_opaq, new_main_exit); diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 2fb57d51187..a5722a705f5 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -27,6 +27,7 @@ #include "opto/node.hpp" #include "opto/opcodes.hpp" +#include "subnode.hpp" //------------------------------Opaque1Node------------------------------------ // A node to prevent unwanted optimizations. Allows constant folding. @@ -72,9 +73,16 @@ class OpaqueLoopStrideNode : public Opaque1Node { class OpaqueZeroTripGuardNode : public Opaque1Node { public: - OpaqueZeroTripGuardNode(Compile* C, Node *n) : Opaque1Node(C, n) { + // This captures the test that returns true when the loop is entered. It depends on whether the loop goes up or down. + // This is used by CmpINode::Value. + BoolTest::mask _loop_entered_mask; + OpaqueZeroTripGuardNode(Compile* C, Node* n, BoolTest::mask loop_entered_test) : + Opaque1Node(C, n), _loop_entered_mask(loop_entered_test) { } virtual int Opcode() const; + virtual uint size_of() const { + return sizeof(*this); + } }; //------------------------------Opaque3Node------------------------------------ diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 2c260ebf4f9..93ff6e81e35 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1683,6 +1683,13 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { } } } + if (use->Opcode() == Op_OpaqueZeroTripGuard) { + assert(use->outcnt() <= 1, "OpaqueZeroTripGuard can't be shared"); + if (use->outcnt() == 1) { + Node* cmp = use->unique_out(); + _worklist.push(cmp); + } + } } } @@ -1901,6 +1908,7 @@ void PhaseCCP::push_more_uses(Unique_Node_List& worklist, Node* parent, const No push_loadp(worklist, use); push_and(worklist, parent, use); push_cast_ii(worklist, parent, use); + push_opaque_zero_trip_guard(worklist, use); } @@ -2021,6 +2029,12 @@ void PhaseCCP::push_cast_ii(Unique_Node_List& worklist, const Node* parent, cons } } +void PhaseCCP::push_opaque_zero_trip_guard(Unique_Node_List& worklist, const Node* use) const { + if (use->Opcode() == Op_OpaqueZeroTripGuard) { + push_if_not_bottom_type(worklist, use->unique_out()); + } +} + //------------------------------do_transform----------------------------------- // Top level driver for the recursive transformer void PhaseCCP::do_transform() { diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 883dc92e7ef..dc5847b4845 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -596,6 +596,7 @@ class PhaseCCP : public PhaseIterGVN { static void push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2* barrier_set, const Node* use); void push_and(Unique_Node_List& worklist, const Node* parent, const Node* use) const; void push_cast_ii(Unique_Node_List& worklist, const Node* parent, const Node* use) const; + void push_opaque_zero_trip_guard(Unique_Node_List& worklist, const Node* use) const; public: PhaseCCP( PhaseIterGVN *igvn ); // Compute conditional constants diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index a1795dbf3da..71c6368e48c 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -34,6 +34,7 @@ #include "opto/matcher.hpp" #include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" @@ -661,6 +662,47 @@ const Type *CmpINode::sub( const Type *t1, const Type *t2 ) const { return TypeInt::CC; // else use worst case results } +const Type* CmpINode::Value(PhaseGVN* phase) const { + Node* in1 = in(1); + Node* in2 = in(2); + // If this test is the zero trip guard for a main or post loop, check whether, with the opaque node removed, the test + // would constant fold so the loop is never entered. If so return the type of the test without the opaque node removed: + // make the loop unreachable. + // The reason for this is that the iv phi captures the bounds of the loop and if the loop becomes unreachable, it can + // become top. In that case, the loop must be removed. + // This is safe because: + // - as optimizations proceed, the range of iterations executed by the main loop narrows. If no iterations remain, then + // we're done with optimizations for that loop. + // - the post loop is initially not reachable but as long as there's a main loop, the zero trip guard for the post + // loop takes a phi that merges the pre and main loop's iv and can't constant fold the zero trip guard. Once, the main + // loop is removed, there's no need to preserve the zero trip guard for the post loop anymore. + if (in1 != NULL && in2 != NULL) { + uint input = 0; + Node* cmp = NULL; + BoolTest::mask test; + if (in1->Opcode() == Op_OpaqueZeroTripGuard && phase->type(in1) != Type::TOP) { + cmp = new CmpINode(in1->in(1), in2); + test = ((OpaqueZeroTripGuardNode*)in1)->_loop_entered_mask; + } + if (in2->Opcode() == Op_OpaqueZeroTripGuard && phase->type(in2) != Type::TOP) { + assert(cmp == NULL, "A cmp with 2 OpaqueZeroTripGuard inputs"); + cmp = new CmpINode(in1, in2->in(1)); + test = ((OpaqueZeroTripGuardNode*)in2)->_loop_entered_mask; + } + if (cmp != NULL) { + const Type* cmp_t = cmp->Value(phase); + const Type* t = BoolTest(test).cc2logical(cmp_t); + cmp->destruct(phase); + if (t == TypeInt::ZERO) { + return cmp_t; + } + } + } + + return SubNode::Value(phase); +} + + // Simplify a CmpU (compare 2 integers) node, based on local information. // If both inputs are constants, compare them. const Type *CmpUNode::sub( const Type *t1, const Type *t2 ) const { diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index cddb23e0737..8a7bd72b170 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -153,6 +153,7 @@ public: virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *sub( const Type *, const Type * ) const; + virtual const Type* Value(PhaseGVN* phase) const; }; //------------------------------CmpUNode--------------------------------------- diff --git a/src/java.base/share/classes/java/security/DrbgParameters.java b/src/java.base/share/classes/java/security/DrbgParameters.java index 7ceb81ed371..ecf8d50aab1 100644 --- a/src/java.base/share/classes/java/security/DrbgParameters.java +++ b/src/java.base/share/classes/java/security/DrbgParameters.java @@ -34,7 +34,7 @@ import java.util.Objects; * Random Bit Generator). *
* According to - * + * * NIST Special Publication 800-90A Revision 1, Recommendation for Random * Number Generation Using Deterministic Random Bit Generators (800-90Ar1), *
diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index 14f1f35d4ac..dcfe5080730 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -43,7 +43,7 @@ import java.util.regex.Pattern; * *A cryptographically strong random number minimally complies with the * statistical random number generator tests specified in - * + * * FIPS 140-2, Security Requirements for Cryptographic Modules, * section 4.9.1. * Additionally, {@code SecureRandom} must produce non-deterministic output. diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java index ff4d37224e3..c96811202d7 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -366,6 +366,8 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou } } + private int savedBlinkRate = 0; + private boolean isBlinkRateSaved = false; // --- FocusListener methods -------------------------- /** @@ -379,8 +381,21 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou public void focusGained(FocusEvent e) { if (component.isEnabled()) { if (component.isEditable()) { - setVisible(true); + if (isBlinkRateSaved) { + setBlinkRate(savedBlinkRate); + savedBlinkRate = 0; + isBlinkRateSaved = false; + } + } else { + if (getBlinkRate() != 0) { + if (!isBlinkRateSaved) { + savedBlinkRate = getBlinkRate(); + isBlinkRateSaved = true; + } + setBlinkRate(0); + } } + setVisible(true); setSelectionVisible(true); updateSystemSelection(); } @@ -1031,17 +1046,29 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou * @see Caret#setBlinkRate */ public void setBlinkRate(int rate) { + if (rate < 0) { + throw new IllegalArgumentException("Invalid blink rate: " + rate); + } if (rate != 0) { - if (flasher == null) { - flasher = new Timer(rate, handler); + if (component.isEditable()) { + if (flasher == null) { + flasher = new Timer(rate, handler); + } + flasher.setDelay(rate); + } else { + savedBlinkRate = rate; + isBlinkRateSaved = true; } - flasher.setDelay(rate); } else { if (flasher != null) { flasher.stop(); flasher.removeActionListener(handler); flasher = null; } + if (component.isEditable() && isBlinkRateSaved) { + savedBlinkRate = 0; + isBlinkRateSaved = false; + } } } @@ -1053,6 +1080,9 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou * @see Caret#getBlinkRate */ public int getBlinkRate() { + if (isBlinkRateSaved) { + return savedBlinkRate; + } return (flasher == null) ? 0 : flasher.getDelay(); } diff --git a/test/hotspot/jtreg/compiler/loopopts/TestOpaqueZeroTripGuardPostLoopRemoval.java b/test/hotspot/jtreg/compiler/loopopts/TestOpaqueZeroTripGuardPostLoopRemoval.java new file mode 100644 index 00000000000..629a688ce43 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestOpaqueZeroTripGuardPostLoopRemoval.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8298176 + * @summary Must remove OpaqueZeroTripGuardPostLoop after main loop disappears else + * the zero-trip-guard of the post loop cannot die and leaves an inconsistent + * graph behind. + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,TestOpaqueZeroTripGuardPostLoopRemoval::test* + * -XX:CompileCommand=dontinline,TestOpaqueZeroTripGuardPostLoopRemoval::* + * TestOpaqueZeroTripGuardPostLoopRemoval + */ + +public class TestOpaqueZeroTripGuardPostLoopRemoval { + static long x; + + public static void main(String[] strArr) { + test_001(); + test_002(); + try { + test_003(); + } catch (Exception e) { + // Expected + } + test_004(); + test_005(); + } + + static void test_001() { + int b = 6; + for (long l = 1; l < 9; l++) { + b++; + } + for (int i = 1; i < 1000; i*=2) { + for (int j = 1; j < 2; j++) { + x = b + 1; + } + } + } + + static void test_002() { + int b = 6; + for (long l = 60; l < 3000; l+=3) { + // bounds of loop: no work for post loop + b += 33; // any multiple of iv step + } + for (int i = 1; i < 1000; i*=2) { + for (int j = 1; j < 2; j++) { + x = b + 1; + } + } + } + + static void dontInline() { + throw new RuntimeException(); + } + + static int test_003() { + int y = 3; + for (int i = 0; i < 9; ) { + for (long l = 1; l < 5; l++) { + y *= 2; + } + while (true) { + dontInline(); + } + } + return y; + } + + static void test_004() { + for (int i2 = 4; i2 < 13; i2++) { + double d = 56; + for (long l = 1; l < 5; l++) { + d = d + 3; + } + for (int i = 0; i < 10; i++) { + for (int d2 = i2; d2 < 2; d2 = 3) { + } + } + } + } + + public static int test_005() { + long arr[]=new long[400]; + for (int i = 3; i < 177; i++) { + for (int j = 0; j < 10; j++){} + } + int y = 0; + for (int i = 15; i < 356; i++) { + // Inner loop prevents strip-mining of outer loop + // later, inner loop is removed, so outer does pre-main-post without strip-mining + for (int j = 0; j < 10; j++){ + y |= 1; + } + } + return y; + } +} + diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 83ab2d698a7..4dffcc4ef18 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -659,8 +659,6 @@ javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all -javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java 8194048 windows-all -javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java 8213562 linux-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-all diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 780612f48aa..b4e13624d24 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -126,6 +126,7 @@ jdk_util = \ jdk_util_other = \ java/util \ sun/util \ + jdk/internal/util \ -:jdk_collections \ -:jdk_concurrent \ -:jdk_stream diff --git a/test/jdk/java/awt/Graphics2D/DrawPrimitivesTest.java b/test/jdk/java/awt/Graphics2D/DrawPrimitivesTest.java new file mode 100644 index 00000000000..55baf940f87 --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/DrawPrimitivesTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, JetBrains s.r.o.. 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. + */ + +/** + * @test + * @key headful + * @bug 8287600 8291266 8299207 + * @requires os.family == "mac" + * @summary [macosx] Some primitives do not render in metal pipeline + * @run main DrawPrimitivesTest + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public abstract class DrawPrimitivesTest extends JFrame { + private final static int W = 800; + private final static int H = 800; + private final static Color[] color = { Color.RED, Color.BLUE, Color.GREEN}; + private final static int COLOR_TOLERANCE = 10; + private final CountDownLatch latchRender = new CountDownLatch(1); + private volatile int frameX0 = 0; + private volatile int frameY0 = 0; + private final String name; + + + private static boolean isAlmostEqual(Color c1, Color c2) { + return Math.abs(c1.getRed() - c2.getRed()) < COLOR_TOLERANCE && + Math.abs(c1.getGreen() - c2.getGreen()) < COLOR_TOLERANCE && + Math.abs(c1.getBlue() - c2.getBlue()) < COLOR_TOLERANCE; + + } + + public static void main(String[] args) throws InterruptedException, AWTException, InvocationTargetException { + new DrawPrimitivesTest("drawLine") { + public void renderPrimitive(Graphics2D g2d, int x0, int y0, int w, int h) { + g2d.drawLine(x0, y0, x0+w, y0+h); + } + }.runTest(); + + new DrawPrimitivesTest("fillRect") { + public void renderPrimitive(Graphics2D g2d, int x0, int y0, int w, int h) { + g2d.fillRect(x0, y0, w, h); + } + }.runTest(); + + new DrawPrimitivesTest("fillOvalAA") { + public void renderPrimitive(Graphics2D g2d, int x0, int y0, int w, int h) { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.fillOval(x0, y0, w, h); + } + }.runTest(); + } + + public abstract void renderPrimitive(Graphics2D g2d, int x0, int y0, int w, int h); + + public DrawPrimitivesTest(String name) { + super(); + this.name = name; + } + + public void runTest() throws InterruptedException, InvocationTargetException, AWTException { + SwingUtilities.invokeLater(() -> { + add(new JPanel() { + @Override + public Dimension getPreferredSize() { + return new Dimension(W, H); + } + + @Override + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setColor(Color.YELLOW); + int c = 0; + for (int i = 0; i < W; i += 10) { + for (int j = 0; j < H; j += 10) { + c = (c + 1) % color.length; + g2d.setColor(color[c]); + renderPrimitive(g2d, i, j, 10, 10); + } + } + Point p = getLocationOnScreen(); + frameX0 = p.x; + frameY0 = p.y - getInsets().top; + + latchRender.countDown(); + } + }); + setPreferredSize(new Dimension(W, H)); + pack(); + setVisible(true); + }); + + latchRender.await(); + Thread.sleep(1000); + + Robot robot = new Robot(); + + boolean hasEmptyContent = true; + l:for (int i = frameX0 + W/3; i < frameX0 + (2*W)/3; i++) { + for (int j = 0; j < 10; j += 2) { + if (isAlmostEqual(robot.getPixelColor(i, frameY0 + H / 2 + j), Color.RED)) { + hasEmptyContent = false; + break l; + } + } + } + + SwingUtilities.invokeAndWait(() -> { + setVisible(false); + dispose(); + }); + + if (hasEmptyContent) { + throw new RuntimeException(name + ": Empty content"); + } + } +} diff --git a/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java index 6b2331f390d..a0a7269b205 100644 --- a/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java +++ b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -21,10 +21,17 @@ * questions. */ -import javax.swing.*; -import java.awt.*; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTextField; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; import java.awt.event.InputEvent; -import java.awt.image.BufferedImage; /** * @test @@ -39,7 +46,6 @@ public class HidingSelectionTest { private static JTextField field1; private static JTextField field2; private static JFrame frame; - private static Rectangle bounds; private static JMenu menu; private static JTextField anotherWindow; private static Point menuLoc; @@ -67,17 +73,9 @@ public class HidingSelectionTest { Robot robot = new Robot(); robot.waitForIdle(); robot.delay(200); - SwingUtilities.invokeAndWait(() -> { - bounds = field2.getBounds(); - bounds.setLocation(field2.getLocationOnScreen()); - }); - BufferedImage nosel = robot.createScreenCapture(bounds); SwingUtilities.invokeAndWait(field2::requestFocus); SwingUtilities.invokeAndWait(field2::selectAll); - robot.waitForIdle(); - robot.delay(200); - BufferedImage sel = robot.createScreenCapture(bounds); SwingUtilities.invokeAndWait(() -> { menuLoc = menu.getLocationOnScreen(); @@ -89,7 +87,7 @@ public class HidingSelectionTest { robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), sel)) { + if (!field2.getCaret().isSelectionVisible()) { throw new RuntimeException("Test fails: menu hides selection"); } @@ -98,7 +96,7 @@ public class HidingSelectionTest { SwingUtilities.invokeAndWait(field1::requestFocus); robot.waitForIdle(); robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), nosel)) { + if (field2.getCaret().isSelectionVisible()) { throw new RuntimeException( "Test fails: focus lost doesn't hide selection"); } @@ -119,35 +117,12 @@ public class HidingSelectionTest { SwingUtilities.invokeAndWait(anotherWindow::requestFocus); robot.waitForIdle(); robot.delay(200); - if (biEqual(robot.createScreenCapture(bounds), nosel)) { + if (!field2.getCaret().isSelectionVisible()) { throw new RuntimeException( "Test fails: switch window hides selection"); } - SwingUtilities.invokeAndWait(anotherWindow::selectAll); - robot.waitForIdle(); - robot.delay(200); - if (biEqual(robot.createScreenCapture(bounds), sel)) { - throw new RuntimeException( - "Test fails: selection ownership is lost selection is shown"); - } - SwingUtilities.invokeLater(frame2::dispose); SwingUtilities.invokeLater(frame::dispose); } - - static boolean biEqual(BufferedImage i1, BufferedImage i2) { - if (i1.getWidth() == i2.getWidth() && - i1.getHeight() == i2.getHeight()) { - for (int x = 0; x < i1.getWidth(); x++) { - for (int y = 0; y < i1.getHeight(); y++) { - if (i1.getRGB(x, y) != i2.getRGB(x, y)) { - return false; - } - } - } - return true; - } - return false; - } } diff --git a/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java index c3cdafe8794..893afab5f4d 100644 --- a/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java +++ b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -21,10 +21,17 @@ * questions. */ -import javax.swing.*; -import java.awt.*; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTextField; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; import java.awt.event.InputEvent; -import java.awt.image.BufferedImage; /** * @test @@ -40,131 +47,113 @@ public class MultiSelectionTest { private static JTextField field1; private static JTextField field2; private static JFrame frame; - private static Rectangle bounds; private static JMenu menu; private static JTextField anotherWindow; private static Point menuLoc; private static JFrame frame2; public static void main(String[] args) throws Exception { - SwingUtilities.invokeAndWait(() -> { - frame = new JFrame(); - field1 = new JTextField("field1 "); - field2 = new JTextField("field2 "); - field1.setEditable(false); - field2.setEditable(false); - frame.getContentPane().setLayout(new FlowLayout()); - frame.getContentPane().add(field1); - frame.getContentPane().add(field2); - JMenuBar menuBar = new JMenuBar(); - menu = new JMenu("menu"); - menu.add(new JMenuItem("item")); - menuBar.add(menu); - frame.setJMenuBar(menuBar); - frame.pack(); - frame.setVisible(true); - }); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + field1 = new JTextField("field1 "); + field2 = new JTextField("field2 "); + field1.setEditable(false); + field2.setEditable(false); + frame.getContentPane().setLayout(new FlowLayout()); + frame.getContentPane().add(field1); + frame.getContentPane().add(field2); + JMenuBar menuBar = new JMenuBar(); + menu = new JMenu("menu"); + menu.add(new JMenuItem("item")); + menuBar.add(menu); + frame.setJMenuBar(menuBar); + frame.pack(); + frame.setVisible(true); + }); - Robot robot = new Robot(); - robot.waitForIdle(); - robot.delay(200); - SwingUtilities.invokeAndWait(() -> { - bounds = field2.getBounds(); - bounds.setLocation(field2.getLocationOnScreen()); - }); - BufferedImage nosel = robot.createScreenCapture(bounds); + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(200); - SwingUtilities.invokeAndWait(field2::requestFocus); - SwingUtilities.invokeAndWait(field2::selectAll); - robot.waitForIdle(); - robot.delay(200); - BufferedImage sel = robot.createScreenCapture(bounds); + SwingUtilities.invokeAndWait(field2::requestFocus); + SwingUtilities.invokeAndWait(field2::selectAll); + robot.waitForIdle(); + robot.delay(200); - SwingUtilities.invokeAndWait(() -> { - menuLoc = menu.getLocationOnScreen(); - menuLoc.translate(10, 10); - }); - robot.mouseMove(menuLoc.x, menuLoc.y); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.delay(50); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - robot.waitForIdle(); - robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), sel)) { - throw new RuntimeException("Test fails: menu hides selection"); - } - - SwingUtilities.invokeAndWait( - MenuSelectionManager.defaultManager()::clearSelectedPath); - SwingUtilities.invokeAndWait(field1::requestFocus); - robot.waitForIdle(); - robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), sel)) { - throw new RuntimeException( - "Test fails: focus lost hides single selection"); - } - - SwingUtilities.invokeAndWait(field1::selectAll); - robot.waitForIdle(); - robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), nosel)) { - throw new RuntimeException( - "Test fails: focus lost doesn't hide selection upon multi selection"); - } - - SwingUtilities.invokeAndWait(field2::requestFocus); - robot.waitForIdle(); - robot.delay(200); - if (!biEqual(robot.createScreenCapture(bounds), sel)) { - throw new RuntimeException( - "Test fails: focus gain hides selection upon multi selection"); - } - - SwingUtilities.invokeAndWait(field2::requestFocus); - robot.waitForIdle(); - SwingUtilities.invokeAndWait(() ->{ - frame2 = new JFrame(); - Point loc = frame.getLocationOnScreen(); - loc.translate(0, frame.getHeight()); - frame2.setLocation(loc); - anotherWindow = new JTextField("textField3"); - frame2.add(anotherWindow); - frame2.pack(); - frame2.setVisible(true); - }); - robot.waitForIdle(); - SwingUtilities.invokeAndWait(anotherWindow::requestFocus); - robot.waitForIdle(); - robot.delay(200); - if (biEqual(robot.createScreenCapture(bounds), nosel)) { - throw new RuntimeException( - "Test fails: switch window hides selection"); - } - - SwingUtilities.invokeAndWait(anotherWindow::selectAll); - robot.waitForIdle(); - robot.delay(200); - if (biEqual(robot.createScreenCapture(bounds), sel)) { - throw new RuntimeException( - "Test fails: selection ownership is lost selection is shown"); - } - - SwingUtilities.invokeLater(frame2::dispose); - SwingUtilities.invokeLater(frame::dispose); - } - - static boolean biEqual(BufferedImage i1, BufferedImage i2) { - if (i1.getWidth() == i2.getWidth() && - i1.getHeight() == i2.getHeight()) { - for (int x = 0; x < i1.getWidth(); x++) { - for (int y = 0; y < i1.getHeight(); y++) { - if (i1.getRGB(x, y) != i2.getRGB(x, y)) { - return false; - } - } + SwingUtilities.invokeAndWait(() -> { + menuLoc = menu.getLocationOnScreen(); + menuLoc.translate(10, 10); + }); + robot.mouseMove(menuLoc.x, menuLoc.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(50); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(200); + if (!field2.getCaret().isSelectionVisible()) { + throw new RuntimeException("Test fails: menu hides selection"); } - return true; + + SwingUtilities.invokeAndWait( + MenuSelectionManager.defaultManager()::clearSelectedPath); + SwingUtilities.invokeAndWait(field1::requestFocus); + robot.waitForIdle(); + robot.delay(200); + if (field2.getSelectedText() == null || field2.getSelectedText().length() == 0) { + throw new RuntimeException( + "Test fails: focus lost hides single selection"); + } + + SwingUtilities.invokeAndWait(field1::selectAll); + robot.waitForIdle(); + robot.delay(200); + if (field2.getCaret().isSelectionVisible()) { + throw new RuntimeException( + "Test fails: focus lost doesn't hide selection upon multi selection"); + } + + SwingUtilities.invokeAndWait(field2::requestFocus); + robot.waitForIdle(); + robot.delay(200); + if (!field2.getCaret().isSelectionVisible()) { + throw new RuntimeException( + "Test fails: focus gain hides selection upon multi selection"); + } + + SwingUtilities.invokeAndWait(field2::requestFocus); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + frame2 = new JFrame(); + Point loc = frame.getLocationOnScreen(); + loc.translate(0, frame.getHeight()); + frame2.setLocation(loc); + anotherWindow = new JTextField("textField3"); + frame2.add(anotherWindow); + frame2.pack(); + frame2.setVisible(true); + }); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(anotherWindow::requestFocus); + robot.waitForIdle(); + robot.delay(200); + if (!field2.getCaret().isSelectionVisible()) { + throw new RuntimeException( + "Test fails: switch window hides selection"); + } + + SwingUtilities.invokeAndWait(anotherWindow::selectAll); + robot.waitForIdle(); + robot.delay(200); + if (field2.getCaret().isSelectionVisible()) { + throw new RuntimeException( + "Test fails: selection ownership is lost selection is shown"); + } + } finally { + if (frame2 != null) { + SwingUtilities.invokeLater(frame2::dispose); + } + SwingUtilities.invokeLater(frame::dispose); } - return false; } }