Incorrect Font Metrics When Anti-Aliasing On

(Apple bug # 3202959)

    The applet above uses a custom component on which text ending in the word "Canvas" is displayed.  On 1.4.x with the Apple system property apple.awt.textantialiasing turned on, the length of the text is computed wrong and the text is cut off.  All is OK on other environments such as 1.3.1 (MRJ 3.3) and the Sun and Microsoft JREs on Windows.

    One might imagine that the behavior of the applet is OK when apple.awt.textantialiasing is off.  For that reason this test applet pops up a certificate asking for trust to check this property and displays its value.  (The class files are also included for environments in which a Sun-signed JAR file does no good.)  However, as demonstrated by the applet at this link setting apple.awt.textantialiasing to off (or false) does not fix the problem.

    The applet on this page also demonstrates that FontMetrics returns different lengths for this text in different environments, as illustrated in the table:

Environment   Width from FontMetrics
     
Windows   583
Mac OS X JRE 1.4.1   583
Mac OS X JRE 1.3.1   556
Mac OS 9 MRJ 2.2.5   599

    If you have any insights, workarounds or comments about this test page please contact Mickey Segal.  A listing of  many Java resources is at this link.

Source code:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class font_measure extends Applet implements ActionListener {

LabelCanvas myLabel;
Button b;
int canvasHeight = 30;

public void init() 
{
    setBackground(new Color(240, 225, 255));
    myLabel = new LabelCanvas("Text should just fit horizontally on the Canvas");
    myLabel.setBackground(Color.cyan);
    add(myLabel);
    b = new Button(getButtonLabel());
    b.addActionListener(this);
    add(b);
    invalidate();
    validate();
}

String getButtonLabel()
{
    return("Canvas height " + canvasHeight);
}

public void actionPerformed(ActionEvent ae)
{
    if (ae.getSource() == b)
    {
        canvasHeight--;
        if (canvasHeight < 10) canvasHeight = 40;
        b.setLabel(getButtonLabel());
        myLabel.setHeight(canvasHeight);
        myLabel.invalidate();
        invalidate();
        validate();
    }
}

public final void paint(Graphics g)
{
    g.drawString("width of box = " + myLabel.width, 10, getSize().height - 25);
    g.drawString("Property apple.awt.textantialiasing = " + System.getProperty("apple.awt.textantialiasing"),
        10, getSize().height - 5);

} // END OF Class font_measure



class LabelCanvas extends Canvas { 

int height;
int width;
Font f;
String label;
boolean needToResetWidth;

LabelCanvas(String label)
{
    this.label = label;
    f = new Font("Serif", Font.BOLD, 30);
    height = 30;
    needToResetWidth = true;
}

void setWidth(Graphics g)
{
    g.setFont(f);
    FontMetrics fm = g.getFontMetrics();
    width = fm.stringWidth(label);
    needToResetWidth = false; 
}

void setHeight(int h)
{
    height = h;
    repaint();
}

public void addNotify()
{
    super.addNotify();
    repaint();
}

public final void paint(Graphics g)
{
    g.setFont(f);
    if (needToResetWidth) setWidth(g);
    g.drawString(label, 0, height - 5);


public final Dimension getMinimumSize()
{
    if (needToResetWidth)
    {
        Graphics g = getGraphics();
        setWidth(g);
        g.dispose();
    }
    return (new Dimension(width, height));
}

public final Dimension getPreferredSize()
{
    return(getMinimumSize());
}

public final void update(Graphics g)
{
    paint(g);
}
} // END OF Class LabelCanvas