Commit a6feefdfefd6eb8e62728f40638241bb1d8c993e

Nikolaus Waxweiler 2019-02-02T15:50:57

[truetype] Apply MVAR hasc, hdsc and hlgp metrics to current FT_Face metrics. Instead of setting typo or win metrics as the new FT_Face metrics indiscriminately, apply only typo deltas to the currently active FT_Face metrics. This prevents line height differences when e.g. the default outlines were used as the regular face and instances for everything else. * src/truetype/ttgxvar.c (tt_apply_mvar): Implement.

diff --git a/ChangeLog b/ChangeLog
index aac45a4..870972c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2019-02-02  Nikolaus Waxweiler  <madigens@gmail.com>
 
+	[truetype] Apply MVAR hasc, hdsc and hlgp metrics to current FT_Face metrics.
+
+	Instead of setting typo or win metrics as the new FT_Face metrics
+	indiscriminately, apply only typo deltas to the currently active FT_Face
+	metrics. This prevents line height differences when e.g. the default
+	outlines were used as the regular face and instances for everything else.
+
+	* src/truetype/ttgxvar.c (tt_apply_mvar): Implement.
+
+2019-02-02  Nikolaus Waxweiler  <madigens@gmail.com>
+
 	[sfnt] Use typo metrics if OS/2 fsSelection USE_TYPO_METRICS bit is set.
 
 	If the OS/2 table exists and fsSelection bit 7 (USE_TYPO_METRICS) is set,
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index a2e6dd1..787d686 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -1325,6 +1325,9 @@
   {
     GX_Blend  blend = face->blend;
     GX_Value  value, limit;
+    FT_Short  mvar_hasc_delta = 0;
+    FT_Short  mvar_hdsc_delta = 0;
+    FT_Short  mvar_hlgp_delta = 0;
 
 
     if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
@@ -1359,6 +1362,14 @@
         /* since we handle both signed and unsigned values as FT_Short, */
         /* ensure proper overflow arithmetic                            */
         *p = (FT_Short)( value->unmodified + (FT_Short)delta );
+
+        /* Treat hasc, hdsc and hlgp specially, see below. */
+        if ( value->tag == MVAR_TAG_HASC )
+          mvar_hasc_delta = (FT_Short)delta;
+        else if ( value->tag == MVAR_TAG_HDSC )
+          mvar_hdsc_delta = (FT_Short)delta;
+        else if ( value->tag == MVAR_TAG_HLGP )
+          mvar_hlgp_delta = (FT_Short)delta;
       }
     }
 
@@ -1366,25 +1377,38 @@
     {
       FT_Face  root = &face->root;
 
-
-      if ( face->os2.version != 0xFFFFU )
-      {
-        if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
-        {
-          root->ascender  = face->os2.sTypoAscender;
-          root->descender = face->os2.sTypoDescender;
-
-          root->height = root->ascender - root->descender +
-                         face->os2.sTypoLineGap;
-        }
-        else
-        {
-          root->ascender  =  (FT_Short)face->os2.usWinAscent;
-          root->descender = -(FT_Short)face->os2.usWinDescent;
-
-          root->height = root->ascender - root->descender;
-        }
-      }
+      /*
+       * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
+       * descender and height attributes, no matter how they were originally
+       * computed.
+       *
+       * (Code that ignores those and accesses the font's metrics values
+       * directly is already served by the delta application code above.)
+       *
+       * The MVAR table supports variations for both typo and win metrics.
+       * According to Behdad Esfahbod, the thinking of the working group was
+       * that no one uses win metrics anymore for setting line metrics (the
+       * specification even calls these metrics "horizontal clipping
+       * ascent/descent", probably for their role on the Windows platform in
+       * computing clipping boxes), and new fonts should use typo metrics, so
+       * typo deltas should be applied to whatever sfnt_load_face decided the
+       * line metrics should be.
+       *
+       * Before, the following led to different line metrics between default
+       * outline and instances, visible when e.g. the default outlines were
+       * used as the regular face and instances for everything else:
+       *
+       * 1. sfnt_load_face applied the hhea metrics by default.
+       * 2. This code later applied the typo metrics by default, regardless of
+       *    whether they were actually changed or the font had the OS/2 table's
+       *    fsSelection's bit 7 (USE_TYPO_METRICS) set.
+       */
+      FT_Short  current_line_gap = root->height - root->ascender +
+                                   root->descender;
+      root->ascender  = root->ascender + mvar_hasc_delta;
+      root->descender = root->descender + mvar_hdsc_delta;
+      root->height    = root->ascender - root->descender +
+                        current_line_gap + mvar_hlgp_delta;
 
       root->underline_position  = face->postscript.underlinePosition -
                                   face->postscript.underlineThickness / 2;