v7: Clean up everything that got through the backwards compatibility mode by resetting all x-coordinates to their previous positions in
TT_Hint_Glyph(). Only do this for glyphs that are instructed, otherwise
we get garbled output.
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index bbebabd..a856fed 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -72,11 +72,10 @@
       FT_UInt*  interpreter_version = (FT_UInt*)value;
 
 
-#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( *interpreter_version != TT_INTERPRETER_VERSION_35 )
+      if ( *interpreter_version != TT_INTERPRETER_VERSION_35 &&
+           *interpreter_version != TT_INTERPRETER_VERSION_38 )
         error = FT_ERR( Unimplemented_Feature );
       else
-#endif
         driver->interpreter_version = *interpreter_version;
 
       return error;
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index 4ab6603..7689595 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -815,11 +815,26 @@
 
 #endif
 
-    /* save glyph phantom points */
-    loader->pp1 = zone->cur[zone->n_points - 4];
-    loader->pp2 = zone->cur[zone->n_points - 3];
-    loader->pp3 = zone->cur[zone->n_points - 2];
-    loader->pp4 = zone->cur[zone->n_points - 1];
+    /* Save possibly modified glyph phantom points unless in v38 backwards
+     * compatibility mode, where no movement on the X-axis means no reason to
+     * change bearings or advance widths. */
+    if ( !loader->exec->backwards_compatibility )
+    {
+      loader->pp1 = zone->cur[zone->n_points - 4];
+      loader->pp2 = zone->cur[zone->n_points - 3];
+      loader->pp3 = zone->cur[zone->n_points - 2];
+      loader->pp4 = zone->cur[zone->n_points - 1];
+    } else {
+      FT_UShort n;
+
+      /* Clean up everything that got through the backwards compatibility mode
+       * by resetting all x-coordinates to their previous positions. Only do
+       * this for glyphs that are instructed, otherwise we get garbled output.
+       */
+      if ( n_ins > 0 )
+        for ( n = 0; n < zone->n_points - 4; n++ )
+          zone->cur[n].x = zone->org[n].x;
+    }
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
@@ -1969,10 +1984,14 @@
     glyph->metrics.horiBearingY = bbox.yMax;
     glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;
 
-    /* adjust advance width to the value contained in the hdmx table */
-    /* unless FT_LOAD_COMPUTE_METRICS is set                         */
-    if ( !face->postscript.isFixedPitch                    &&
-         IS_HINTED( loader->load_flags )                   &&
+    /* Adjust advance width to the value contained in the hdmx table unless
+     * FT_LOAD_COMPUTE_METRICS is set or backwards compatibility mode of the
+     * v38 interpreter is active. Non-"native ClearType" fonts should be
+     * stopped from changing advance widths or spacing may suffer, "native
+     * ClearType" fonts are trusted to know what they're doing. */
+    if ( !( loader->exec && loader->exec->backwards_compatibility ) &&
+         !face->postscript.isFixedPitch                             &&
+         IS_HINTED( loader->load_flags )                            &&
          !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) )
     {
       FT_Byte*  widthp;
@@ -2186,6 +2205,7 @@
 
     TT_Face    face;
     FT_Stream  stream;
+    TT_Driver  driver;
 #ifdef TT_USE_BYTECODE_INTERPRETER
     FT_Bool    pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
 #endif
@@ -2193,6 +2213,7 @@
 
     face   = (TT_Face)glyph->face;
     stream = face->root.stream;
+    driver = (TT_Driver)FT_FACE_DRIVER( face );
 
     FT_MEM_ZERO( loader, sizeof ( TT_LoaderRec ) );
 
@@ -2203,6 +2224,8 @@
     {
       TT_ExecContext  exec;
       FT_Bool         grayscale;
+      FT_Bool         subpixel_hinting;
+      FT_Bool         grayscale_cleartype;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
       TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
@@ -2239,6 +2262,18 @@
       if ( !exec )
         return FT_THROW( Could_Not_Find_Context );
 
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+      {
+        subpixel_hinting = TRUE;
+        grayscale_cleartype = ! FT_BOOL( load_flags & FT_LOAD_TARGET_LCD ||
+                                         load_flags & FT_LOAD_TARGET_LCD_V );
+        exec->vertical_lcd = FT_BOOL( load_flags & FT_LOAD_TARGET_LCD_V );
+      } else {
+        subpixel_hinting = FALSE;
+        grayscale_cleartype = FALSE;
+        exec->vertical_lcd = FALSE;
+      }
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
@@ -2299,8 +2334,8 @@
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
       {
-        grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                             FT_RENDER_MODE_MONO );
+        grayscale = FT_BOOL( ! subpixel_hinting &&
+                             FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO );
       }
 
       error = TT_Load_Context( exec, face, size );
@@ -2338,6 +2373,28 @@
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
       {
+        /* a change from mono to subpixel rendering (and vice versa) */
+        /* requires a re-execution of the CVT program                */
+        if ( subpixel_hinting != exec->subpixel_hinting )
+        {
+          FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
+                      " re-executing `prep' table\n" ));
+
+          exec->subpixel_hinting = subpixel_hinting;
+          reexecute              = TRUE;
+        }
+
+        /* a change from colored to grayscale subpixel rendering (and vice
+         * versa) requires a re-execution of the CVT program               */
+        if ( grayscale_cleartype != exec->grayscale_cleartype )
+        {
+          FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
+                      " re-executing `prep' table\n" ));
+
+          exec->grayscale_cleartype = grayscale_cleartype;
+          reexecute                 = TRUE;
+        }
+
         /* a change from mono to grayscale rendering (and vice versa) */
         /* requires a re-execution of the CVT program                 */
         if ( grayscale != exec->grayscale )
