Hi,

I committed this patch to HEAD.  The font metrics we were returning were
larger than the ones Sun returns.  This caused problems for applets that
rely on font metrics for positioning text correctly.  With this patch we
now approximate Sun's metrics within a two pixel tolerance.  I added
gnu.testlet.java.awt.FontMetrics.TestLogicalFontMetrics to show this.
Before this patch, it had 1484 failures.  After the patch it has 118
failures (caused by Monospaced fonts).  I'll fix these failures in a
separate patch.

Tom

2006-03-16  Thomas Fitzsimmons  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/gtk/GdkFontMetrics.java (getLeading): Always
        return 0.
        * gnu/java/awt/peer/gtk/GdkFontPeer.java (getFontMetrics): Get
        font metrics through toolkit.
        * gnu/java/awt/peer/gtk/GdkGraphics.java (getFontMetrics):
        Likewise.
        * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c
        (getFontMetrics): To calculate Java logical ascent and descent
        values, average Pango ink and logical values.

Index: gnu/java/awt/peer/gtk/GdkFontMetrics.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java,v
retrieving revision 1.15
diff -u -r1.15 GdkFontMetrics.java
--- gnu/java/awt/peer/gtk/GdkFontMetrics.java	30 Sep 2005 09:58:31 -0000	1.15
+++ gnu/java/awt/peer/gtk/GdkFontMetrics.java	16 Mar 2006 20:19:08 -0000
@@ -110,14 +110,10 @@
     return stringWidth (new String (data, off, len));
   }
 
-  /* 
-     Sun's Motif implementation always returns 0 or 1 here (???), but
-     going by the X11 man pages, it seems as though we should return
-     font.ascent + font.descent.
-  */
   public int getLeading ()
   {
-    return 1;
+    // Sun always returns 0.
+    return 0;
   }
 
   public int getAscent ()
Index: gnu/java/awt/peer/gtk/GdkFontPeer.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java,v
retrieving revision 1.7
diff -u -r1.7 GdkFontPeer.java
--- gnu/java/awt/peer/gtk/GdkFontPeer.java	2 Jul 2005 20:32:11 -0000	1.7
+++ gnu/java/awt/peer/gtk/GdkFontPeer.java	16 Mar 2006 20:19:08 -0000
@@ -43,6 +43,7 @@
 
 import java.awt.Font;
 import java.awt.FontMetrics;
+import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.font.LineMetrics;
@@ -301,7 +302,9 @@
 
   public FontMetrics getFontMetrics (Font font)
   {
-    return new GdkFontMetrics (font);
+    // Get the font metrics through GtkToolkit to take advantage of
+    // the metrics cache.
+    return Toolkit.getDefaultToolkit().getFontMetrics (font);
   }
 
 }
Index: gnu/java/awt/peer/gtk/GdkGraphics.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java,v
retrieving revision 1.53
diff -u -r1.53 GdkGraphics.java
--- gnu/java/awt/peer/gtk/GdkGraphics.java	14 Dec 2005 21:33:38 -0000	1.53
+++ gnu/java/awt/peer/gtk/GdkGraphics.java	16 Mar 2006 20:19:08 -0000
@@ -48,6 +48,7 @@
 import java.awt.Image;
 import java.awt.Rectangle;
 import java.awt.Shape;
+import java.awt.Toolkit;
 import java.awt.image.ImageObserver;
 import java.text.AttributedCharacterIterator;
 
@@ -373,7 +374,9 @@
 
   public FontMetrics getFontMetrics (Font font)
   {
-    return new GdkFontMetrics (font);
+    // Get the font metrics through GtkToolkit to take advantage of
+    // the metrics cache.
+    return Toolkit.getDefaultToolkit().getFontMetrics (font);
   }
 
   native void setClipRectangle (int x, int y, int width, int height);
Index: native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c,v
retrieving revision 1.12
diff -u -r1.12 gnu_java_awt_peer_gtk_GdkFontPeer.c
--- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c	18 Nov 2005 21:05:06 -0000	1.12
+++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c	16 Mar 2006 20:19:08 -0000
@@ -239,6 +239,17 @@
   struct peerfont *pfont = NULL;
   jdouble *native_metrics = NULL;
   PangoFontMetrics *pango_metrics = NULL;
+  PangoLayout* layout = NULL;
+  PangoRectangle ink_rect;
+  PangoRectangle logical_rect;
+  PangoLayoutIter* iter = NULL;
+  int pango_ascent = 0;
+  int pango_descent = 0;
+  int pango_ink_ascent = 0;
+  int pango_ink_descent = 0;
+  int baseline = 0;
+  int java_ascent = 0;
+  int java_descent = 0;
 
   gdk_threads_enter();
 
@@ -254,21 +265,46 @@
 
   g_assert (native_metrics != NULL);
 
-  native_metrics[FONT_METRICS_ASCENT] 
-    = PANGO_PIXELS (pango_font_metrics_get_ascent (pango_metrics));
+  pango_ascent = PANGO_PIXELS (pango_font_metrics_get_ascent (pango_metrics));
+  pango_descent = PANGO_PIXELS (pango_font_metrics_get_descent (pango_metrics));
 
-  native_metrics[FONT_METRICS_MAX_ASCENT] 
-    = native_metrics[FONT_METRICS_ASCENT];
+  layout = pango_layout_new (pfont->ctx);
 
-  native_metrics[FONT_METRICS_DESCENT] 
-    = PANGO_PIXELS (pango_font_metrics_get_descent (pango_metrics));
+  /* Pango seems to produce ascent and descent values larger than
+     those that Sun produces for the same-sized font.  It turns out
+     that an average of the "ink ascent" and "logical ascent" closely
+     approximates Sun's ascent values.  Likewise for descent values.
+     This is expensive but we cache GdkFontMetrics so this should only
+     run once per Font instance. */
+  pango_layout_set_text (layout, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
+                         "MNOPQRSTUVWXYZ0123456789", -1);
+  pango_layout_set_font_description (layout, pfont->desc);
 
-  if (native_metrics[FONT_METRICS_DESCENT] < 0)
-    native_metrics[FONT_METRICS_DESCENT] 
-      = - native_metrics[FONT_METRICS_DESCENT];
+  pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
 
-  native_metrics[FONT_METRICS_MAX_DESCENT] 
-    = native_metrics[FONT_METRICS_DESCENT];
+  iter = pango_layout_get_iter (layout);
+
+  baseline = PANGO_PIXELS (pango_layout_iter_get_baseline (iter));
+
+  pango_ink_ascent = baseline - ink_rect.y;
+  pango_ink_descent = ink_rect.y + ink_rect.height - baseline;
+
+  java_ascent = (pango_ascent + pango_ink_ascent) >> 1;
+  java_descent = (pango_descent + pango_ink_descent) >> 1;
+
+  java_ascent = MAX(0, java_ascent);
+  java_descent = MAX(0, java_descent);
+
+  pango_ascent = MAX(0, pango_ascent);
+  pango_descent = MAX(0, pango_descent);
+
+  native_metrics[FONT_METRICS_ASCENT] = java_ascent;
+
+  native_metrics[FONT_METRICS_MAX_ASCENT] = pango_ascent;
+
+  native_metrics[FONT_METRICS_DESCENT] = java_descent;
+
+  native_metrics[FONT_METRICS_MAX_DESCENT] = pango_descent;
 
   native_metrics[FONT_METRICS_MAX_ADVANCE] 
     = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width 

Reply via email to