Commit 5cd21551131ef3a9690ecbefcc9782286ee5199e

Werner Lemberg 2015-04-10T07:01:01

[cff] Update advance width handling to OpenType 1.7. Problem reported by Behdad. * src/cff/cffdrivr.c (cff_get_advances): Handle SFNT case separately. * src/cff/cffgload.c (cff_slot_load): Use advance width and side bearing values from `hmtx' table if present.

diff --git a/ChangeLog b/ChangeLog
index 985a889..ad0c031 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2015-04-10  Werner Lemberg  <wl@gnu.org>
+
+	[cff] Update advance width handling to OpenType 1.7.
+
+	Problem reported by Behdad.
+
+	* src/cff/cffdrivr.c (cff_get_advances): Handle SFNT case
+	separately.
+
+	* src/cff/cffgload.c (cff_slot_load): Use advance width and side
+	bearing values from `hmtx' table if present.
+
 2015-04-03  Alexei Podtelezhnikov <apodtele@gmail.com>
 
 	* src/autofit/afhints.c (af_glyph_hints_reload): Use do-while loop.
diff --git a/include/internal/tttypes.h b/include/internal/tttypes.h
index 1d442f7..31dd0aa 100644
--- a/include/internal/tttypes.h
+++ b/include/internal/tttypes.h
@@ -1111,7 +1111,7 @@ FT_BEGIN_HEADER
   /*                            This field also contains the associated    */
   /*                            vertical metrics table (`vmtx'), if found. */
   /*                            IMPORTANT: The contents of this field is   */
-  /*                            undefined if the `verticalInfo' field is   */
+  /*                            undefined if the `vertical_info' field is  */
   /*                            unset.                                     */
   /*                                                                       */
   /*    num_names            :: The number of name records within this     */
diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c
index 35e23b9..f46a1c5 100644
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -195,6 +195,68 @@
     FT_GlyphSlot  slot  = face->glyph;
 
 
+    if ( FT_IS_SFNT( face ) )
+    {
+      /* OpenType 1.7 mandates that the data from `hmtx' table be used; */
+      /* it is no longer necessary that those values are identical to   */
+      /* the values in the `CFF' table                                  */
+
+      TT_Face   ttface = (TT_Face)face;
+      FT_Short  dummy;
+
+
+      if ( flags & FT_LOAD_VERTICAL_LAYOUT )
+      {
+        /* check whether we have data from the `vmtx' table at all; */
+        /* otherwise we extract the info from the CFF glyphstrings  */
+        /* (instead of synthesizing a global value using the `OS/2' */
+        /* table)                                                   */
+        if ( !ttface->vertical_info )
+          goto Missing_Table;
+
+        for ( nn = 0; nn < count; nn++ )
+        {
+          FT_UShort  ah;
+
+
+          ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
+                                                       1,
+                                                       start + nn,
+                                                       &dummy,
+                                                       &ah );
+
+          FT_TRACE5(( "  idx %d: advance height %d font units\n",
+                      start + nn, ah ));
+          advances[nn] = ah;
+        }
+      }
+      else
+      {
+        /* check whether we have data from the `hmtx' table at all */
+        if ( !ttface->horizontal.number_Of_HMetrics )
+          goto Missing_Table;
+
+        for ( nn = 0; nn < count; nn++ )
+        {
+          FT_UShort  aw;
+
+
+          ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
+                                                       0,
+                                                       start + nn,
+                                                       &dummy,
+                                                       &aw );
+
+          FT_TRACE5(( "  idx %d: advance width %d font units\n",
+                      start + nn, aw ));
+          advances[nn] = aw;
+        }
+      }
+
+      return error;
+    }
+
+  Missing_Table:
     flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
 
     for ( nn = 0; nn < count; nn++ )
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index b5bc4a2..d731387 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -2725,7 +2725,7 @@
                                 face->vertical_info                   &&
                                 face->vertical.number_Of_VMetrics > 0 );
 
-          /* get the vertical metrics from the vtmx table if we have one */
+          /* get the vertical metrics from the vmtx table if we have one */
           if ( has_vertical_info )
           {
             (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
@@ -2953,25 +2953,43 @@
         FT_Bool            has_vertical_info;
 
 
-        /* copy the _unscaled_ advance width */
-        metrics->horiAdvance                    = decoder.glyph_width;
-        glyph->root.linearHoriAdvance           = decoder.glyph_width;
+        if ( face->horizontal.number_Of_HMetrics )
+        {
+          FT_Short   horiBearingX = 0;
+          FT_UShort  horiAdvance  = 0;
+
+
+          ( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
+                                                     glyph_index,
+                                                     &horiBearingX,
+                                                     &horiAdvance );
+          metrics->horiAdvance          = horiAdvance;
+          metrics->horiBearingX         = horiBearingX;
+          glyph->root.linearHoriAdvance = horiAdvance;
+        }
+        else
+        {
+          /* copy the _unscaled_ advance width */
+          metrics->horiAdvance          = decoder.glyph_width;
+          glyph->root.linearHoriAdvance = decoder.glyph_width;
+        }
+
         glyph->root.internal->glyph_transformed = 0;
 
         has_vertical_info = FT_BOOL( face->vertical_info                   &&
                                      face->vertical.number_Of_VMetrics > 0 );
 
-        /* get the vertical metrics from the vtmx table if we have one */
+        /* get the vertical metrics from the vmtx table if we have one */
         if ( has_vertical_info )
         {
           FT_Short   vertBearingY = 0;
           FT_UShort  vertAdvance  = 0;
 
 
-          (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
-                                                           glyph_index,
-                                                           &vertBearingY,
-                                                           &vertAdvance );
+          ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+                                                     glyph_index,
+                                                     &vertBearingY,
+                                                     &vertAdvance );
           metrics->vertBearingY = vertBearingY;
           metrics->vertAdvance  = vertAdvance;
         }
@@ -3046,7 +3064,9 @@
         metrics->width  = cbox.xMax - cbox.xMin;
         metrics->height = cbox.yMax - cbox.yMin;
 
-        metrics->horiBearingX = cbox.xMin;
+        if ( !face->horizontal.number_Of_HMetrics )
+          metrics->horiBearingX = cbox.xMin;
+
         metrics->horiBearingY = cbox.yMax;
 
         if ( has_vertical_info )