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

Bad Font Metrics returned (ascent, descent) when using scaled fonts in Java2D

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 1.4.0
    • client-libs
    • 2d
    • 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)
      ======================================================================

            dougfelt Doug Felt
            gmanwanisunw Girish Manwani (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: