-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
1.4.0
-
Fix Understood
-
x86
-
windows_2000
Name: gm110360 Date: 11/05/2001
java version "1.4.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-b77)
Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)
import java.awt.*;
import java.awt.image.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
/*
I have found a problem with Fonts and TextLayout when using
scaled fonts in Java2D JDK 1.4 Beta2. I am trying to adjust the
"user space" coordinates so that "1.0 units" means about the
same as 1 inch. Depending on your screen size, this means
applying a scale factor to the Graphics2D of about 100.
This works beautifully until I try to start displaying multi-line
text. Doing that requires knowing the Ascent, Descent and Leading;
when running with this scale factor these numbers are always
returned incorrectly as zero or close to it.
This test program shows the problem; I try to draw a line of text
using TextLayout in my scaled context. The output appears at the
expected size and in the expected position. However, when I ask
the TextLayout for Ascent, Descent and Leading it returns the
wrong answers (usually zero).
I tried to dig in deeper and get the same wrong answers when
going after the LineMetrics directly from the Font. Of course,
the FontMetrics returns zeros because it only knows about integers.
But I expected LineMetrics (which returns floats) to give the
right result.
I tried this under JDK 1.3.1 and the results are even worse.
Not only are the metrics wrong, but all the characters are piled
on top of each other, meaning that the "advance" is wrong as well.
But I only care about JDK 1.4...
This problem obviously stems from Font's checkered past; in the
deeps of time it only knew about integer metrics. I imagine there
is still some code hiding in Font or FontMetrics or LineMetrics
or whatever that hasn't been updated to respect the "fractional
metrics" hint. Some rogue roundoff error is throwing away my
metrics, which are perfectly correct for my user space (although
they would seem wrong in the old integer/pointsize view of Fonts).
This is pretty serious for us since we are trying to write
a sophisticated drawing program that can scale and zoom. Java2D
is perfect for that, except for this problem with Font metrics.
It certainly seems like Java2D *should* be able to do what we
want. A workaround would be fine, but it would be nice to see
a fix before 1.4 goes FCS.
To run this test, just compile it
javac FontTest.java
and run it
java FontTest
The window looks correct; the (bad) metrics will be printed to stdout.
My results look something like this:
usesFractionalMetrics=true
TextLayout
tl.Ascent=-0.0
tl.Descent=0.0
tl.Leading=-0.0
tl.Bounds=java.awt.geom.Rectangle2D$Float[x=3.4028235E38,y=3.4028235E38,w=-
3.4028235E38,h=-3.4028235E38]
font.size2d=0.24
r2d.Bounds=java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=1.1471485,h=0.0]
r2d.MaxBounds=java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
LineMetrics
lm.Ascent=-0.0
lm.Descent=0.0
lm.Leading=-0.0
FontMetrics
fm.Ascent=0
fm.Descent=0
fm.Leading=0
Steve Langley
###@###.###
*/
public class FontTest extends JFrame
{
//
// Scaling like this makes 1 user space unit roughly equal to 1 inch
//
private static final double SCALE = 100.0;
public FontTest()
{
super();
WindowListener listener = new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
};
this.setTitle("Font Test");
this.setBackground(Color.white);
this.getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel()
{
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
Font f = new Font("Arial",Font.PLAIN,24);
g2d.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setColor(Color.white);
g2d.fillRect(0,0,getWidth(),getHeight());
//
// Scale user space so "1.0 units" equals about 1 inch
//
g2d.scale(SCALE,SCALE);
g2d.setColor(Color.black);
//
// This is just a trick to create a "24 point font" in our user
// space. Since it's less than 1 we can't use the old
fashioned way
// using an integer.
//
f = f.deriveFont((float)(24.0 / SCALE));
g2d.setFont(f);
FontRenderContext frc = g2d.getFontRenderContext();
System.out.println("usesFractionalMetrics=" +
frc.usesFractionalMetrics());
TextLayout tl = new TextLayout("TextLayout ", f, frc);
//
// Draw about 1 inch over, 1 inch down
//
tl.draw(g2d, (float)1.0, (float)1.0);
//
// The font appears at the right place and at the right size.
// But all of the line metrics are wrong, which makes doing
// multi-line text impossible (since you don't know how
// far down to position the next line.)
//
System.out.println("TextLayout");
System.out.println(" tl.Ascent=" + tl.getAscent());
System.out.println(" tl.Descent=" + tl.getDescent());
System.out.println(" tl.Leading=" + tl.getLeading());
System.out.println(" tl.Bounds=" + tl.getBounds());
//
// Let's just try something simpler; use drawString
//
//
// Draw about 1 inch over, 2 inches down
//
g2d.drawString("drawString", (float)1.0, (float)2.0);
//
// This comes out as we expect (.24)
//
System.out.println("font.size2d=" + f.getSize2D());
//
// This is wrong
//
Rectangle2D r = f.getStringBounds("drawString",frc);
System.out.println("r2d.Bounds=" + r);
//
// And this is wrong
//
r = f.getMaxCharBounds(frc);
System.out.println("r2d.MaxBounds=" + r);
//
// And this is wrong
//
LineMetrics lm = f.getLineMetrics("drawString",frc);
System.out.println("LineMetrics");
System.out.println(" lm.Ascent=" + lm.getAscent());
System.out.println(" lm.Descent=" + lm.getDescent());
System.out.println(" lm.Leading=" + lm.getLeading());
//
// And this is wrong too
//
FontMetrics fm = g2d.getFontMetrics();
System.out.println("FontMetrics");
System.out.println(" fm.Ascent=" + fm.getAscent());
System.out.println(" fm.Descent=" + fm.getDescent());
System.out.println(" fm.Leading=" + fm.getLeading());
}
};
this.getContentPane().add("Center", panel);
this.addWindowListener(listener);
this.pack();
this.setSize(400,300);
this.show();
}
public static void main(String argv[])
{
FontTest ft = new FontTest();
}
}
(Review ID: 134618)
======================================================================
- relates to
-
JDK-6313761 FontMetrics.getStringBounds() floating point overflow problems
-
- Closed
-