JDK-6313761 : FontMetrics.getStringBounds() floating point overflow problems
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_xp
  • CPU: itanium
  • Submitted: 2005-08-20
  • Updated: 2017-09-08
  • Resolved: 2017-09-08
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_04-b05)
Java HotSpot(TM) Client VM (build 1.5.0_04-b05, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
There seems to be a pretty serious bug in FontMetrics.getStringBounds() whereby the font width will keep on increasing as the font size grows but then all of a sudden on larger values it'll shrink. I'm expecting the font width to always get bigger as the font size increases. Here are two data points that show what I'm seeing...

java.awt.Font[family=Georgia,name=Georgia,style=bold,size=268435488]
\-> width("SAMPLE")=145

java.awt.Font[family=Georgia,name=Georgia,style=bold,size=134217776]
\-> width("SAMPLE")=218

Notice how the text width grows as the font size shrinks.

This is a serious problem for me because I'm trying to programmatically detect what font size (in point units) will produce a certain text width (in pixel units). I can't use a binary search algorithm with the above bug.


REPRODUCIBILITY :
This bug can be reproduced always.
The submitter provided this additional information

import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;

public class FontMetricsBug
{
   public static void main(String[] args)
   {
     Font bigFont = new Font("Times New Roman", Font.PLAIN, 268435488);
     Font smallFont = new Font("Times New Roman", Font.PLAIN, 134217776);
     JFrame frame = new JFrame();
     frame.setVisible(true);
     Graphics graphics = frame.getGraphics();
     final String text = "test";
     int bigWidth = graphics.getFontMetrics(bigFont).stringWidth(text);
     int smallWidth = graphics.getFontMetrics(smallFont).stringWidth(text);
     assert(bigWidth >= smallWidth): "bigWidth=" + bigWidth + ", 
smallWidth=" +
       smallWidth;
   }
}

	I get an output of "bigWidth=43, smallWidth=66" on my end which clearly 
indicates a problem :) Also, on a related note, I noticed that 
FontMetrics.getStringBounds() returns a Rectangle2D and then you can 
invoke Rectangle2D.getBounds() to cast the bounds from float/double into 
an int. I looked at the underlying code and there is no checking for 
overflow. Isn't it possible for an overflow to occur if the original 
coordinates were double and were being cast to an int? Should I file a 
separate issue for this? (it is somewhat related to FontMetrics and 
overflow problems)

I also see problems with the following test case:

import java.awt.*;
import java.awt.image.*;

public class FM {

    public static void main(String args[]) {
       BufferedImage bi = new BufferedImage(100,100,BufferedImage.TYPE_INT_RGB);       Graphics2D g = (Graphics2D)bi.getGraphics();

        double sf = 1;
        //double sf = 0.0000001;
        //double sf = 10000;
        g.scale(sf, sf);
        for (int i=0;i<31;i++){
            int sz = (int)Math.pow(2, i);
            Font f = new Font("Arial", Font.PLAIN, sz);
            g.setFont(f);
            FontMetrics fm = g.getFontMetrics();
            System.out.println(f.getSize() + " " + fm.stringWidth("SAMPLE") +
                                " " + fm.getStringBounds("SAMPLE", g));
        }
    }
}
% java FM
1 6 java.awt.geom.Rectangle2D$Float[x=0.0,y=-0.92163086,w=6.0,h=1.1499023]
2 7 java.awt.geom.Rectangle2D$Float[x=0.0,y=-1.8432617,w=7.0,h=2.2998047]
4 17 java.awt.geom.Rectangle2D$Float[x=0.0,y=-3.6865234,w=17.0,h=4.5996094]
8 31 java.awt.geom.Rectangle2D$Float[x=0.0,y=-7.373047,w=31.0,h=9.199219]
16 66 java.awt.geom.Rectangle2D$Float[x=0.0,y=-14.746094,w=66.0,h=18.398438]
32 129 java.awt.geom.Rectangle2D$Float[x=0.0,y=-29.492188,w=129.0,h=36.796875]
64 261 java.awt.geom.Rectangle2D$Float[x=0.0,y=-58.984375,w=261.0,h=73.59375]
128 516 java.awt.geom.Rectangle2D$Float[x=0.0,y=-117.96875,w=516.0,h=147.1875]
256 1039 java.awt.geom.Rectangle2D$Float[x=0.0,y=-235.9375,w=1039.0,h=294.375]
512 2080 java.awt.geom.Rectangle2D$Float[x=0.0,y=-471.875,w=2080.0,h=588.75]
1024 4155 java.awt.geom.Rectangle2D$Float[x=0.0,y=-943.75,w=4155.0,h=1177.5]
2048 8310 java.awt.geom.Rectangle2D$Float[x=0.0,y=-1887.5,w=8310.0,h=2355.0]
4096 16619 java.awt.geom.Rectangle2D$Float[x=0.0,y=-3775.0,w=16619.0,h=4710.0]
8192 33237 java.awt.geom.Rectangle2D$Float[x=0.0,y=-7550.0,w=33237.0,h=9420.0]
16384 66473 java.awt.geom.Rectangle2D$Float[x=0.0,y=-15100.0,w=66473.0,h=18840.0]
32768 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
65536 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
131072 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
262144 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
524288 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
1048576 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
2097152 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
4194304 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
8388608 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
16777216 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
33554432 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
67108864 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
134217728 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
268435456 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
536870912 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]
1073741824 0 java.awt.geom.Rectangle2D$Float[x=0.0,y=0.0,w=0.0,h=0.0]

