-
Bug
-
Resolution: Fixed
-
P4
-
1.3.1
-
beta2
-
x86
-
linux
Name: bsC130419 Date: 05/25/2001
java version "1.3.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-beta-b15)
Java HotSpot(TM) Client VM (build 1.3.1beta-b15, mixed mode)
LineBreakMeasurer.nextLayout() measures length in a way that is
inconsistent with TextLayout.getBounds() and TextLayout.getAdvance(). We
use TextLayout.getBounds() to measure the width of a string during the
layout of the X axis of a custom component. After our component decides
on an X-axis layout, it uses the LineBreakMeasurer to divide up the
pargraph string into lines for Y-axis layout and then drawing. If a
particular string is allocated exactly as much horizontal space as
TextLayout.getBounds() indicates it should need, this algorithm fails.
The problem is that using the width from TextLayout.getBounds() as the
maxAdvance argument to LineBreakMeasurer.nextAdvance() doesn't yield a
single TextLayout object with the whole string. If the string has no
whitespace, the last character or few gets moved to a second line. If the
string has whitespace in it, the last word is moved to a second line.
The following code demonstrates the problem.
import java.awt.*;
import java.awt.font.*;
import java.text.*;
import javax.swing.*;
public class TestLayout {
static String longString = "VeryVeryVeryVeryVeryVeryVeryLongTestString";
static String brokenString = "Line wraps where it should not.";
JFrame jf = new JFrame();
AttributedString asLong;
AttributedString asBroken;
LineBreakMeasurer lbmLong;
LineBreakMeasurer lbmBroken;
FontRenderContext frc;
public TestLayout() {
jf = new JFrame();
jf.setVisible( true );
Graphics g = jf.getGraphics();
frc = ((Graphics2D) g).getFontRenderContext();
asLong = new AttributedString( longString );
lbmLong = new LineBreakMeasurer( asLong.getIterator(), frc );
asBroken = new AttributedString( brokenString );
lbmBroken = new LineBreakMeasurer( asBroken.getIterator(), frc );
}
public void runTest() {
lbmLong.setPosition( 0 );
TextLayout tl1 = lbmLong.nextLayout( Short.MAX_VALUE );
int neededSpace = (int) Math.ceil( tl1.getBounds().getWidth() );
System.err.println( "End position after advancing the whole string: " +
lbmLong.getPosition() );
lbmLong.setPosition( 0 );
TextLayout tl2 = lbmLong.nextLayout( neededSpace );
// On our system, the previous println shows a position of 42
// while this println shows a position of 41. The last character
// is left to the next TextLayout.
System.err.println( "End position after minimal advance: " +
lbmLong.getPosition() );
TextLayout tl3 = lbmLong.nextLayout( Short.MAX_VALUE );
lbmBroken.setPosition( 0 );
TextLayout tl4 = lbmBroken.nextLayout( Short.MAX_VALUE );
neededSpace = (int) Math.ceil( tl4.getBounds().getWidth() );
System.err.println( "End position after advancing the whole string: " +
lbmBroken.getPosition() );
lbmBroken.setPosition( 0 );
TextLayout tl5 = lbmBroken.nextLayout( neededSpace );
// On our system, the previous println shows a position of 31, while this
// println shows a position of 27. The last word is left to the next
// text layout.
System.err.println( "End position after minimal advance: " +
lbmBroken.getPosition() );
TextLayout tl6 = lbmBroken.nextLayout( Short.MAX_VALUE );
jf.setSize( 1000, 500 );
Graphics g = jf.getGraphics();
// tl1 shows the whole string on one line, this is the string being
// measured.
tl1.draw( (Graphics2D) g, 100, 100 );
// tl2 shows all but the last character because the LineBreakMeasurer
// doesn't return the whole string using the width measured with by
// tl1.
tl2.draw( (Graphics2D) g, 100, 200 );
// tl3 shows the character that did not make it into tl2
tl3.draw( (Graphics2D) g, 100, 220 );
// tl4 shows the whole line the was used to measure the string
tl4.draw( (Graphics2D) g, 100, 300 );
// tl5 shows the line that nextLayout returned using the measurement
// provided by tl4.getBounds().getWidth()
tl5.draw( (Graphics2D) g, 100, 400 );
// tl6 shows the part of the line that was left over.
tl6.draw( (Graphics2D) g, 100, 420 );
}
public static void main(String args[]) {
TestLayout t = new TestLayout();
t.runTest();
}
}
We've tried using both TextLayout.getBounds() and TextLayout.getAdvance()
to measure the string, and the problem is the same both ways. Simply
adding some padding to the maxAdvance argument for the nextLayout call hasn't
worked around the problem for us. The amount of padding necessary seems to
depend on the formatting attributes of the string (though we're less
certain of this -- we might just not have played with the padding constant
enough).
(Review ID: 124280)
======================================================================