Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8048110

Using tables in JTextPane leads to infinite loop in FlowLayout.layoutRow

XMLWordPrintable

    • b33
    • x86_64
    • windows_7

        FULL PRODUCT VERSION :
        java version "1.7.0_60"
        Java(TM) SE Runtime Environment (build 1.7.0_60-b19)
        Java HotSpot(TM) Client VM (build 24.60-b09, mixed mode, sharing)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7601]

        A DESCRIPTION OF THE PROBLEM :
        We are using a JTextPane to display HTML content in a Swing application. For this we also use Swing's HTMLEditorKit and HTMLDocument implementation. The application works fine when the document contains simple HTML.
        If we replace a paragraph inside the HTML document with an HTML table by using the HTMLDocument.setInnerHTML method, this method never returns and hangs in an infinite loop.

        When searching for a workaround we evaluated using the HTMLDocument.insertAfterStart method instead. This method returns, but the layouting of the simple table fails as there are multiple tables visible now. Thus, using this method (or the related insert... methods) does not solve the problem.

        The application works fine with Java releases prior 1.7.0_60.
        The problem occurs also with Java 8 and Java 8u5.

        REGRESSION. Last worked in version 7u55

        ADDITIONAL REGRESSION INFORMATION:
        java version "1.7.0_55"
        Java(TM) SE Runtime Environment (build 1.7.0_55-b13)
        Java HotSpot(TM) Client VM (build 24.55-b03, mixed mode, sharing)

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1. Run the test program below, a Swing frame will be displayed
        2. Click the button

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The application displays the simple 2x2 HTML table in the text pane.
        ACTUAL -
        The application freezes and consumes 100% of a CPU core.

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Stack trace of the thread "AWT-EventQueue-0":

        java.util.Arrays.copyOf(java.lang.Object[ ], int, java.lang.Class) (line: 2245)
        java.util.Arrays.copyOf(java.lang.Object[ ], int)
        java.util.Vector.grow(int) (line: 262)
        java.util.Vector.ensureCapacityHelper(int) (line: 242)
        java.util.Vector.add(java.lang.Object) (line: 778)
        javax.swing.text.FlowView$FlowStrategy.layoutRow(javax.swing.text.FlowView, int, int) (line: 563)
        javax.swing.text.FlowView$FlowStrategy.layout(javax.swing.text.FlowView) (line: 477)
        javax.swing.text.FlowView.layout(int, int) (line: 201)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 366)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 348)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 361)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 334)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 366)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 348)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 361)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 334)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 366)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 348)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.FlowView.layout(int, int) (line: 220)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 366)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 348)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.text.BoxView.updateChildSizes() (line: 366)
        javax.swing.text.BoxView.setSpanOnAxis(int, float) (line: 348)
        javax.swing.text.BoxView.layout(int, int) (line: 708)
        javax.swing.text.BoxView.setSize(float, float) (line: 397)
        javax.swing.plaf.basic.BasicTextUI$RootView.setSize(float, float) (line: 1714)
        javax.swing.plaf.basic.BasicTextUI$RootView.paint(java.awt.Graphics, java.awt.Shape) (line: 1433)
        javax.swing.plaf.basic.BasicTextUI.paintSafely(java.awt.Graphics) (line: 737)
        javax.swing.plaf.basic.BasicTextUI.paint(java.awt.Graphics, javax.swing.JComponent) (line: 881)
        javax.swing.plaf.basic.BasicTextUI.update(java.awt.Graphics, javax.swing.JComponent) (line: 860)
        javax.swing.JComponent.paintComponent(java.awt.Graphics) (line: 778)
        javax.swing.JComponent.paint(java.awt.Graphics) (line: 1054)
        javax.swing.JComponent.paintToOffscreen(java.awt.Graphics, int, int, int, int, int, int) (line: 5219)
        javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(javax.swing.JComponent, java.awt.Image, java.awt.Graphics, int, int, int, int) (line: 1529)
        javax.swing.RepaintManager$PaintManager.paint(javax.swing.JComponent, javax.swing.JComponent, java.awt.Graphics, int, int, int, int) (line: 1452)
        javax.swing.RepaintManager.paint(javax.swing.JComponent, javax.swing.JComponent, java.awt.Graphics, int, int, int, int) (line: 1249)
        javax.swing.JComponent._paintImmediately(int, int, int, int) (line: 5167)
        javax.swing.JComponent.paintImmediately(int, int, int, int) (line: 4978)
        javax.swing.RepaintManager$3.run() (line: 808)
        javax.swing.RepaintManager$3.run()
        java.security.AccessController.doPrivileged(java.security.PrivilegedAction, java.security.AccessControlContext)
        java.security.ProtectionDomain$1.doIntersectionPrivilege(java.security.PrivilegedAction, java.security.AccessControlContext, java.security.AccessControlContext)
        javax.swing.RepaintManager.paintDirtyRegions(java.util.Map) (line: 796)
        javax.swing.RepaintManager.paintDirtyRegions() (line: 769)
        javax.swing.RepaintManager.prePaintDirtyRegions() (line: 718)
        javax.swing.RepaintManager.access$1100(javax.swing.RepaintManager)
        javax.swing.RepaintManager$ProcessingRunnable.run() (line: 1677)
        java.awt.event.InvocationEvent.dispatch() (line: 312)
        java.awt.EventQueue.dispatchEventImpl(java.awt.AWTEvent, java.lang.Object) (line: 733)
        java.awt.EventQueue.access$200(java.awt.EventQueue, java.awt.AWTEvent, java.lang.Object)
        java.awt.EventQueue$3.run() (line: 694)
        java.awt.EventQueue$3.run()
        java.security.AccessController.doPrivileged(java.security.PrivilegedAction, java.security.AccessControlContext)
        java.security.ProtectionDomain$1.doIntersectionPrivilege(java.security.PrivilegedAction, java.security.AccessControlContext, java.security.AccessControlContext)
        java.awt.EventQueue.dispatchEvent(java.awt.AWTEvent) (line: 703)
        java.awt.EventDispatchThread.pumpOneEventForFilters(int) (line: 242)
        java.awt.EventDispatchThread.pumpEventsForFilter(int, java.awt.Conditional, java.awt.EventFilter) (line: 161)
        java.awt.EventDispatchThread.pumpEventsForHierarchy(int, java.awt.Conditional, java.awt.Component) (line: 150)
        java.awt.EventDispatchThread.pumpEvents(int, java.awt.Conditional) (line: 146)
        java.awt.EventDispatchThread.pumpEvents(java.awt.Conditional) (line: 138)
        java.awt.EventDispatchThread.run() (line: 91)

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.awt.BorderLayout;
        import java.awt.Dimension;
        import java.awt.event.ActionEvent;
        import java.awt.event.ActionListener;

        import javax.swing.JButton;
        import javax.swing.JFrame;
        import javax.swing.JTextPane;
        import javax.swing.WindowConstants;
        import javax.swing.text.Element;
        import javax.swing.text.html.HTMLDocument;
        import javax.swing.text.html.HTMLEditorKit;

        public class FlowViewLayoutBug extends JFrame
        {
            public static void main(String[] args)
            {
                final FlowViewLayoutBug frame = new FlowViewLayoutBug();
                final JTextPane textPane = new JTextPane();

                HTMLEditorKit editorKit = new HTMLEditorKit();
                textPane.setContentType("text/html");
                textPane.setEditorKit(editorKit);
                textPane.setText("Initial text without table works as expected.<br/>However, as soon as clicking the button, the whole app hangs with 100% CPU consumption.");

                JButton button = new JButton("Click me");
                button.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e)
                    {
                        // using an HTML table inside the document causes the problem
                        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>";

                        try
                        {
                            textPane.setDocument(textPane.getEditorKit().createDefaultDocument());
                            HTMLDocument htmlDocument = (HTMLDocument) textPane.getDocument();
                            Element firstParagraph = findFirstElement(textPane.getDocument().getDefaultRootElement(), "p");
                            // this line causes the application to hang in an infinite loop
                            htmlDocument.setInnerHTML(firstParagraph, htmlText);
                            
                            // if we use 'insertAfterStart' instead of 'setInnerHTML', the application does
                            // not lang, but the layouting of the simple table fails (there are multiple tables visible).
                            // Thus, this is no workaround.
                            // To reproduce this, uncomment line below and comment line above.
                            //htmlDocument.insertAfterStart(firstParagraph, htmlText);
                        }
                        catch (Exception ex)
                        {
                            ex.printStackTrace();
                        }
                    }
                });

                frame.getContentPane().setLayout(new BorderLayout());
                frame.getContentPane().add(textPane, BorderLayout.CENTER);
                frame.getContentPane().add(button, BorderLayout.SOUTH);

                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setSize(new Dimension(500, 200));
                frame.setVisible(true);
            }

            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;
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        We did not find any workaround.
        Displaying HTML content with tables is an essential feature of our application. Thus, we cannot continue until this bug is resolved.


              dmarkov Dmitry Markov
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: