shithub: freetype+ttf2subf

Download patch

ref: 4694ea2b9519d8128cfdc537629c292fc9d627f3
parent: 03e8b2f763ea0368e714345d98c534226915adc6
author: Bram Tassyns <[email protected]>
date: Wed Sep 2 09:06:33 EDT 2009

Improve vertical metrics calculation (Savannah bug #27364).

The calculation of `vertBearingX' is not defined in the OTF font
spec so FreeType does a `best effort' attempt.  However, this value
is defined in the PDF and PostScript specs, and that algorithm is
better than the one FreeType currently uses:

  FreeType: Use the middle of the bounding box as the X coordinate
            of the vertical origin.

  Adobe PDF spec: Use the middle of the horizontal advance vector as
                  the X coordinate of the vertical origin.

FreeType's algorithm goes wrong if you have a really small glyph
(like the full-width, circle-like dot at the end of the sentence, as
used in CJK scripts) with large bearings.  With the FreeType
algorithm this dot gets centered on the baseline; with the PDF
algorithm it gets the correct location (in the top right).  Note
that this is a serious issue, it's like printing the dot at the end
of a Roman sentence at the center of the textline instead of on the
baseline like it should. So i believe the PDF spec's algorithm
should be used in FreeType as well.

The `vertBearingY' value for such small glyphs is also very strange
if no `vmtx' information is present, since the height of the bbox is
not representable for the height of the glyph visually (the
whitespace up to the baseline is part of the glyph).  The fix also
includes some code for a better estimate of `vertBearingY'.

* src/base/ftobjs.c (ft_synthesize_vertical_metrics): `vertBearingX'
is now calculated as described by the Adobe PDF Spec.  Estimate for
`vertBearingY' now works better for small glyphs completely above or
below the baseline into account.

* src/cff/cffgload.c (cff_slot_load): `vertBearingX' is now
calculated as described by the Adobe PDF Spec.  Vertical metrics
information was always ignored when FT_CONFIG_OPTION_OLD_INTERNALS
was not defined.

* src/truetype/ttgload.c (compute_glyph_metrics): `vertBearingX' is
now calculated as described by the Adobe PDF Spec.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+2009-09-02  Bram Tassyns  <[email protected]>
+
+	Improve vertical metrics calculation (Savannah bug #27364).
+
+	The calculation of `vertBearingX' is not defined in the OTF font
+	spec so FreeType does a `best effort' attempt.  However, this value
+	is defined in the PDF and PostScript specs, and that algorithm is
+	better than the one FreeType currently uses:
+
+	  FreeType: Use the middle of the bounding box as the X coordinate
+	            of the vertical origin.
+
+	  Adobe PDF spec: Use the middle of the horizontal advance vector as
+	                  the X coordinate of the vertical origin.
+
+	FreeType's algorithm goes wrong if you have a really small glyph
+	(like the full-width, circle-like dot at the end of the sentence, as
+	used in CJK scripts) with large bearings.  With the FreeType
+	algorithm this dot gets centered on the baseline; with the PDF
+	algorithm it gets the correct location (in the top right).  Note
+	that this is a serious issue, it's like printing the dot at the end
+	of a Roman sentence at the center of the textline instead of on the
+	baseline like it should. So i believe the PDF spec's algorithm
+	should be used in FreeType as well.
+
+	The `vertBearingY' value for such small glyphs is also very strange
+	if no `vmtx' information is present, since the height of the bbox is
+	not representable for the height of the glyph visually (the
+	whitespace up to the baseline is part of the glyph).  The fix also
+	includes some code for a better estimate of `vertBearingY'.
+
+	* src/base/ftobjs.c (ft_synthesize_vertical_metrics): `vertBearingX'
+	is now calculated as described by the Adobe PDF Spec.  Estimate for
+	`vertBearingY' now works better for small glyphs completely above or
+	below the baseline into account.
+
+	* src/cff/cffgload.c (cff_slot_load): `vertBearingX' is now
+	calculated as described by the Adobe PDF Spec.  Vertical metrics
+	information was always ignored when FT_CONFIG_OPTION_OLD_INTERNALS
+	was not defined.
+
+	* src/truetype/ttgload.c (compute_glyph_metrics): `vertBearingX' is
+	now calculated as described by the Adobe PDF Spec.
+
 2009-09-01  John Tytgat <[email protected]>
 
 	Fix custom cmap for empty Type 1 font (Savannah bug #27294).
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -2404,12 +2404,24 @@
   ft_synthesize_vertical_metrics( FT_Glyph_Metrics*  metrics,
                                   FT_Pos             advance )
   {
+    FT_Pos  height = metrics->height;
+
+
+    /* compensate for glyph with bbox above/below the baseline */
+    if ( metrics->horiBearingY < 0 )
+    {
+      if ( height < metrics->horiBearingY )
+        height = metrics->horiBearingY;
+    }
+    else if ( metrics->horiBearingY > 0 )
+      height -= metrics->horiBearingY;
+
     /* the factor 1.2 is a heuristical value */
     if ( !advance )
-      advance = metrics->height * 12 / 10;
+      advance = height * 12 / 10;
 
-    metrics->vertBearingX = -( metrics->width / 2 );
-    metrics->vertBearingY = ( advance - metrics->height ) / 2;
+    metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
+    metrics->vertBearingY = ( advance - height ) / 2;
     metrics->vertAdvance  = advance;
   }
 
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -2726,9 +2726,14 @@
         glyph->root.linearHoriAdvance           = decoder.glyph_width;
         glyph->root.internal->glyph_transformed = 0;
 
+#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
         has_vertical_info = FT_BOOL( face->vertical_info                   &&
                                      face->vertical.number_Of_VMetrics > 0 &&
                                      face->vertical.long_metrics           );
+#else
+        has_vertical_info = FT_BOOL( face->vertical_info                   &&
+                                     face->vertical.number_Of_VMetrics > 0 );
+#endif
 
         /* get the vertical metrics from the vtmx table if we have one */
         if ( has_vertical_info )
@@ -2819,7 +2824,8 @@
         metrics->horiBearingY = cbox.yMax;
 
         if ( has_vertical_info )
-          metrics->vertBearingX = -metrics->width / 2;
+          metrics->vertBearingX = metrics->horiBearingX -
+                                    metrics->horiAdvance / 2;
         else
           ft_synthesize_vertical_metrics( metrics,
                                           metrics->vertAdvance );
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -1594,10 +1594,28 @@
     glyph->metrics.horiBearingY = bbox.yMax;
     glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;
 
-    /* Now take care of vertical metrics.  In the case where there is    */
-    /* no vertical information within the font (relatively common), make */
-    /* up some metrics by `hand'...                                      */
+    /* adjust advance width to the value contained in the hdmx table */
+    if ( !face->postscript.isFixedPitch  &&
+         IS_HINTED( loader->load_flags ) )
+    {
+      FT_Byte*  widthp;
 
+
+      widthp = tt_face_get_device_metrics( face,
+                                           size->root.metrics.x_ppem,
+                                           glyph_index );
+
+      if ( widthp )
+        glyph->metrics.horiAdvance = *widthp << 6;
+    }
+
+    /* set glyph dimensions */
+    glyph->metrics.width  = bbox.xMax - bbox.xMin;
+    glyph->metrics.height = bbox.yMax - bbox.yMin;
+
+    /* Now take care of vertical metrics.  In the case where there is */
+    /* no vertical information within the font (relatively common),   */
+    /* create some metrics manually                                   */
     {
       FT_Pos  top;      /* scaled vertical top side bearing  */
       FT_Pos  advance;  /* scaled vertical advance height    */
@@ -1686,30 +1704,12 @@
       /* XXX: for now, we have no better algorithm for the lsb, but it */
       /*      should work fine.                                        */
       /*                                                               */
-      glyph->metrics.vertBearingX = ( bbox.xMin - bbox.xMax ) / 2;
+      glyph->metrics.vertBearingX = glyph->metrics.horiBearingX -
+                                      glyph->metrics.horiAdvance / 2;
       glyph->metrics.vertBearingY = top;
       glyph->metrics.vertAdvance  = advance;
     }
 
-    /* adjust advance width to the value contained in the hdmx table */
-    if ( !face->postscript.isFixedPitch  &&
-         IS_HINTED( loader->load_flags ) )
-    {
-      FT_Byte*  widthp;
-
-
-      widthp = tt_face_get_device_metrics( face,
-                                           size->root.metrics.x_ppem,
-                                           glyph_index );
-
-      if ( widthp )
-        glyph->metrics.horiAdvance = *widthp << 6;
-    }
-
-    /* set glyph dimensions */
-    glyph->metrics.width  = bbox.xMax - bbox.xMin;
-    glyph->metrics.height = bbox.yMax - bbox.yMin;
-
     return 0;
   }
 
@@ -2013,7 +2013,7 @@
             break;
           }
         }
-        else 
+        else
           glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
       }