JDK-6539700 : JTextPane line wrap radically different from previous versions in jre 1.5.0_10+
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6,7
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2007-03-28
  • Updated: 2015-05-13
  • Resolved: 2009-08-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7
1.4-poolResolved 6u10Fixed 7 b70Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
I:\>java -version
java version "1.5.0_11"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
Java HotSpot(TM) Client VM (build 1.5.0_11-b03, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
I:\>ver

Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
For several years, I have been displaying marked up DNA sequence in a JTextPane -- DNA is one long string without spaces or line breaks. Until jre 1.5.0_10 on windows, the JTextPane would wrap my text at the last character that would fit in the component -- logical and exactly what I want. but in version 1.5.0_10 line wrapping seems to chunk by AttributeSet (see working code example in "steps to reproduce" below). This makes no sense and it any case breaks existing applications like mine.

Screen shot on how this has affected my production application here:

http://everydaysystems.com/usenet/JTextPane/

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the code sample below and run on jre 1.5.0_4 on windows and then on jre1.5.0_10 or higher on windows (I'm not sure how versions in between fare, except that 1.5.0_7 on the mac works fine). You will see very different line wrapping in the JTextPane.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Here is a screenshot of how the line wrapping has changed in version 1.5.0_10

http://everydaysystems.com/usenet/JTextPane/

Line wrapping used to chunk by "character" for string with no internal spaces, now it seems to chunk by AttributeSet.

I want the old version back!
ACTUAL -
I saw line breaks inserted at AttributeSet boundaries. This makes no sense and  is a radical and undocumented change from previous versions of the JRE.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.awt.Color;
import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

public class JTextPaneWrapChangeDemo {

    public JTextPaneWrapChangeDemo() {
        super();
    }

    public static void main(String[] args) {
        JTextPaneWrapChangeDemo demo = new JTextPaneWrapChangeDemo();
        demo.run();
    }

    public void run() {
        JFrame frame = new JFrame();
        frame.setSize(400, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTextPane textPane = new JTextPane();
        JScrollPane scrollPane = new JScrollPane(textPane);
        frame.add(scrollPane);
        textPane.setEditable(false);
        textPane.setFont(new Font("Courier", Font.PLAIN, 12));
        MutableAttributeSet exonAttributeSet = new SimpleAttributeSet();
        MutableAttributeSet intronAttributeSet = new SimpleAttributeSet();
        StyleConstants.setFontSize(exonAttributeSet, 12);
        StyleConstants.setForeground(exonAttributeSet, Color.blue);
        StyleConstants.setFontSize(intronAttributeSet, 12);
        StyleConstants.setForeground(intronAttributeSet, Color.black);
        try {
            Document d = textPane.getDocument();
            d.insertString(d.getLength(), exon1, exonAttributeSet);
            d.insertString(d.getLength(), intron1, intronAttributeSet);
            d.insertString(d.getLength(), exon2, exonAttributeSet);
            d.insertString(d.getLength(), intron2, intronAttributeSet);
            d.insertString(d.getLength(), exon3, exonAttributeSet);

        } catch (BadLocationException e) {
            System.out.println("bad location exception" + e);
        }
        frame.show();
    }

    String exon1 = "ATGCCACCAAAAGCGCGTATAAACTCAAAAAATTCAGTTGAGCAGGAGGGAAGGGTCCTACTTGCAGTATCAGCTTTGAAAAATAAGGAAATTCTCAATATTCGTGAAGCTGCGCGTGTCTATAATGTGCCTTATACTACCCTCCAGCGGCGCCTAAAGGGGCATACTTTTCGAGCTGAATTACGCGCAAATGGCCATAAAATGACTCAGAATGAAGAGGATTCACTTATTAGATGGATTCTATCTATGGATCAACGTGGAGCGGCTCCCCGACCGTCCCATGTACGAGAAATGGCGAATATCCTGCTTGCGCAGCGTGGTTCAACTCCTACCCAGACTGTTGGAGAGAAATGGGTATATAACTTCATTAATCGGCATGATGAGATCAAAACCCGATTCTCTAGGCGCTATAACCACCAGCGTGCTAAATGTGAAGACCCAAAGATTATCCTGGAATGGTTCAATCGTGTCCAGATCACAATAATGCAGCATGGGATTACACTGGAAGATATCTACAACTTTGATGAAACTGGCTTTGCAATGGGCTTAGTAGCTACTGCTAAG";
    String intron1 = "GTAGTTACAAGAGCTGAGATGCTTAGTCGGCCCTTCCTTATCCAGCCAGGGAACCGCGAATGGGTTACCTCTATAGAGTGTATTAACTCTACTGGCTGGGTGCTTCCACCATGCATTATCTTCAAGGGAAAGGTCCATATTGAGGACTGGTATTAAGATACAGCCTTACCAGCAGACTGGCGGATCGAGGTCAGTGAGAATGGATGGACGACTGATCAGATTGGATTACGATGGCTTCAAAAAGTCTTTATTCCTGCTACTACCAGTCGTACAACTGGTAGATATCGACTATTAATTCTTGATGGCCATGGGAGCCATCTAACACCACAGTTTGATCAAATCTGCACTGAGAATGATATCATTCCAATCTGCATGCCTGCACATTCATCACATCTCCTCCAGCCTCTAGATGTTGGCTGTTTCTCTCCTCTTAAGCGTGCGTATGGCCGCTTGATTGAGGATAAGATGCGGCTTGGTTTCAACCATATTGACAAGTTTGATTTCCTTGAGGCCTATCCACAAGCTCATACGGCAATCTTTTCAGCAGATAATATTAAAAGTGGCTTTTCAGCAACTGGATTAATACCACTGAATCCAGATCGGGTGCTCAGTCAGCTTAATATCCAGCTTAGAACACCTACACCACCAGGCAGCCGATCAACTAATTCTGTCCCAAAAACACCTTACAATCTCAAGCA";
    String exon2 = "GCTGAAGAAGCAGGAAACTACGCTTAAGAAGCTACTTAGGGAGCGTACATACAGCCCTCCTACCCCTACAAAGGCTGTGCTAGGTCAGATTATCAAGGGGTGTGAGATGGCAATGAATAACGCTGCCCTTCTTGCAAAGGAAAATCATGATCTACGTGCTGCACATGAAAAGCACCTTCAAAAGCAGAAGCGATCTAGGCGGCAGATAGAAACTGCA";
    String intron2 = "GTGGGATTATCTATCCAGGAAGGGCAGGAGATCATTTAACGCAGGGATCAGGCTGCTGAAGCTATCCCAACTATCCCTCCAGAGCAGGTAGTAGATACAGAACAACGCCCTCAACGGGCACCCCCACGCTGCAGTGACTGCCATATTCTAGGCCATAGGCGATTGCAATGTCCGCAGCGCAAGAATAACTAGATTTAGTAATAAAATCATGTTTTAGGGGTTCAAAATAGCCTCCAATTTCGGCCGCGGCCAAATTCTATAG";
    String exon3 = "TATGGTGATCCGCTCGGTTACGTGATCCGCTCGCTTACCGATTACGTTACTTCTCTGGAAGACGATCCTGGACTAAGTCATTTCCTTTTGCGTAGTTCAGCGGATTTTTTTTTTCTTCTGCTACTTGGGGTCGCTGAAGATGGAATCAATCAGACGT";

}

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

CUSTOMER SUBMITTED WORKAROUND :
Tell users to use an  older JRE. This is not satisfactory.

Release Regression From : 5.0u7
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Comments
SUGGESTED FIX Webrev: http://sa.sfbay.sun.com/projects/swing_data/7/6539700.1 Regtest: test/javax/swing/text/GlyphView/6539700/bug6539700.java
03-08-2009

EVALUATION It should be noted that the requested default splitting behavior (breaking GlyphView at arbitrary place when no valid breakpoint is found by BreakIterator) is horribly wrong and should not be restored in any JDK release, either future or past. This particular case MAY be addressed by implementing BreakIterator that mimics the old behavior if turned on either explicitly or implicitly by setting some environment variable. But anyway this applies to JDK7+ only, as the earlier JDKs have no API for setting BreakIterator on JTextComponent. As mentioned earlier in this evaluation, simple workaround (one character per view) is available already for cases like this one.
21-05-2007

EVALUATION from ###@###.###: --- I think it is because of my fix for 6306218 [JEditorPane is unable to do reasonably spaced indentation in complex HTML tables] http://sa.sfbay.sun.com/projects/swing_data/mustang/6306218/ (part of it was: If there is no good point to break GlyphView we break it on the boundary rather than splitting it.) http://sa.sfbay.sun.com/mail-archive/6306218/0016.html > 2. PargraphView minimum span returns maximum of minimum spans for the views it contains. > That is wrong since we not necessarily break rows on the View boundaries. > For example : > <b>bold</b><i>italic</i> > The minimum width for this should be the width of <b>bold</b><i>italic</i> but not the max(width(<b>bold</b>), width(<i>italic</i>)) > To partially address problem with ParagraphView > I suggest to change breakWeight for GlyphView and all descendants. > Breaking on the View boundary is better than splitting it. For example : <b>bold</b><i>italic</i> > After this change will be split only: > <b>bold</b> > <i>italic</i> > It is not correct since it should not be wrapped at all but it is much better > than splitting "bold" or "italic" across two rows. > New bug has been created to address ParagraphView minimum span problem: > 6423287 [PargraphView returns wrong minimum span] As soon as 6423287 is fixed that change to GlyphView can be undone. Note: do not think we broke any specs with that change. Developers expectations were broken but it could be because the expectations were wrong... Bug submitter case is an unusual one. IMO in most of the cases things got way better because of that change. There is a simple workaround for this: one character per view/element. That is not going to be expensive for the bug submitter case. Instead of d.insertString(d.getLength(), exon1, exonAttributeSet); do for (int i = 0; i < exon1.length(); i++) { d.insertString(d.getLength(), exon1.substring(i, i + 1), exonAttributeSet); } ---
04-04-2007

EVALUATION This is caused by the same problem reported earlier in 6423287 "PargraphView returns wrong minimum span." Fixing the above bug will fix this too.
03-04-2007