diff --git a/src/truetype/ttinterp.h b/src/truetype/ttinterp.h
index e5a02b9..218aa46 100644
--- a/src/truetype/ttinterp.h
+++ b/src/truetype/ttinterp.h
@@ -247,7 +247,68 @@ FT_BEGIN_HEADER
     TT_Set_CVT_Func    func_write_cvt; /* write a cvt entry (in pixels) */
     TT_Set_CVT_Func    func_move_cvt;  /* incr a cvt entry (in pixels)  */
 
-    FT_Bool            grayscale;      /* are we hinting for grayscale? */
+    FT_Bool            grayscale;      /* Bi-level hinting and grayscale
+                                          rendering */
+
+    /* Modern TrueType fonts are usually rendered through Microsoft's
+     * collection of rendering techniques called ClearType (e.g. subpixel
+     * rendering and subpixel hinting). When ClearType was introduced, most
+     * fonts were not ready. Microsoft decided to implement a backwards
+     * compatibility mode that employed several simple to complicated
+     * assumptions and tricks that modified the interpretation of the bytecode
+     * contained in these fonts to make them look ClearType-y somehow. Most
+     * (web)fonts that were released since then have come to rely on these
+     * hacks to render correctly, even some of Microsoft's flagship ClearType
+     * fonts (Calibri, Cambria, Segoe UI). Microsoft describes a way to turn
+     * off backwards compatibility and interpret instructions as before
+     * ("native ClearType")[1]. The font designer then regains full control and
+     * is responsible for making the font work correctly with ClearType without
+     * any hand-holding by the interpreter or rasterizer[2].
+     *
+     * Of the hacks implemented in FreeType, ignoring any point movement on the
+     * X-axis if the freedom vector is parallel to the X-axis has the smallest
+     * code footprint and single biggest effect (cf. Direct_Move() and
+     * Direct_Move_X()). The best results are achieved for fonts that were from
+     * the outset designed with ClearType in mind, meaning they leave the X-axis
+     * mostly alone.  The harder the designer tried to produce very specific
+     * black-and-white pixel patterns ("superhinting") for
+     * pre-ClearType-display, the worse the results. Most web fonts seen in the
+     * wild are made for ClearType display.
+     *
+     * The v38 interpreter assumes backwards compatibility by default. Fonts
+     * can turn it off and go "native ClearType" by using the following
+     * bytecode sequence at the beginning of the CVT program[1]:
+     *
+     *  #PUSH 4,3
+     *  INSTCTRL[]
+     *
+     * (cf. Ins_INSTCTRL()).
+     *
+     * [1]: Proposed by Microsoft's Greg Hitchcock in
+     * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx#Toc227035738
+     * [2]: The list of "native ClearType" fonts is small at the time of this
+     * writing, I found the following on a Windows 10 Update 1511 installation:
+     * Constantia, Corbel, Sitka, Malgun Gothic, Microsoft JhengHei (Bold and
+     * UI Bold), Microsoft YaHei (Bold and UI Bold), SimSun, NSimSun and Yu Gothic.
+     */
+    FT_Bool            subpixel_hinting; /* Using v38 implies this. */
+    FT_Bool            vertical_lcd;     /* long side of LCD subpixel */
+                                         /* rectangles is horizontal  */
+
+    FT_Bool            backwards_compatibility; /* Defaults to true with v38
+                                                   interpreter. If this is
+                                                   false, it implies the
+                                                   interpreter is in v35 or in
+                                                   native ClearType mode. */
+    FT_Bool            iup_called; /* Useful for detecting and denying post-iup trickery. */
+
+    /* ClearType hinting and grayscale rendering, as used by Universal Windows
+     * Platform apps (Windows 8 and above). Like the standard colorful
+     * ClearType mode, it utilizes a vastly increased virtual resolution on the
+     * X-axis.  Different from bi-level hinting and grayscale rendering, the
+     * old mode from Win9x days that roughly adheres to the physical pixel grid
+     * on both axes. */
+    FT_Bool            grayscale_cleartype;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     TT_Round_Func      func_round_sphn;   /* subpixel rounding function */
diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c
index cd4e294..4b43bb4 100644
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -1286,12 +1286,7 @@
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
     TT_Driver  driver = (TT_Driver)ttdriver;
