JDK-6623223 : java.awt.FontMetrics getAscent() returns getMaxAscent()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-10-29
  • Updated: 2012-01-16
Description
FULL PRODUCT VERSION :
1.6.0_02

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

A DESCRIPTION OF THE PROBLEM :
FontMetrics getFontAscent is supposed to return a smaller number than getMaxAscent. A label's default size is a height from the descent line to the max-ascent line (if you make the label opaque, give it a background color and place in in a container where it can adopt its preferred size you can see it). Someimtes you know you are only going to use cetain characters and want to base the height of the label on the normal ascent, not the max ascent. I have to hack it by subtracing the descent (plus leading) from the max ascent, which gives the right number for most popular fonts.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this:

package scratch;

import javax.swing.*;
import java.awt.*;

public class MainFont {
  public static void main(String[] args) {
    GraphicsEnvironment gEnv = GraphicsEnvironment
            .getLocalGraphicsEnvironment();
    String envfonts[] = gEnv.getAvailableFontFamilyNames();

    JLabel c = new JLabel();
    for (String fontName : envfonts) {
      for (int size = 0; size < 151; size++) {
        Font f = new Font(fontName, Font.PLAIN, size);
        FontMetrics fm = c.getFontMetrics(f);
        if (fm.getMaxAscent() - fm.getAscent() != 0) {
          System.out.println(fontName);
        }
      }
    }

  }
}


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
For almost all fonts, the name should be printed out almost 150 times, because the maximum ascent should differ from the ascent for most sizes of most fonts.
ACTUAL -
Not one font name will be printed to system.out, because for every font (260 on my system) and every size from 1 to 150, getAscent returns the same number as getMaxAscent.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
not applicable

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package scratch;

import javax.swing.*;
import java.awt.*;

public class MainFont {
  public static void main(String[] args) {
    GraphicsEnvironment gEnv = GraphicsEnvironment
            .getLocalGraphicsEnvironment();
    String envfonts[] = gEnv.getAvailableFontFamilyNames();

    JLabel c = new JLabel();
    for (String fontName : envfonts) {
      for (int size = 0; size < 151; size++) {
        Font f = new Font(fontName, Font.PLAIN, size);
        FontMetrics fm = c.getFontMetrics(f);
        if (fm.getMaxAscent() - fm.getAscent() != 0) {
          System.out.println(fontName);
        }
      }
    }

  }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Create a utility like this, and use it to get the (probable) real ascent.

import java.awt.*;

public class TextUtil {
  public static int getRealAscent(Component c) {
    FontMetrics metrics = c.getFontMetrics(c.getFont());
    /* Note: there seems to be a bug whereby getAscent returns getMaxAscent, which seems to mostly equal ascent + descent + leading*/

    return metrics.getAscent()-metrics.getDescent()-metrics.getLeading();
  }
}

Comments
EVALUATION This has always been true, even as far back as JDK 1.0. Looking at the windows platform the GDI TEXTMETRIC structure was used to retrieve a single value used for both. Since JDK 1.2, for the same TrueType fonts, the value has been retrieved from the 'hhea' table's 'ascent' field. So if this were a problem for a lot of people I'd have expected someone to complain about this before, but I can't find another report. Ideally JDK 1.2 should have used the OS/2 table value for usWinAscent, or perhaps sTypoAscender (so there's at least three choices here, see http://www.microsoft.com/typography/otspec/recom.htm#tad for more info). For max ascent we could use the yMax field in the font header. In most fonts I think this is equivalent to the value we retrieve from the hhea table, hence the observation that both methods return the max ascent. But this would have consequences for applications which laid out their UI based on ascent - which is a component of font.getHeight(). Its very likely that some apps would find their windows to be lesser in height, and that icons are no longer aligned to expected sizes of text fields. So I'm not at all sure we can change this.
30-10-2007