OpenJDK / jdk8u / jdk8u / jdk
changeset 10010:eb4956a1974f
8048110: Using tables in JTextPane leads to infinite loop in FlowLayout.layoutRow
Reviewed-by: alexp, alexsch
author | dmarkov |
---|---|
date | Fri, 12 Sep 2014 14:16:41 +0400 |
parents | 3ae82f0c6b31 |
children | 8375459f193f |
files | src/share/classes/javax/swing/text/FlowView.java src/share/classes/javax/swing/text/GlyphView.java src/share/classes/javax/swing/text/View.java test/javax/swing/text/View/8048110/bug8048110.java |
diffstat | 4 files changed, 152 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/javax/swing/text/FlowView.java Thu Sep 11 15:13:37 2014 +0400 +++ b/src/share/classes/javax/swing/text/FlowView.java Fri Sep 12 14:16:41 2014 +0400 @@ -800,14 +800,22 @@ @Override protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { - calculateUpdateIndexes(e); - // Send update event to all views followed by the changed place. - lastUpdateIndex = Math.max((getViewCount() - 1), 0); - for (int i = firstUpdateIndex; i <= lastUpdateIndex; i++) { - View v = getView(i); - if (v != null) { - Shape childAlloc = getChildAllocation(i, a); - forwardUpdateToView(v, e, childAlloc, f); + // Update the view responsible for the changed element by invocation of + // super method. + super.forwardUpdate(ec, e, a, f); + // Re-calculate the update indexes and update the views followed by + // the changed place. Note: we update the views only when insertion or + // removal takes place. + DocumentEvent.EventType type = e.getType(); + if (type == DocumentEvent.EventType.INSERT || + type == DocumentEvent.EventType.REMOVE) { + firstUpdateIndex = Math.min((lastUpdateIndex + 1), (getViewCount() - 1)); + lastUpdateIndex = Math.max((getViewCount() - 1), 0); + for (int i = firstUpdateIndex; i <= lastUpdateIndex; i++) { + View v = getView(i); + if (v != null) { + v.updateAfterChange(); + } } } }
--- a/src/share/classes/javax/swing/text/GlyphView.java Thu Sep 11 15:13:37 2014 +0400 +++ b/src/share/classes/javax/swing/text/GlyphView.java Fri Sep 12 14:16:41 2014 +0400 @@ -971,6 +971,14 @@ } } + /** {@inheritDoc} */ + @Override + void updateAfterChange() { + // Drop the break spots. They will be re-calculated during + // layout. It is necessary for proper line break calculation. + breakSpots = null; + } + /** * Class to hold data needed to justify this GlyphView in a PargraphView.Row */
--- a/src/share/classes/javax/swing/text/View.java Thu Sep 11 15:13:37 2014 +0400 +++ b/src/share/classes/javax/swing/text/View.java Fri Sep 12 14:16:41 2014 +0400 @@ -1199,6 +1199,13 @@ } /** + * Updates the view to reflect the changes. + */ + void updateAfterChange() { + // Do nothing by default. Should be overridden in subclasses, if any. + } + + /** * Forwards the <code>DocumentEvent</code> to the give child view. This * simply messages the view with a call to <code>insertUpdate</code>, * <code>removeUpdate</code>, or <code>changedUpdate</code> depending
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/text/View/8048110/bug8048110.java Fri Sep 12 14:16:41 2014 +0400 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014, 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 8048110 + * @summary Using tables in JTextPane leads to infinite loop in FlowLayout.layoutRow + * @author Dmitry Markov + * @run main bug8048110 + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.text.Element; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; + +public class bug8048110 { + private static SunToolkit toolkit = (SunToolkit)Toolkit.getDefaultToolkit(); + private static Object lock = new Object(); + private static boolean isRealSyncPerformed = false; + private static final String htmlText = "<table width=\"100%\" cellpadding=\"10\" cellspacing=\"5\" align=\"center\">" + + "<tr><th align=\"left\" bgcolor=\"#bec3c6\">Devices</th><th align=\"left\" bgcolor=\"#bec3c6\">State</th></tr>" + + "<tr><td align=\"left\" bgcolor=\"#bec3c6\">PC</td><td align=\"left\" bgcolor=\"#46a055\">Ok</td></tr></table>"; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createAndShowGUI(); + } + }); + + Thread thread = new Thread() { + @Override + public void run() { + toolkit.realSync(); + synchronized (lock) { + isRealSyncPerformed = true; + lock.notifyAll(); + } + } + }; + thread.start(); + + synchronized (lock) { + if (!isRealSyncPerformed) { + lock.wait(5000); + } + } + + if (!isRealSyncPerformed) { + throw new RuntimeException("Test Failed!"); + } + } + + private static void createAndShowGUI() { + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + HTMLEditorKit editorKit = new HTMLEditorKit(); + JTextPane textPane = new JTextPane(); + textPane.setContentType("text/html"); + textPane.setEditorKit(editorKit); + textPane.setText("Initial text without table"); + + JFrame frame = new JFrame("bug8048110"); + frame.getContentPane().add(textPane, BorderLayout.CENTER); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setSize(500, 200); + frame.setVisible(true); + + textPane.setDocument(textPane.getEditorKit().createDefaultDocument()); + HTMLDocument htmlDocument = (HTMLDocument) textPane.getDocument(); + Element firstParagraph = findFirstElement(textPane.getDocument().getDefaultRootElement(), "p"); + + try { + htmlDocument.setInnerHTML(firstParagraph, htmlText); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static Element findFirstElement(Element e, String name) { + String elementName = e.getName(); + if (elementName != null && elementName.equalsIgnoreCase(name)) { + return e; + } + for (int i = 0; i < e.getElementCount(); i++) { + Element result = findFirstElement(e.getElement(i), name); + if (result != null) { + return result; + } + } + return null; + } +} +