-
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     driver->interpreter_version = TT_INTERPRETER_VERSION_38;
-#else
-    driver->interpreter_version = TT_INTERPRETER_VERSION_35;
-#endif
 
 #else /* !TT_USE_BYTECODE_INTERPRETER */
 
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index ccbb1d7..c0da814 100644
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -1642,6 +1642,10 @@
   /* <InOut>                                                               */
   /*    zone     :: The affected glyph zone.                               */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not move points on the X-axis if using the v38 interpreter in */
+  /*    backwards compatibility mode. Will still `touch' the point.        */
+  /*                                                                       */
   static void
   Direct_Move( TT_ExecContext  exc,
                TT_GlyphZone    zone,
@@ -1660,6 +1664,9 @@
            ( !exc->ignore_x_mode                                ||
              ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+      /* Non-native ClearType fonts cannot be trusted to responsibly move
+       * points on the X-axis. */
+      if ( ! exc->backwards_compatibility )
         zone->cur[point].x += FT_MulDiv( distance, v, exc->F_dot_P );
 
       zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
@@ -1721,6 +1728,9 @@
   /*   The following versions are used whenever both vectors are both      */
   /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
   /*                                                                       */
+  /*   Will not move points on the X-axis if using the v38 interpreter     */
+  /*   in backwards compatibility mode. Will still `touch' the point.      */
+  /*                                                                       */
   /*************************************************************************/
 
 
@@ -1736,6 +1746,10 @@
     if ( !SUBPIXEL_HINTING   ||
          !exc->ignore_x_mode )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+    /* Some non-native ClearType fonts seem to shuffle x-coordinates around,
+     * presumably to clean up rounding results. This creates dents in the
+     * outline. Deny, but still `touch' point so IUP works as expected. */
+    if ( ! exc->backwards_compatibility )
       zone->cur[point].x += distance;
 
     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
@@ -1853,6 +1867,10 @@
   /* <Return>                                                              */
   /*    Rounded distance.                                                  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not round on the X-axis if using the v38 interpreter          */
+  /*    in backwards compatibility mode.                                   */
+  /*                                                                       */
   static FT_F26Dot6
   Round_To_Grid( TT_ExecContext  exc,
                  FT_F26Dot6      distance,
@@ -1860,8 +1878,13 @@
   {
     FT_F26Dot6  val;
 
-    FT_UNUSED( exc );
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
 
     if ( distance >= 0 )
     {
@@ -1896,6 +1919,10 @@
   /* <Return>                                                              */
   /*    Rounded distance.                                                  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_To_Half_Grid( TT_ExecContext  exc,
                       FT_F26Dot6      distance,
@@ -1903,8 +1930,13 @@
   {
     FT_F26Dot6  val;
 
-    FT_UNUSED( exc );
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
 
     if ( distance >= 0 )
     {
@@ -1939,6 +1971,10 @@
   /* <Return>                                                              */
   /*    Rounded distance.                                                  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_Down_To_Grid( TT_ExecContext  exc,
                       FT_F26Dot6      distance,
@@ -1946,8 +1982,13 @@
   {
     FT_F26Dot6  val;
 
-    FT_UNUSED( exc );
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
 
     if ( distance >= 0 )
     {
@@ -1982,6 +2023,10 @@
   /* <Return>                                                              */
   /*    Rounded distance.                                                  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_Up_To_Grid( TT_ExecContext  exc,
                     FT_F26Dot6      distance,
@@ -1989,8 +2034,13 @@
   {
     FT_F26Dot6  val;
 
-    FT_UNUSED( exc );
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
 
     if ( distance >= 0 )
     {
@@ -2025,6 +2075,10 @@
   /* <Return>                                                              */
   /*    Rounded distance.                                                  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_To_Double_Grid( TT_ExecContext  exc,
                         FT_F26Dot6      distance,
@@ -2032,8 +2086,13 @@
   {
     FT_F26Dot6 val;
 
-    FT_UNUSED( exc );
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
 
     if ( distance >= 0 )
     {
@@ -2074,6 +2133,9 @@
   /*    the description of super round that we should add the compensation */
   /*    before rounding.                                                   */
   /*                                                                       */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_Super( TT_ExecContext  exc,
                FT_F26Dot6      distance,
@@ -2082,6 +2144,13 @@
     FT_F26Dot6  val;
 
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
+
     if ( distance >= 0 )
     {
       val = ( distance - exc->phase + exc->threshold + compensation ) &
@@ -2123,6 +2192,9 @@
   /*    There is a separate function for Round_Super_45() as we may need   */
   /*    greater precision.                                                 */
   /*                                                                       */
+  /*    Will not round on the X-axis if using the v38 interpreter in       */
+  /*    backwards compatibility mode.                                      */
+  /*                                                                       */
   static FT_F26Dot6
   Round_Super_45( TT_ExecContext  exc,
                   FT_F26Dot6      distance,
@@ -2131,6 +2203,13 @@
     FT_F26Dot6  val;
 
 
+    /* Given ClearType's virtual increase of resolution on the X-axis, rounding
+     * to the physical pixel grid there doesn't make much sense. Native ClearType
+     * fonts know this, the rest (where backwards compatibility applies) may or
+     * may not. Short out rounding if freedom vector is parallel to X-axis. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+      return Round_None( exc, distance, compensation );
+
     if ( distance >= 0 )
     {
       val = ( ( distance - exc->phase + exc->threshold + compensation ) /
@@ -5049,6 +5128,11 @@
     if ( K == 3 )
       exc->ignore_x_mode = FT_BOOL( L == 4 );
 #endif
+    /* Native ClearType fonts sign a waiver that turns off all backwards
+     * compatibility hacks and lets them program points to the grid like it's
+     * 1996. They might sign a waiver for just one glyph though. */
+    if ( K == 3 )
+      exc->backwards_compatibility = ! FT_BOOL( L == 4 );
   }
 
 
@@ -5337,7 +5421,12 @@
         Move_Zp2_Point( exc, point, 0, dy, TRUE );
       else
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-        Move_Zp2_Point( exc, point, dx, dy, TRUE );
+        /* Stop movement on the X-axis when using the v38 interpreter in
+         * backwards compatibility mode. Prevents dents in outlines. */
+        if ( exc->backwards_compatibility )
+          Move_Zp2_Point( exc, point, 0, dy, TRUE );
+        else
+          Move_Zp2_Point( exc, point, dx, dy, TRUE );
 
       exc->GS.loop--;
     }
@@ -5574,7 +5663,13 @@
 
 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
-      Move_Zp2_Point( exc, point, dx, dy, TRUE );
+      /* Stop movement on the X-axis when using the v38 interpreter in
+       * backwards compatibility mode. Prevents dents in outlines by overeager
+       * designers back in the bad old days ("superhinting"). */
+      if ( exc->backwards_compatibility )
+        Move_Zp2_Point( exc, point, 0, dy, TRUE );
+      else
+        Move_Zp2_Point( exc, point, dx, dy, TRUE );
 
 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
@@ -5616,6 +5711,17 @@
 
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    FT_F26Dot6  control_value_cutin = exc->GS.control_value_cutin;
+
+    /* From "Backwards Compatibility of TrueType Instructions with Microsoft
+     * ClearType" by Greg Hitchcock, 2009: "Some fonts pre-calculate stroke
+     * weights and subsequently use MSIRP[.], which involves neither rounding
+     * nor CVT cut-ins. Therefore MSIRP[.] now respects the CVT cut-in". Cut-in
+     * is set to zero because there's no movement on the X-axis anyway
+     * ("infinite resolution"). */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+        control_value_cutin = 0;
+
     point = (FT_UShort)args[0];
 
     if ( BOUNDS( point,       exc->zp1.n_points ) ||
@@ -5646,6 +5752,10 @@
       distance = args[1];
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    if ( exc->backwards_compatibility &&
+         FT_ABS( distance - args[1] ) >= control_value_cutin )
+      distance = args[1];
+
     exc->func_move( exc, &exc->zp1, point, args[1] - distance );
 
     exc->GS.rp1 = exc->GS.rp0;
@@ -5738,6 +5848,16 @@
       control_value_cutin = 0;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    /* From "Backwards Compatibility of TrueType Instructions with Microsoft
+     * ClearType" by Greg Hitchcock, 2009: "In some fonts fractional stroke
+     * weights were calculated and used in MIRP[…r…]. While this provides some
+     * extra granularity in font smoothing, it unnecessarily quantizes stroke
+     * weights in ClearType, because un-rounded MIRPs now respect CVT cut-in.
+     * [...] with ClearType on, do CVT cut-in always". Cut-in is set to zero
+     * because there's no movement on the X-axis anyway ("infinite resolution"). */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+        control_value_cutin = 0;
+
     if ( BOUNDS( point,     exc->zp0.n_points ) ||
          BOUNDSL( cvtEntry, exc->cvtSize )      )
     {
@@ -5845,6 +5965,11 @@
       minimum_distance = 0;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    /* Like in MSIRP and MIRP, no movement on the X-axis ("infinite
+     * resolution") means minimum_distance might as well be zero. */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+        minimum_distance = 0;
+
     point = (FT_UShort)args[0];
 
     if ( BOUNDS( point,       exc->zp1.n_points ) ||
@@ -5998,6 +6123,17 @@
       control_value_cutin = minimum_distance = 0;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    /* From "Backwards Compatibility of TrueType Instructions with Microsoft
+     * ClearType" by Greg Hitchcock, 2009: "In some fonts fractional stroke
+     * weights were calculated and used in MIRP[…r…]. While this provides some
+     * extra granularity in font smoothing, it unnecessarily quantizes stroke
+     * weights in ClearType, because un-rounded MIRPs now respect CVT cut-in.
+     * [...] with ClearType on, do CVT cut-in always". Cut-in  and minimum
+     * distance are set to zero because there's no movement on the X-axis
+     * anyway ("infinite resolution"). */
+    if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 )
+        control_value_cutin = minimum_distance = 0;
+
     /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
 
     if ( BOUNDS( point,       exc->zp1.n_points ) ||
@@ -6106,6 +6242,13 @@
       }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+      if ( exc->backwards_compatibility &&
+           exc->GS.gep0 == exc->GS.gep1 )
+      {
+        if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
+          cvt_dist = org_dist;
+      }
+
       distance = Round_None(
                    exc,
                    cvt_dist,
@@ -6211,6 +6354,13 @@
     }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    /* Prevents severe dents in Arial's 'D' and 'G'. */
+    if ( exc->backwards_compatibility && exc->iup_called )
+    {
+      exc->error = FT_THROW( Invalid_Reference );
+      goto Fail;
+    }
+
     if ( exc->top < exc->GS.loop                  ||
          BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
     {
@@ -6752,6 +6902,13 @@
     }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+    /* Useful to detect attempts at "superhinting", e.g. shuffling outlines
+     * around after IUP to produce a specific black-and-white pixel pattern the
+     * designer wanted to see. Bad for everything except monochrome rendering.
+     */
+    if ( exc->backwards_compatibility )
+      exc->iup_called = TRUE;
+
     do
     {
       end_point   = exc->pts.contours[contour] - exc->pts.first_point;
@@ -6945,8 +7102,24 @@
           }
           else
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-
-            exc->func_move( exc, &exc->zp0, A, B );
+            /* Like with SHPIX, DELTAP was/is often used to pop pixels on or
+             * off to produce some specific black-and-white pixel pattern the
+             * designer wanted to see ("superhinting"). Bad for everything
+             * except monochrome rendering. Short out as much as possible in
+             * backwards compatibility mode, except if we are DELTAPing in a
+             * composite glyph and on the Y-axis (e.g. offsetting diacritics
+             * from base glyphs) or if we're moving previously y-touched points
+             * (moves entire outline instead of denting it, that's ok).
+             * Details in "Backwards Compatibility of TrueType Instructions
+             * with Microsoft ClearType" by Greg Hitchcock, 2009.
+             */
+            if ( exc->backwards_compatibility )
+            {
+              if ( ! ( exc->is_composite && exc->GS.freeVector.y == 0 ) &&
+                   exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )
+                exc->func_move( exc, &exc->zp0, A, B );
+            } else
+              exc->func_move( exc, &exc->zp0, A, B );
         }
       }
       else
@@ -7063,9 +7236,11 @@
                FT_Long*        args )
   {
     FT_Long  K;
+    TT_Driver driver;
 
 
     K = 0;
+    driver = (TT_Driver)FT_FACE_DRIVER( exc->face );
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     /********************************/
@@ -7091,7 +7266,7 @@
     else
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
       if ( ( args[0] & 1 ) != 0 )
-        K = TT_INTERPRETER_VERSION_35;
+        K = driver->interpreter_version;
 
     /********************************/
     /* GLYPH ROTATED                */
@@ -7110,13 +7285,65 @@
       K |= 1 << 8;
 
     /********************************/
-    /* HINTING FOR GRAYSCALE        */
+    /* BI-LEVEL HINTING AND         */
+    /* GRAYSCALE RENDERING          */
     /* Selector Bit:  5             */
     /* Return Bit(s): 12            */
     /*                              */
     if ( ( args[0] & 32 ) != 0 && exc->grayscale )
       K |= 1 << 12;
 
+
+    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+    {
+      /********************************/
+      /* HINTING FOR SUBPIXEL         */
+      /* Selector Bit:  6             */
+      /* Return Bit(s): 13            */
+      /*                              */
+      /* v38 will do subpixel hinting by default. */
+      if ( ( args[0] & 64 ) != 0 )
+        K |= 1 << 13;
+
+      /********************************/
+      /* VERTICAL LCD SUBPIXELS?      */
+      /* Selector Bit:  8             */
+      /* Return Bit(s): 15            */
+      /*                              */
+      if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
+        K |= 1 << 15;
+
+      /********************************/
+      /* SUBPIXEL POSITIONED?         */
+      /* Selector Bit:  10            */
+      /* Return Bit(s): 17            */
+      /*                              */
+      /* XXX: FreeType supports it, dependant on what client does? */
+      if ( ( args[0] & 1024 ) != 0 )
+        K |= 1 << 17;
+
+      /********************************/
+      /* SYMMETRICAL SMOOTHING        */
+      /* Selector Bit:  11            */
+      /* Return Bit(s): 18            */
+      /*                              */
+      /* The only smoothing method FreeType supports unless someone set
+       * FT_LOAD_TARGET_MONO. */
+      if ( ( args[0] & 2048 ) != 0 )
+        K |= 1 << 18;
+
+      /********************************/
+      /* CLEARTYPE HINTING AND        */
+      /* GRAYSCALE RENDERING          */
+      /* Selector Bit:  12            */
+      /* Return Bit(s): 19            */
+      /*                              */
+      /* Grayscale rendering is what FreeType does anyway unless someone set
+       * FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */
+      if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
+        K |= 1 << 19;
+    }
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
     if ( SUBPIXEL_HINTING                                     &&
@@ -7274,6 +7501,8 @@
     FT_Long    ins_counter = 0;  /* executed instructions counter */
     FT_UShort  i;
 
+    TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face );
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     FT_Byte    opcode_pattern[1][2] = {
                   /* #8 TypeMan Talk Align */
@@ -7291,6 +7520,17 @@
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     exc->iup_called = FALSE;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+    /* Toggle backwards compatibility according to what font says, except when
+     * it's a 'tricky' font that heavily relies on the interpreter to render
+     * glyphs correctly, e.g. DFKai-SB. Backwards compatibility hacks may break
+     * it. */
+    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
+         !FT_IS_TRICKY( (&exc->face->root) ) )
+      exc->backwards_compatibility = ! (exc->GS.instruct_control & 4);
+    else
+      exc->backwards_compatibility = FALSE;
+
+    exc->iup_called = FALSE;
 
     /* set PPEM and CVT functions */
     exc->tt_metrics.ratio = 0;
_______________________________________________
Freetype-devel mailing list
Freetype-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/freetype-devel

Reply via email to