From bc41986ee3691ca3dd1281a20a9494010470d6d6 Mon Sep 17 00:00:00 2001 From: duke Date: Wed, 28 May 2025 09:47:18 +0000 Subject: [PATCH 1/3] Backport 46251bc6e248a19e8d78173ff8d0502c68ee1acb --- .../swing/plaf/basic/BasicOptionPaneUI.java | 11 +++- .../TestOptionPaneStackOverflow.java | 59 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index b3a12edb5fb..4086bb1ac11 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -89,6 +89,7 @@ public class BasicOptionPaneUI extends OptionPaneUI { public static final int MinimumHeight = 90; private static String newline; + private static int recursionCount; /** * {@code JOptionPane} that the receiver is providing the @@ -455,7 +456,7 @@ protected void addMessageComponents(Container container, @SuppressWarnings("serial") // anonymous class JPanel breakPanel = new JPanel() { public Dimension getPreferredSize() { - Font f = getFont(); + Font f = getFont(); if (f != null) { return new Dimension(1, f.getSize() + 2); @@ -470,8 +471,14 @@ public Dimension getPreferredSize() { addMessageComponents(container, cons, s.substring(0, nl), maxll, false); } + // Prevent recursion of more than + // 200 successive newlines in a message + if (recursionCount++ > 200) { + recursionCount = 0; + return; + } addMessageComponents(container, cons, s.substring(nl + nll), maxll, - false); + false); } else if (len > maxll) { Container c = Box.createVerticalBox(); diff --git a/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java b/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java new file mode 100644 index 00000000000..f8650c28ac4 --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java @@ -0,0 +1,59 @@ +/* + * 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 8224267 + @key headful + @summary Verifies if StackOverflowError is not thrown for multiple newlines + @run main TestOptionPaneStackOverflow + */ + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +public class TestOptionPaneStackOverflow +{ + static JFrame frame; + + public static void main(String[] argv) throws Exception + { + try { + String message = java.nio.CharBuffer.allocate(5000).toString(). + replace('\0','\n'); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + JOptionPane optionPane = new JOptionPane(); + optionPane.createDialog(frame, null); + optionPane.setMessage(message); + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} From ee23fc5705580eba71820a56dedc3b1d141af3d3 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sat, 7 Jun 2025 02:51:39 +0200 Subject: [PATCH 2/3] Backport 6e18883d8ffd9a7b7d495da05e9859dc1d1a2677 --- .../classes/javax/swing/plaf/basic/BasicOptionPaneUI.java | 4 ++++ .../javax/swing/JOptionPane/TestOptionPaneStackOverflow.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index 4086bb1ac11..84143a2c215 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -369,6 +369,7 @@ protected Container createMessageArea() { "OptionPane.messageAnchor", GridBagConstraints.CENTER); cons.insets = new Insets(0,0,3,0); + recursionCount = 0; addMessageComponents(body, cons, getMessage(), getMaxCharactersPerLineCount(), false); top.add(realBody, BorderLayout.CENTER); @@ -473,8 +474,11 @@ public Dimension getPreferredSize() { } // Prevent recursion of more than // 200 successive newlines in a message + // and indicate message is truncated via ellipsis if (recursionCount++ > 200) { recursionCount = 0; + addMessageComponents(container, cons, new String("..."), + maxll,false); return; } addMessageComponents(container, cons, s.substring(nl + nll), maxll, diff --git a/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java b/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java index f8650c28ac4..9cfaea13755 100644 --- a/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java +++ b/test/jdk/javax/swing/JOptionPane/TestOptionPaneStackOverflow.java @@ -22,7 +22,7 @@ */ /* @test - @bug 8224267 + @bug 8224267 8290162 @key headful @summary Verifies if StackOverflowError is not thrown for multiple newlines @run main TestOptionPaneStackOverflow From f947402ef46cc9b4148d16698e9d336de1485c8f Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sat, 7 Jun 2025 02:52:40 +0200 Subject: [PATCH 3/3] Backport 91072ee3934616ab2edc4850a59c0a25fd0de3b4 --- .../swing/plaf/basic/BasicOptionPaneUI.java | 104 +++++++++++------- .../swing/JOptionPane/TestJOptionHTMLTag.java | 66 +++++++++++ 2 files changed, 130 insertions(+), 40 deletions(-) create mode 100644 test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java index 84143a2c215..27e8feb94d6 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -451,51 +451,75 @@ protected void addMessageComponents(Container container, } else if ((nl = s.indexOf('\n')) >= 0) { nll = 1; } - if (nl >= 0) { - // break up newlines - if (nl == 0) { - @SuppressWarnings("serial") // anonymous class - JPanel breakPanel = new JPanel() { - public Dimension getPreferredSize() { - Font f = getFont(); - - if (f != null) { - return new Dimension(1, f.getSize() + 2); - } - return new Dimension(0, 0); - } - }; - breakPanel.setName("OptionPane.break"); - addMessageComponents(container, cons, breakPanel, maxll, - true); - } else { - addMessageComponents(container, cons, s.substring(0, nl), - maxll, false); - } - // Prevent recursion of more than - // 200 successive newlines in a message - // and indicate message is truncated via ellipsis - if (recursionCount++ > 200) { - recursionCount = 0; - addMessageComponents(container, cons, new String("..."), - maxll,false); - return; + if (s.contains("")) { + /* line break in html text is done by
tag + * and not by /n so it's incorrect to address newline + * same as non-html text. + * Text between tags are extracted + * and rendered as JLabel text + */ + int index1 = s.indexOf(""); + int index2 = s.indexOf(""); + String str = ""; + if (index2 >= 0) { + str = s.substring(index2 + "".length()); + s = s.substring(index1, index2 + + "".length()); } - addMessageComponents(container, cons, s.substring(nl + nll), maxll, - false); - - } else if (len > maxll) { - Container c = Box.createVerticalBox(); - c.setName("OptionPane.verticalBox"); - burstStringInto(c, s, maxll); - addMessageComponents(container, cons, c, maxll, true ); - - } else { JLabel label; - label = new JLabel( s, JLabel.LEADING ); + label = new JLabel(s, JLabel.LEADING); label.setName("OptionPane.label"); configureMessageLabel(label); addMessageComponents(container, cons, label, maxll, true); + if (!str.isEmpty()) { + addMessageComponents(container, cons, str, maxll, false); + } + } else { + if (nl >= 0) { + // break up newlines + if (nl == 0) { + @SuppressWarnings("serial") // anonymous class + JPanel breakPanel = new JPanel() { + public Dimension getPreferredSize() { + Font f = getFont(); + + if (f != null) { + return new Dimension(1, f.getSize() + 2); + } + return new Dimension(0, 0); + } + }; + breakPanel.setName("OptionPane.break"); + addMessageComponents(container, cons, breakPanel, maxll, + true); + } else { + addMessageComponents(container, cons, s.substring(0, nl), + maxll, false); + } + // Prevent recursion of more than + // 200 successive newlines in a message + // and indicate message is truncated via ellipsis + if (recursionCount++ > 200) { + recursionCount = 0; + addMessageComponents(container, cons, new String("..."), + maxll, false); + return; + } + addMessageComponents(container, cons, s.substring(nl + nll), maxll, + false); + + } else if (len > maxll) { + Container c = Box.createVerticalBox(); + c.setName("OptionPane.verticalBox"); + burstStringInto(c, s, maxll); + addMessageComponents(container, cons, c, maxll, true); + + } else { + JLabel label; + label = new JLabel(s, JLabel.LEADING); + label.setName("OptionPane.label"); + configureMessageLabel(label); + addMessageComponents(container, cons, label, maxll, true); + } } } } diff --git a/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java b/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java new file mode 100644 index 00000000000..efbba1440c7 --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/TestJOptionHTMLTag.java @@ -0,0 +1,66 @@ +/* + * 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 5074006 + * @key headful + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Swing JOptionPane shows tag as a string after newline + * @run main/manual TestJOptionHTMLTag +*/ + +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +public class TestJOptionHTMLTag { + static String instructions + = "INSTRUCTIONS:\n" + + " A dialog will be shown.\n" + + " If it does not contain string, press Pass else press Fail.\n"; + static PassFailJFrame passFailJFrame; + + public static void main(String[] args) throws Exception { + + SwingUtilities.invokeAndWait(() -> { + try { + String message = "" + "This is a test\n" + ""; + JOptionPane optionPane = new JOptionPane(); + optionPane.setMessage(message); + optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + JDialog dialog = new JDialog(); + dialog.setContentPane(optionPane); + dialog.pack(); + dialog.setVisible(true); + + passFailJFrame = new PassFailJFrame(instructions); + PassFailJFrame.addTestWindow(dialog); + PassFailJFrame.positionTestWindow(dialog, PassFailJFrame.Position.HORIZONTAL); + } catch (Exception e) { + e.printStackTrace(); + } + }); + passFailJFrame.awaitAndCheck(); + } +} +