Comments
This is not reproducible in jdk 9 build 181 and jdk 10. Also as Doug mentioned, it does not make sense top use fonts at this large size, a limit has already been put to the maximum point size which is 32767 (15 bit highest value). The font metrices after this point size are invalid and return everything as 0. Following is a log to prove this point. So closing it and marking not reproducible.
08-09-2017

This is not reproducible in jdk 9 build 181 and jdk 10. Also as Doug mentioned, it does not make sense top use fonts at this large size, a limit has already been put to the maximum point size which is 32767 (15 bit highest value). The font metrices after this point size are invalid and return everything as 0. Following is a log to prove this point. So closing it and marking not reproducible. big Size: 32050 bigWidth: 44508 small Size: 32000 smallWidth: 44438 big Size: 32150 bigWidth: 44646 small Size: 32100 smallWidth: 44576 big Size: 32250 bigWidth: 44784 small Size: 32200 smallWidth: 44715 big Size: 32350 bigWidth: 44923 small Size: 32300 smallWidth: 44854 big Size: 32450 bigWidth: 45063 small Size: 32400 smallWidth: 44994 big Size: 32550 bigWidth: 45200 small Size: 32500 smallWidth: 45133 big Size: 32650 bigWidth: 45340 small Size: 32600 smallWidth: 45270 big Size: 32750 bigWidth: 45479 small Size: 32700 smallWidth: 45410 big Size: 32850 bigWidth: 0 small Size: 32800 smallWidth: 0 big Size: 32950 bigWidth: 0 small Size: 32900 smallWidth: 0 big Size: 33050 bigWidth: 0 small Size: 33000 smallWidth: 0 big Size: 33150 bigWidth: 0 small Size: 33100 smallWidth: 0 big Size: 33250 bigWidth: 0 small Size: 33200 smallWidth: 0 big Size: 33350 bigWidth: 0 small Size: 33300 smallWidth: 0 big Size: 33450 bigWidth: 0 small Size: 33400 smallWidth: 0
31-08-2017

EVALUATION Any font system implementation is going to have some limits. Here the problem is that for point sizes somewhere over 16,000, the font system stops working. Note that in the sample code, this would generate a image of the sample string that was over 66,000 pixels wide. I don't see how this is an unacceptable limit. Currently, anyway, I know of no display technology that could handle strings this wide. It's not clear to me that the caller's problem really requires the implementation to support font sizes of this magnitude. Now, when you exceed its limits, the system just silently stops returning rational values, rather than throwing an exception or otherwise indicating an error. It could be argued that we should provide some way for an client to tell when the implementation's limits have been reached. I suggest that the caller limit the binary search to ranges that are smaller. Different font implementations may have different limits and we should probably not try to require them to support magnitudes larger than this. I suspect the simplest approach is to document the potential problem.
03-11-2005