shithub: freetype+ttf2subf

Download patch

ref: f04951af8dd16495ebe5bd45a3e33ad30f511553
parent: 6650be7c43c9f7299a0bfbd5d81b481efbe9d95b
author: Werner Lemberg <[email protected]>
date: Fri May 17 09:51:07 EDT 2013

[truetype] Add `interpreter-version' property.

This makes the option TT_CONFIG_OPTION_SUBPIXEL_HINTING controllable
at runtime.

* src/truetype/ttdriver.c: Include FT_TRUETYPE_DRIVER_H.
(tt_property_set, tt_property_get): Fill templates.

* src/truetype/ttobjs.h (TT_DriverRec): Add `interpreter_version'
member.
Remove unused `extension_component' member.

* src/truetype/ttgload.c: Include FT_TRUETYPE_DRIVER_H.
(tt_get_metrics, TT_Hint_Glyph, TT_Process_Simple_Glyph,
compute_glyph_metrics, tt_loader_init): Use `interpreter_version'.

* src/truetype/ttinterp.c: Include FT_TRUETYPE_DRIVER_H.
(SUBPIXEL_HINTING): New macro to check `interpreter_version' flag.
Update all affected functions to use it.
Use TT_INTERPRETER_VERSION_XXX where appropriate.

* src/truetype/ttobjs.c: Include FT_TRUETYPE_DRIVER_H.
(tt_driver_init): Initialize `interpreter_version'.

* src/truetype/ttsubpix.c: Include FT_TRUETYPE_DRIVER_H.
Use TT_INTERPRETER_VERSION_XXX where appropriate.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2013-05-15  Werner Lemberg  <[email protected]>
+
+	[truetype] Add `interpreter-version' property.
+
+	This makes the option TT_CONFIG_OPTION_SUBPIXEL_HINTING controllable
+	at runtime.
+
+	* src/truetype/ttdriver.c: Include FT_TRUETYPE_DRIVER_H.
+	(tt_property_set, tt_property_get): Fill templates.
+
+	* src/truetype/ttobjs.h (TT_DriverRec): Add `interpreter_version'
+	member.
+	Remove unused `extension_component' member.
+
+	* src/truetype/ttgload.c: Include FT_TRUETYPE_DRIVER_H.
+	(tt_get_metrics, TT_Hint_Glyph, TT_Process_Simple_Glyph,
+	compute_glyph_metrics, tt_loader_init): Use `interpreter_version'.
+
+	* src/truetype/ttinterp.c: Include FT_TRUETYPE_DRIVER_H.
+	(SUBPIXEL_HINTING): New macro to check `interpreter_version' flag.
+	Update all affected functions to use it.
+	Use TT_INTERPRETER_VERSION_XXX where appropriate.
+
+	* src/truetype/ttobjs.c: Include FT_TRUETYPE_DRIVER_H.
+	(tt_driver_init): Initialize `interpreter_version'.
+
+	* src/truetype/ttsubpix.c: Include FT_TRUETYPE_DRIVER_H.
+	Use TT_INTERPRETER_VERSION_XXX where appropriate.
+
 2013-05-13  Werner Lemberg  <[email protected]>
 
 	[truetype] Avoid empty source file.
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -344,6 +344,19 @@
   /*************************************************************************
    *
    * @macro:
+   *   FT_TRUETYPE_DRIVER_H
+   *
+   * @description:
+   *   A macro used in #include statements to name the file containing
+   *   structures and macros related to the TrueType driver module.
+   *
+   */
+#define FT_TRUETYPE_DRIVER_H  <freetype/ftttdrv.h>
+
+
+  /*************************************************************************
+   *
+   * @macro:
    *   FT_TYPE1_TABLES_H
    *
    * @description:
--- a/include/freetype/ftchapters.h
+++ b/include/freetype/ftchapters.h
@@ -67,27 +67,15 @@
 /***************************************************************************/
 /*                                                                         */
 /* <Chapter>                                                               */
-/*    auto_hinter                                                          */
+/*    module_specific                                                      */
 /*                                                                         */
 /* <Title>                                                                 */
-/*    The Auto-Hinter                                                      */
+/*    Controlling FreeType Modules                                         */
 /*                                                                         */
 /* <Sections>                                                              */
 /*    auto_hinter                                                          */
-/*                                                                         */
-/***************************************************************************/
-
-
-/***************************************************************************/
-/*                                                                         */
-/* <Chapter>                                                               */
 /*    cff_driver                                                           */
-/*                                                                         */
-/* <Title>                                                                 */
-/*    The CFF Driver                                                       */
-/*                                                                         */
-/* <Sections>                                                              */
-/*    cff_driver                                                           */
+/*    tt_driver                                                            */
 /*                                                                         */
 /***************************************************************************/
 
--- /dev/null
+++ b/include/freetype/ftttdrv.h
@@ -1,0 +1,150 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftttdrv.h                                                              */
+/*                                                                         */
+/*    FreeType API for controlling the TrueType driver                     */
+/*    (specification only).                                                */
+/*                                                                         */
+/*  Copyright 2013 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTTTDRV_H__
+#define __FTTTDRV_H__
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   tt_driver
+   *
+   * @title:
+   *   The TrueType driver
+   *
+   * @abstract:
+   *   Controlling the TrueType driver module.
+   *
+   * @description:
+   *   While FreeType's TrueType driver doesn't expose API functions by
+   *   itself, it is possible to control its behaviour with @FT_Property_Set
+   *   and @FT_Property_Get.  The following lists the available properties
+   *   together with the necessary macros and structures.
+   *
+   *   The TrueType driver's module name is `truetype'.
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @property:
+   *   interpreter-version
+   *
+   * @description:
+   *   Currently, two versions are available which represent the bytecode
+   *   interpreter with and without subpixel hinting support,
+   *   respectively.  The default is subpixel support if
+   *   TT_CONFIG_OPTION_SUBPIXEL_HINTING is defined, and no subpixel
+   *   support otherwise (since it isn't available then).
+   *
+   *   If subpixel hinting is on, many TrueType bytecode instructions
+   *   behave differently compared to B/W or grayscale rendering.  The
+   *   main idea is to render at a much increased horizontal resolution,
+   *   then sampling down the created output to subpixel precision.
+   *   However, many older fonts are not suited to this and must be
+   *   specially taken care of by applying (hardcoded) font-specific
+   *   tweaks.
+   *
+   *   Details on subpixel hinting and some of the necessary tweaks can be
+   *   found in Greg Hitchcock's whitepaper at
+   *   `http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'.
+   *
+   *   The following example code demonstrates how to activate subpixel
+   *   hinting (omitting the error handling).
+   *
+   *   {
+   *     FT_Library  library;
+   *     FT_Face     face;
+   *     FT_UInt     interpreter_version = TT_INTERPRETER_VERSION_38;
+   *
+   *
+   *     FT_Init_FreeType( &library );
+   *
+   *     FT_Property_Set( library, "truetype",
+   *                               "interpreter-version",
+   *                               &interpreter_version );
+   *   }
+   *
+   * @note:
+   *   This property can be used with @FT_Property_Get also.
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @enum:
+   *   TT_INTERPRETER_VERSION_XXX
+   *
+   * @description:
+   *   A list of constants used for the @interpreter-version property to
+   *   select the hinting engine for Truetype fonts.
+   *
+   *   The numeric value in the constant names represents the version
+   *   number as returned by the `GETINFO' bytecode instruction.
+   *
+   * @values:
+   *   TT_INTERPRETER_VERSION_35 ::
+   *     Version~35 corresponds to MS rasterizer v.1.7 as used e.g. in
+   *     Windows~98; only grayscale and B/W rasterizing is supported.
+   *
+   *   TT_INTERPRETER_VERSION_38 ::
+   *     Version~38 corresponds to MS rasterizer v.1.9; it is roughly
+   *     equivalent to the hinting provided by DirectWrite ClearType (as
+   *     can be found, for example, in the Internet Explorer~9 running on
+   *     Windows~7).
+   *
+   * @note:
+   *   This property controls the behaviour of the bytecode interpreter
+   *   and thus how outlines get hinted.  It does *not* control how glyph
+   *   get rasterized!  In particular, it does not control subpixel color
+   *   filtering.
+   *
+   *   If FreeType has not been compiled with configuration option
+   *   FT_CONFIG_OPTION_SUBPIXEL_HINTING, selecting version~38 causes an
+   *   `FT_Err_Unimplemented_Feature' error.
+   *
+   */
+#define TT_INTERPRETER_VERSION_35  35
+#define TT_INTERPRETER_VERSION_38  38
+
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __FTTTDRV_H__ */
+
+
+/* END */
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -30,6 +30,7 @@
 #include FT_SERVICE_TRUETYPE_ENGINE_H
 #include FT_SERVICE_TRUETYPE_GLYF_H
 #include FT_SERVICE_PROPERTIES_H
+#include FT_TRUETYPE_DRIVER_H
 
 #include "ttdriver.h"
 #include "ttgload.h"
@@ -66,7 +67,24 @@
     TT_Driver  driver = (TT_Driver)module;
 
 
-    return error;
+    if ( !ft_strcmp( property_name, "interpreter-version" ) )
+    {
+      FT_UInt*  interpreter_version = (FT_UInt*)value;
+
+
+#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+      if ( *interpreter_version != TT_INTERPRETER_VERSION_35 )
+        error = FT_ERR( Unimplemented_Feature );
+      else
+#endif
+        driver->interpreter_version = *interpreter_version;
+
+      return error;
+    }
+
+    FT_TRACE0(( "tt_property_set: missing property `%s'\n",
+                property_name ));
+    return FT_THROW( Missing_Property );
   }
 
 
@@ -78,8 +96,22 @@
     FT_Error   error  = FT_Err_Ok;
     TT_Driver  driver = (TT_Driver)module;
 
+    FT_UInt  interpreter_version = driver->interpreter_version;
 
-    return error;
+
+    if ( !ft_strcmp( property_name, "interpreter-version" ) )
+    {
+      FT_UInt*  val = (FT_UInt*)value;
+
+
+      *val = interpreter_version;
+
+      return error;
+    }
+
+    FT_TRACE0(( "tt_property_get: missing property `%s'\n",
+                property_name ));
+    return FT_THROW( Missing_Property );
   }
 
 
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -23,6 +23,7 @@
 #include FT_INTERNAL_SFNT_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_OUTLINE_H
+#include FT_TRUETYPE_DRIVER_H
 
 #include "ttgload.h"
 #include "ttpload.h"
@@ -132,7 +133,10 @@
   tt_get_metrics( TT_Loader  loader,
                   FT_UInt    glyph_index )
   {
-    TT_Face  face = (TT_Face)loader->face;
+    TT_Face    face   = (TT_Face)loader->face;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
 
     FT_Short   left_bearing = 0, top_bearing = 0;
     FT_UShort  advance_width = 0, advance_height = 0;
@@ -151,12 +155,15 @@
     loader->vadvance     = advance_height;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( loader->exec )
-      loader->exec->sph_tweak_flags = 0;
+    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+    {
+      if ( loader->exec )
+        loader->exec->sph_tweak_flags = 0;
 
-    /* this may not be the right place for this, but it works */
-    if ( loader->exec && loader->exec->ignore_x_mode )
-      sph_set_tweaks( loader, glyph_index );
+      /* this may not be the right place for this, but it works */
+      if ( loader->exec && loader->exec->ignore_x_mode )
+        sph_set_tweaks( loader, glyph_index );
+    }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     if ( !loader->linear_def )
@@ -720,6 +727,11 @@
   TT_Hint_Glyph( TT_Loader  loader,
                  FT_Bool    is_composite )
   {
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    TT_Face    face   = (TT_Face)loader->face;
+    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
+
     TT_GlyphZone  zone = &loader->zone;
     FT_Pos        origin;
 
@@ -820,12 +832,16 @@
     }
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
-      FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
+    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+    {
+      if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
+        FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
 
-    else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
-      FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
-#endif
+      else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
+        FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
+    }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     return FT_Err_Ok;
   }
 
@@ -848,15 +864,7 @@
     FT_Outline*     outline;
     FT_Int          n_points;
 
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    TT_Face     face           = (TT_Face)loader->face;
-    FT_String*  family         = face->root.family_name;
-    FT_Int      ppem           = loader->size->metrics.x_ppem;
-    FT_String*  style          = face->root.style_name;
-    FT_Int      x_scale_factor = 1000;
-#endif
 
-
     outline  = &gloader->current.outline;
     n_points = outline->n_points;
 
@@ -910,54 +918,83 @@
                      loader->zone.n_points + 4 );
     }
 
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    /* scale, but only if enabled and only if TT hinting is being used */
-    if ( IS_HINTED( loader->load_flags ) )
-      x_scale_factor = sph_test_tweak_x_scaling( face,
-                                                 family,
-                                                 ppem,
-                                                 style,
-                                                 loader->glyph_index );
-    /* scale the glyph */
-    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
-         x_scale_factor != 1000                         )
     {
-      FT_Vector*  vec     = outline->points;
-      FT_Vector*  limit   = outline->points + n_points;
-      FT_Fixed    x_scale = FT_MulDiv(
-                              ((TT_Size)loader->size)->metrics.x_scale,
-                              x_scale_factor, 1000 );
-      FT_Fixed    y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+      TT_Face    face   = (TT_Face)loader->face;
+      TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 
+      FT_String*  family         = face->root.family_name;
+      FT_Int      ppem           = loader->size->metrics.x_ppem;
+      FT_String*  style          = face->root.style_name;
+      FT_Int      x_scale_factor = 1000;
+#endif
 
-      /* compensate for any scaling by de/emboldening; */
-      /* the amount was determined via experimentation */
-      if ( x_scale_factor != 1000 && ppem > 11 )
-         FT_Outline_EmboldenXY( outline,
-                                FT_MulFix( 1280 * ppem,
-                                           1000 - x_scale_factor ),
-                                0 );
-#else
-    /* scale the glyph */
-    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
-    {
-      FT_Vector*  vec     = outline->points;
-      FT_Vector*  limit   = outline->points + n_points;
-      FT_Fixed    x_scale = ((TT_Size)loader->size)->metrics.x_scale;
-      FT_Fixed    y_scale = ((TT_Size)loader->size)->metrics.y_scale;
-#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+      FT_Vector*  vec   = outline->points;
+      FT_Vector*  limit = outline->points + n_points;
 
+      FT_Fixed  x_scale;
+      FT_Fixed  y_scale;
 
-      for ( ; vec < limit; vec++ )
+      FT_Bool  do_scale = FALSE;
+
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
       {
-        vec->x = FT_MulFix( vec->x, x_scale );
-        vec->y = FT_MulFix( vec->y, y_scale );
+        /* scale, but only if enabled and only if TT hinting is being used */
+        if ( IS_HINTED( loader->load_flags ) )
+          x_scale_factor = sph_test_tweak_x_scaling( face,
+                                                     family,
+                                                     ppem,
+                                                     style,
+                                                     loader->glyph_index );
+        /* scale the glyph */
+        if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
+             x_scale_factor != 1000                         )
+        {
+          x_scale = FT_MulDiv( ((TT_Size)loader->size)->metrics.x_scale,
+                               x_scale_factor, 1000 );
+          y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+
+          /* compensate for any scaling by de/emboldening; */
+          /* the amount was determined via experimentation */
+          if ( x_scale_factor != 1000 && ppem > 11 )
+            FT_Outline_EmboldenXY( outline,
+                                   FT_MulFix( 1280 * ppem,
+                                              1000 - x_scale_factor ),
+                                   0 );
+          do_scale = TRUE;
+        }
       }
+      else
 
-      loader->pp1 = outline->points[n_points - 4];
-      loader->pp2 = outline->points[n_points - 3];
-      loader->pp3 = outline->points[n_points - 2];
-      loader->pp4 = outline->points[n_points - 1];
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+      {
+        /* scale the glyph */
+        if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+        {
+          x_scale = ((TT_Size)loader->size)->metrics.x_scale;
+          y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+
+          do_scale = TRUE;
+        }
+      }
+
+      if ( do_scale )
+      {
+        for ( ; vec < limit; vec++ )
+        {
+          vec->x = FT_MulFix( vec->x, x_scale );
+          vec->y = FT_MulFix( vec->y, y_scale );
+        }
+
+        loader->pp1 = outline->points[n_points - 4];
+        loader->pp2 = outline->points[n_points - 3];
+        loader->pp3 = outline->points[n_points - 2];
+        loader->pp4 = outline->points[n_points - 1];
+      }
     }
 
     if ( IS_HINTED( loader->load_flags ) )
@@ -1662,11 +1699,15 @@
   compute_glyph_metrics( TT_Loader  loader,
                          FT_UInt    glyph_index )
   {
+    TT_Face    face   = (TT_Face)loader->face;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
+
     FT_BBox       bbox;
-    TT_Face       face = (TT_Face)loader->face;
     FT_Fixed      y_scale;
     TT_GlyphSlot  glyph = loader->glyph;
-    TT_Size       size = (TT_Size)loader->size;
+    TT_Size       size  = (TT_Size)loader->size;
 
 
     y_scale = 0x10000L;
@@ -1692,27 +1733,35 @@
     {
       FT_Byte*  widthp;
 
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      FT_Bool  ignore_x_mode;
 
-
-      ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) !=
-                               FT_RENDER_MODE_MONO );
-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-
       widthp = tt_face_get_device_metrics( face,
                                            size->root.metrics.x_ppem,
                                            glyph_index );
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( widthp                                                   &&
-           ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
-              !ignore_x_mode                                      ||
-              SPH_OPTION_BITMAP_WIDTHS                            ) )
-#else
-      if ( widthp )
+
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+      {
+        FT_Bool  ignore_x_mode;
+
+
+        ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) !=
+                                 FT_RENDER_MODE_MONO );
+
+        if ( widthp                                                   &&
+             ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
+                !ignore_x_mode                                      ||
+                SPH_OPTION_BITMAP_WIDTHS                            ) )
+          glyph->metrics.horiAdvance = *widthp << 6;
+      }
+      else
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-        glyph->metrics.horiAdvance = *widthp << 6;
+
+      {
+        if ( widthp )
+          glyph->metrics.horiAdvance = *widthp << 6;
+      }
     }
 
     /* set glyph dimensions */
@@ -1908,18 +1957,25 @@
     {
       TT_ExecContext  exec;
       FT_Bool         grayscale;
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      FT_Bool         subpixel_hinting;
-      FT_Bool         grayscale_hinting;
+      TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
+
+      FT_Bool  subpixel_hinting  = FALSE;
+      FT_Bool  grayscale_hinting = TRUE;
+
 #if 0
-      FT_Bool         compatible_widths;
-      FT_Bool         symmetrical_smoothing;
-      FT_Bool         bgr;
-      FT_Bool         subpixel_positioned;
+      /* not used yet */
+      FT_Bool  compatible_widths;
+      FT_Bool  symmetrical_smoothing;
+      FT_Bool  bgr;
+      FT_Bool  subpixel_positioned;
 #endif
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+      FT_Bool  reexecute = FALSE;
 
+
       if ( !size->cvt_ready )
       {
         FT_Error  error = tt_size_ready_bytecode( size, pedantic );
@@ -1937,113 +1993,114 @@
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
-      subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags )
-                                    != FT_RENDER_MODE_MONO )          &&
-                                  SPH_OPTION_SET_SUBPIXEL             );
-
-      if ( subpixel_hinting )
-        grayscale = grayscale_hinting = FALSE;
-      else if ( SPH_OPTION_SET_GRAYSCALE )
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
       {
-        grayscale = grayscale_hinting = TRUE;
-        subpixel_hinting = FALSE;
-      }
-      else
-        grayscale = grayscale_hinting = FALSE;
+        subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags )
+                                      != FT_RENDER_MODE_MONO )          &&
+                                    SPH_OPTION_SET_SUBPIXEL             );
 
-      if ( FT_IS_TRICKY( glyph->face ) )
-        subpixel_hinting = grayscale_hinting = FALSE;
+        if ( subpixel_hinting )
+          grayscale = grayscale_hinting = FALSE;
+        else if ( SPH_OPTION_SET_GRAYSCALE )
+        {
+          grayscale = grayscale_hinting = TRUE;
+          subpixel_hinting              = FALSE;
+        }
+        else
+          grayscale = grayscale_hinting = FALSE;
 
-      exec->ignore_x_mode      = subpixel_hinting || grayscale_hinting;
-      exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
-      if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
-        exec->rasterizer_version = 35;
+        if ( FT_IS_TRICKY( glyph->face ) )
+          subpixel_hinting = grayscale_hinting = FALSE;
 
+        exec->ignore_x_mode      = subpixel_hinting || grayscale_hinting;
+        exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
+        if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
+          exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
+
 #if 1
-      exec->compatible_widths     = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
-      exec->symmetrical_smoothing = FALSE;
-      exec->bgr                   = FALSE;
-      exec->subpixel_positioned   = TRUE;
+        exec->compatible_widths     = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
+        exec->symmetrical_smoothing = FALSE;
+        exec->bgr                   = FALSE;
+        exec->subpixel_positioned   = TRUE;
 #else /* 0 */
-      exec->compatible_widths =
-        FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                 TT_LOAD_COMPATIBLE_WIDTHS );
-      exec->symmetrical_smoothing =
-        FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                 TT_LOAD_SYMMETRICAL_SMOOTHING );
-      exec->bgr =
-        FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                 TT_LOAD_BGR );
-      exec->subpixel_positioned =
-        FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                 TT_LOAD_SUBPIXEL_POSITIONED );
+        exec->compatible_widths =
+          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                   TT_LOAD_COMPATIBLE_WIDTHS );
+        exec->symmetrical_smoothing =
+          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                   TT_LOAD_SYMMETRICAL_SMOOTHING );
+        exec->bgr =
+          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                   TT_LOAD_BGR );
+        exec->subpixel_positioned =
+          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                   TT_LOAD_SUBPIXEL_POSITIONED );
 #endif /* 0 */
 
-#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+      }
+      else
 
-      grayscale =
-        FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO );
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
-#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+      {
+        grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                             FT_RENDER_MODE_MONO );
+      }
 
       TT_Load_Context( exec, face, size );
 
 #ifdef 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 )
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
       {
-        FT_UInt  i;
+        /* 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;
+        }
 
-        FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
-                    " re-executing `prep' table\n" ));
+        /* a change from mono to grayscale rendering (and vice versa) */
+        /* requires a re-execution of the CVT program                 */
+        if ( grayscale != exec->grayscale_hinting )
+        {
+          FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
+                      " re-executing `prep' table\n" ));
 
-        exec->subpixel_hinting = subpixel_hinting;
-
-        for ( i = 0; i < size->cvt_size; i++ )
-          size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
-        tt_size_run_prep( size, pedantic );
+          exec->grayscale_hinting = grayscale_hinting;
+          reexecute               = TRUE;
+        }
       }
+      else
 
-      /* a change from mono to grayscale rendering (and vice versa) */
-      /* requires a re-execution of the CVT program                 */
-      if ( grayscale != exec->grayscale_hinting )
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
       {
-        FT_UInt  i;
+        /* a change from mono to grayscale rendering (and vice versa) */
+        /* requires a re-execution of the CVT program                 */
+        if ( grayscale != exec->grayscale )
+        {
+          FT_TRACE4(( "tt_loader_init: grayscale change,"
+                      " re-executing `prep' table\n" ));
 
-
-        FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
-                    " re-executing `prep' table\n" ));
-
-        exec->grayscale_hinting = grayscale_hinting;
-
-        for ( i = 0; i < size->cvt_size; i++ )
-          size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
-        tt_size_run_prep( size, pedantic );
+          exec->grayscale = grayscale;
+          reexecute       = TRUE;
+        }
       }
 
-#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-
-      /* a change from mono to grayscale rendering (and vice versa) */
-      /* requires a re-execution of the CVT program                 */
-      if ( grayscale != exec->grayscale )
+      if ( reexecute )
       {
         FT_UInt  i;
 
 
-        FT_TRACE4(( "tt_loader_init: grayscale change,"
-                    " re-executing `prep' table\n" ));
-
-        exec->grayscale = grayscale;
-
         for ( i = 0; i < size->cvt_size; i++ )
           size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
         tt_size_run_prep( size, pedantic );
       }
-
-#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
       /* see whether the cvt program has disabled hinting */
       if ( exec->GS.instruct_control & 1 )
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -25,6 +25,7 @@
 #include FT_INTERNAL_CALC_H
 #include FT_TRIGONOMETRY_H
 #include FT_SYSTEM_H
+#include FT_TRUETYPE_DRIVER_H
 
 #include "ttinterp.h"
 #include "tterrors.h"
@@ -131,6 +132,11 @@
 #define FT_UNUSED_ARG  FT_UNUSED_EXEC; FT_UNUSED( args )
 
 
+#define SUBPIXEL_HINTING                                                    \
+          ( ((TT_Driver)FT_FACE_DRIVER( CUR.face ))->interpreter_version == \
+            TT_INTERPRETER_VERSION_38 )
+
+
   /*************************************************************************/
   /*                                                                       */
   /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to        */
@@ -1764,10 +1770,11 @@
     if ( v != 0 )
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( !CUR.ignore_x_mode                                ||
-           ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) )
+      if ( !SUBPIXEL_HINTING                                     ||
+           ( !CUR.ignore_x_mode                                ||
+             ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-      zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
+        zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
 
       zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
     }
@@ -1842,10 +1849,12 @@
     FT_UNUSED_EXEC;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( !CUR.ignore_x_mode                                 ||
-         ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVEX ) )
+    if ( !SUBPIXEL_HINTING                                      ||
+         ( !CUR.ignore_x_mode                                 ||
+           ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVEX ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-    zone->cur[point].x += distance;
+      zone->cur[point].x += distance;
+
     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
   }
 
@@ -3165,7 +3174,8 @@
        /* subpixel hinting - avoid Typeman Dstroke and */ \
        /* IStroke and Vacuform rounds                  */ \
                                                           \
-       if ( CUR.ignore_x_mode                          && \
+       if ( SUBPIXEL_HINTING                           && \
+            CUR.ignore_x_mode                          && \
             ( ( I == 24                            &&     \
                 ( CUR.face->sph_found_func_flags &        \
                   ( SPH_FDEF_SPACING_1 |                  \
@@ -4604,100 +4614,104 @@
 
     while ( SKIP_Code() == SUCCESS )
     {
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
-      for ( i = 0; i < opcode_patterns; i++ )
+      if ( SUBPIXEL_HINTING )
       {
-        if ( opcode_pointer[i] < opcode_size[i]                 &&
-             CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
+        for ( i = 0; i < opcode_patterns; i++ )
         {
-          opcode_pointer[i] += 1;
-
-          if ( opcode_pointer[i] == opcode_size[i] )
+          if ( opcode_pointer[i] < opcode_size[i]                 &&
+               CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
           {
-            FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
-                        i, n,
-                        CUR.face->root.family_name,
-                        CUR.face->root.style_name ));
+            opcode_pointer[i] += 1;
 
-            switch ( i )
+            if ( opcode_pointer[i] == opcode_size[i] )
             {
-            case 0:
-              rec->sph_fdef_flags            |= SPH_FDEF_INLINE_DELTA_1;
-              CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
-              break;
+              FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
+                          i, n,
+                          CUR.face->root.family_name,
+                          CUR.face->root.style_name ));
 
-            case 1:
-              rec->sph_fdef_flags            |= SPH_FDEF_INLINE_DELTA_2;
-              CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
-              break;
-
-            case 2:
-              switch ( n )
+              switch ( i )
               {
-              /* needs to be implemented still */
-              case 58:
-                rec->sph_fdef_flags            |= SPH_FDEF_DIAGONAL_STROKE;
-                CUR.face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
-              }
-              break;
-
-            case 3:
-              switch ( n )
-              {
               case 0:
-                rec->sph_fdef_flags            |= SPH_FDEF_VACUFORM_ROUND_1;
-                CUR.face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
-              }
-              break;
+                rec->sph_fdef_flags            |= SPH_FDEF_INLINE_DELTA_1;
+                CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
+                break;
 
-            case 4:
-              /* probably not necessary to detect anymore */
-              rec->sph_fdef_flags            |= SPH_FDEF_TTFAUTOHINT_1;
-              CUR.face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
-              break;
-
-            case 5:
-              switch ( n )
-              {
-              case 0:
               case 1:
-              case 2:
-              case 4:
-              case 7:
-              case 8:
-                rec->sph_fdef_flags            |= SPH_FDEF_SPACING_1;
-                CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
-              }
-              break;
+                rec->sph_fdef_flags            |= SPH_FDEF_INLINE_DELTA_2;
+                CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
+                break;
 
-            case 6:
-              switch ( n )
-              {
-              case 0:
-              case 1:
               case 2:
+                switch ( n )
+                {
+                  /* needs to be implemented still */
+                case 58:
+                  rec->sph_fdef_flags            |= SPH_FDEF_DIAGONAL_STROKE;
+                  CUR.face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
+                }
+                break;
+
+              case 3:
+                switch ( n )
+                {
+                case 0:
+                  rec->sph_fdef_flags            |= SPH_FDEF_VACUFORM_ROUND_1;
+                  CUR.face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
+                }
+                break;
+
               case 4:
-              case 7:
-              case 8:
-                rec->sph_fdef_flags            |= SPH_FDEF_SPACING_2;
-                CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
+                /* probably not necessary to detect anymore */
+                rec->sph_fdef_flags            |= SPH_FDEF_TTFAUTOHINT_1;
+                CUR.face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
+                break;
+
+              case 5:
+                switch ( n )
+                {
+                case 0:
+                case 1:
+                case 2:
+                case 4:
+                case 7:
+                case 8:
+                  rec->sph_fdef_flags            |= SPH_FDEF_SPACING_1;
+                  CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
+                }
+                break;
+
+              case 6:
+                switch ( n )
+                {
+                case 0:
+                case 1:
+                case 2:
+                case 4:
+                case 7:
+                case 8:
+                  rec->sph_fdef_flags            |= SPH_FDEF_SPACING_2;
+                  CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
+                }
+                break;
               }
-              break;
+              opcode_pointer[i] = 0;
             }
-            opcode_pointer[i] = 0;
           }
+
+          else
+            opcode_pointer[i] = 0;
         }
 
-        else
-          opcode_pointer[i] = 0;
+        /* Set sph_compatibility_mode only when deltas are detected */
+        CUR.face->sph_compatibility_mode =
+          ( ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
+            ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
       }
 
-      /* Set sph_compatibility_mode only when deltas are detected */
-      CUR.face->sph_compatibility_mode =
-        ( ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
-          ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
-
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
       switch ( CUR.opcode )
@@ -5282,7 +5296,8 @@
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
-    if ( CUR.ignore_x_mode && FT_ABS( D ) == 64 )
+    if ( SUBPIXEL_HINTING                       &&
+         CUR.ignore_x_mode && FT_ABS( D ) == 64 )
       D += 1;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
@@ -5779,11 +5794,13 @@
     if ( CUR.GS.freeVector.x != 0 )
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( !CUR.ignore_x_mode                                      ||
-          ( CUR.ignore_x_mode                                    &&
-            ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_MOVE_ZP2 ) ) )
+      if ( !SUBPIXEL_HINTING                                            ||
+           ( !CUR.ignore_x_mode                                       ||
+             ( CUR.ignore_x_mode                                    &&
+               ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_MOVE_ZP2 ) ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
         CUR.zp2.cur[point].x += dx;
+
       if ( touch )
         CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
     }
@@ -6022,7 +6039,8 @@
         /*   - the glyph is specifically set to allow SHPIX moves          */
         /*   - the move is on a previously Y-touched point                 */
 
-        if ( CUR.ignore_x_mode )
+        if ( SUBPIXEL_HINTING  &&
+             CUR.ignore_x_mode )
         {
           /* save point for later comparison */
           if ( CUR.GS.freeVector.y != 0 )
@@ -6071,15 +6089,19 @@
                  ( B2 & 63 ) != 0                                          &&
                  B1 != B2                                                  ) )
             MOVE_Zp2_Point( point, -dx, -dy, TRUE );
-      }
+        }
         else
           MOVE_Zp2_Point( point, dx, dy, TRUE );
       }
-  Skip:
-#else
+
+    Skip:
+
+#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
         MOVE_Zp2_Point( point, dx, dy, TRUE );
-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
       CUR.GS.loop--;
     }
 
@@ -6100,16 +6122,21 @@
   {
     FT_UShort   point;
     FT_F26Dot6  distance;
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     FT_F26Dot6  control_value_cutin;
 
 
-    control_value_cutin = CUR.GS.control_value_cutin;
+    if ( SUBPIXEL_HINTING )
+    {
+      control_value_cutin = CUR.GS.control_value_cutin;
 
-    if ( CUR.ignore_x_mode                                 &&
-         CUR.GS.freeVector.x != 0                          &&
-         !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-      control_value_cutin = 0;
+      if ( CUR.ignore_x_mode                                 &&
+           CUR.GS.freeVector.x != 0                          &&
+           !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+        control_value_cutin = 0;
+    }
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     point = (FT_UShort)args[0];
@@ -6136,7 +6163,8 @@
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     /* subpixel hinting - make MSIRP respect CVT cut-in; */
-    if ( CUR.ignore_x_mode                                   &&
+    if ( SUBPIXEL_HINTING                                    &&
+         CUR.ignore_x_mode                                   &&
          CUR.GS.freeVector.x != 0                            &&
          FT_ABS( distance - args[1] ) >= control_value_cutin )
       distance = args[1];
@@ -6179,7 +6207,8 @@
     {
       cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( CUR.ignore_x_mode        &&
+      if ( SUBPIXEL_HINTING         &&
+           CUR.ignore_x_mode        &&
            CUR.GS.freeVector.x != 0 )
         distance = ROUND_None(
                      cur_dist,
@@ -6221,7 +6250,8 @@
     point               = (FT_UShort)args[0];
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                                 &&
+    if ( SUBPIXEL_HINTING                                  &&
+         CUR.ignore_x_mode                                 &&
          CUR.GS.freeVector.x != 0                          &&
          !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
       control_value_cutin = 0;
@@ -6262,7 +6292,9 @@
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
       /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
       /* Determined via experimentation and may be incorrect...         */
-      if ( !CUR.ignore_x_mode || !CUR.face->sph_compatibility_mode )
+      if ( !SUBPIXEL_HINTING                     ||
+           ( !CUR.ignore_x_mode                ||
+             !CUR.face->sph_compatibility_mode ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
         CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
                                             CUR.GS.freeVector.x );
@@ -6271,7 +6303,8 @@
       CUR.zp0.cur[point]   = CUR.zp0.org[point];
     }
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                             &&
+    if ( SUBPIXEL_HINTING                              &&
+         CUR.ignore_x_mode                             &&
          ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
          distance > 0                                  &&
          CUR.GS.freeVector.y != 0                      )
@@ -6286,7 +6319,8 @@
         distance = org_dist;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( CUR.ignore_x_mode        &&
+      if ( SUBPIXEL_HINTING         &&
+           CUR.ignore_x_mode        &&
            CUR.GS.freeVector.x != 0 )
         distance = ROUND_None( distance,
                                CUR.tt_metrics.compensations[0] );
@@ -6320,13 +6354,13 @@
     minimum_distance = CUR.GS.minimum_distance;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                                 &&
+    if ( SUBPIXEL_HINTING                                  &&
+         CUR.ignore_x_mode                                 &&
          CUR.GS.freeVector.x != 0                          &&
          !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
       minimum_distance = 0;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
-
     point = (FT_UShort)args[0];
 
     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
@@ -6390,7 +6424,9 @@
     if ( ( CUR.opcode & 4 ) != 0 )
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( CUR.ignore_x_mode && CUR.GS.freeVector.x != 0 )
+      if ( SUBPIXEL_HINTING         &&
+           CUR.ignore_x_mode        &&
+           CUR.GS.freeVector.x != 0 )
         distance = ROUND_None(
                      org_dist,
                      CUR.tt_metrics.compensations[CUR.opcode & 3] );
@@ -6468,7 +6504,8 @@
     cvtEntry            = (FT_ULong)( args[1] + 1 );
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                                 &&
+    if ( SUBPIXEL_HINTING                                  &&
+         CUR.ignore_x_mode                                 &&
          CUR.GS.freeVector.x != 0                          &&
          !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
       control_value_cutin = minimum_distance = 0;
@@ -6489,10 +6526,12 @@
       cvt_dist = 0;
     else
       cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( CUR.ignore_x_mode                                 &&
-           ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) )
-        cvt_dist = 0;
+    if ( SUBPIXEL_HINTING                                  &&
+         CUR.ignore_x_mode                                 &&
+         ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) )
+      cvt_dist = 0;
 #endif
 
     /* single width test */
@@ -6531,8 +6570,10 @@
       if ( ( org_dist ^ cvt_dist ) < 0 )
         cvt_dist = -cvt_dist;
     }
+
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                                        &&
+    if ( SUBPIXEL_HINTING                                         &&
+         CUR.ignore_x_mode                                        &&
          CUR.GS.freeVector.y != 0                                 &&
          ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
     {
@@ -6542,6 +6583,7 @@
         cvt_dist += 32;
     }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     /* control value cut-in and round */
 
     if ( ( CUR.opcode & 4 ) != 0 )
@@ -6572,23 +6614,23 @@
                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
     }
     else
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     {
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
       /* do cvt cut-in always in MIRP for sph */
-      if ( CUR.ignore_x_mode && CUR.GS.gep0 == CUR.GS.gep1 )
+      if ( SUBPIXEL_HINTING           &&
+           CUR.ignore_x_mode          &&
+           CUR.GS.gep0 == CUR.GS.gep1 )
       {
         if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
           cvt_dist = org_dist;
       }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
       distance = ROUND_None(
                    cvt_dist,
                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
     }
-#else
-      distance = ROUND_None(
-                   cvt_dist,
-                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     /* minimum distance test */
 
@@ -6607,52 +6649,58 @@
     }
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    B1 = CUR.zp1.cur[point].y;
+    if ( SUBPIXEL_HINTING )
+    {
+      B1 = CUR.zp1.cur[point].y;
 
-    /* Round moves if necessary */
-    if ( CUR.ignore_x_mode                                          &&
-         CUR.GS.freeVector.y != 0                                   &&
-         ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
-      distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
+      /* Round moves if necessary */
+      if ( CUR.ignore_x_mode                                          &&
+           CUR.GS.freeVector.y != 0                                   &&
+           ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
+        distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
 
-    if ( CUR.ignore_x_mode                                      &&
-         CUR.GS.freeVector.y != 0                               &&
-         ( CUR.opcode & 16 ) == 0                               &&
-         ( CUR.opcode & 8 ) == 0                                &&
-         ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
-      distance += 64;
+      if ( CUR.ignore_x_mode                                      &&
+           CUR.GS.freeVector.y != 0                               &&
+           ( CUR.opcode & 16 ) == 0                               &&
+           ( CUR.opcode & 8 ) == 0                                &&
+           ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
+        distance += 64;
+    }
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    B2 = CUR.zp1.cur[point].y;
-
-    /* Reverse move if necessary */
-    if ( CUR.ignore_x_mode )
+    if ( SUBPIXEL_HINTING )
     {
-      if ( CUR.face->sph_compatibility_mode                          &&
-           CUR.GS.freeVector.y != 0                                  &&
-           ( B1 & 63 ) == 0                                          &&
-           ( B2 & 63 ) != 0                                          )
-        reverse_move = TRUE;
+      B2 = CUR.zp1.cur[point].y;
 
-      if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
-           CUR.GS.freeVector.y != 0                                  &&
-           ( B2 & 63 ) != 0                                          &&
-           ( B1 & 63 ) != 0                                          )
-        reverse_move = TRUE;
+      /* Reverse move if necessary */
+      if ( CUR.ignore_x_mode )
+      {
+        if ( CUR.face->sph_compatibility_mode                          &&
+             CUR.GS.freeVector.y != 0                                  &&
+             ( B1 & 63 ) == 0                                          &&
+             ( B2 & 63 ) != 0                                          )
+          reverse_move = TRUE;
 
-      if ( ( CUR.sph_tweak_flags                      &
-             SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) &&
-           !reverse_move                                &&
-           FT_ABS( B1 - B2 ) >= 64                      )
-        reverse_move = TRUE;
-    }
+        if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
+             CUR.GS.freeVector.y != 0                                  &&
+             ( B2 & 63 ) != 0                                          &&
+             ( B1 & 63 ) != 0                                          )
+          reverse_move = TRUE;
 
-    if ( reverse_move )
-      CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
+        if ( ( CUR.sph_tweak_flags                      &
+               SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) &&
+             !reverse_move                                &&
+             FT_ABS( B1 - B2 ) >= 64                      )
+          reverse_move = TRUE;
+      }
 
+      if ( reverse_move )
+        CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
+    }
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
   Fail:
@@ -6681,7 +6729,8 @@
 
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode                                        &&
+    if ( SUBPIXEL_HINTING                                         &&
+         CUR.ignore_x_mode                                        &&
          CUR.iup_called                                           &&
          ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
     {
@@ -7212,7 +7261,8 @@
     point   = 0;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode )
+    if ( SUBPIXEL_HINTING  &&
+         CUR.ignore_x_mode )
     {
       CUR.iup_called = 1;
       if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
@@ -7366,67 +7416,76 @@
           B = B * 64 / ( 1L << CUR.GS.delta_shift );
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-          /*
-           *  Allow delta move if
-           *
-           *  - not using ignore_x_mode rendering
-           *  - glyph is specifically set to allow it
-           *  - glyph is composite and freedom vector is not subpixel vector
-           */
-          if ( !CUR.ignore_x_mode                                   ||
-               ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
-               ( CUR.is_composite && CUR.GS.freeVector.y != 0 )     )
-            CUR_Func_move( &CUR.zp0, A, B );
 
-          /* Otherwise apply subpixel hinting and compatibility mode rules */
-          else if ( CUR.ignore_x_mode )
+          if ( SUBPIXEL_HINTING )
           {
-            if ( CUR.GS.freeVector.y != 0 )
-              B1 = CUR.zp0.cur[A].y;
-            else
-              B1 = CUR.zp0.cur[A].x;
-#if 0
-            /* Standard Subpixel Hinting: Allow y move.       */
-            /* This messes up dejavu and may not be needed... */
-            if ( !CUR.face->sph_compatibility_mode &&
-                 CUR.GS.freeVector.y != 0           )
+            /*
+             *  Allow delta move if
+             *
+             *  - not using ignore_x_mode rendering
+             *  - glyph is specifically set to allow it
+             *  - glyph is composite and freedom vector is not subpixel
+             *    vector
+             */
+            if ( !CUR.ignore_x_mode                                   ||
+                 ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
+                 ( CUR.is_composite && CUR.GS.freeVector.y != 0 )     )
               CUR_Func_move( &CUR.zp0, A, B );
-            else
-#endif
-            /* Compatibility Mode: Allow x or y move if point touched in */
-            /* Y direction.                                              */
-            if ( CUR.face->sph_compatibility_mode                      &&
-                 !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
+
+            /* Otherwise apply subpixel hinting and */
+            /* compatibility mode rules             */
+            else if ( CUR.ignore_x_mode )
             {
-              /* save the y value of the point now; compare after move */
-              B1 = CUR.zp0.cur[A].y;
+              if ( CUR.GS.freeVector.y != 0 )
+                B1 = CUR.zp0.cur[A].y;
+              else
+                B1 = CUR.zp0.cur[A].x;
 
-              if ( ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
-                B = FT_PIX_ROUND( B1 + B ) - B1;
-
-              /* Allow delta move if using sph_compatibility_mode,   */
-              /* IUP has not been called, and point is touched on Y. */
-              if ( !CUR.iup_called                            &&
-                   ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
+#if 0
+              /* Standard Subpixel Hinting: Allow y move.       */
+              /* This messes up dejavu and may not be needed... */
+              if ( !CUR.face->sph_compatibility_mode &&
+                   CUR.GS.freeVector.y != 0           )
                 CUR_Func_move( &CUR.zp0, A, B );
-            }
+              else
+#endif /* 0 */
 
-            B2 = CUR.zp0.cur[A].y;
+              /* Compatibility Mode: Allow x or y move if point touched in */
+              /* Y direction.                                              */
+              if ( CUR.face->sph_compatibility_mode                      &&
+                   !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
+              {
+                /* save the y value of the point now; compare after move */
+                B1 = CUR.zp0.cur[A].y;
 
-            /* Reverse this move if it results in a disallowed move */
-            if ( CUR.GS.freeVector.y != 0                    &&
-                 ( ( CUR.face->sph_compatibility_mode    &&
-                     ( B1 & 63 ) == 0                    &&
-                     ( B2 & 63 ) != 0                    ) ||
-                   ( ( CUR.sph_tweak_flags             &
-                       SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
-                     ( B1 & 63 ) != 0                    &&
-                     ( B2 & 63 ) != 0                    ) ) )
-              CUR_Func_move( &CUR.zp0, A, -B );
+                if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
+                  B = FT_PIX_ROUND( B1 + B ) - B1;
+
+                /* Allow delta move if using sph_compatibility_mode,   */
+                /* IUP has not been called, and point is touched on Y. */
+                if ( !CUR.iup_called                            &&
+                     ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
+                  CUR_Func_move( &CUR.zp0, A, B );
+              }
+
+              B2 = CUR.zp0.cur[A].y;
+
+              /* Reverse this move if it results in a disallowed move */
+              if ( CUR.GS.freeVector.y != 0                    &&
+                   ( ( CUR.face->sph_compatibility_mode    &&
+                       ( B1 & 63 ) == 0                    &&
+                       ( B2 & 63 ) != 0                    ) ||
+                     ( ( CUR.sph_tweak_flags             &
+                         SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
+                       ( B1 & 63 ) != 0                    &&
+                       ( B2 & 63 ) != 0                    ) ) )
+                CUR_Func_move( &CUR.zp0, A, -B );
+            }
           }
-#else
-          CUR_Func_move( &CUR.zp0, A, B );
-#endif /* *TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+          else
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+            CUR_Func_move( &CUR.zp0, A, B );
         }
       }
       else
@@ -7562,7 +7621,9 @@
     /* Selector Bit:  0             */
     /* Return Bit(s): 0-7           */
     /*                              */
-    if ( ( args[0] & 1 ) != 0 && CUR.ignore_x_mode )
+    if ( SUBPIXEL_HINTING     &&
+         ( args[0] & 1 ) != 0 &&
+         CUR.ignore_x_mode    )
     {
       K = CUR.rasterizer_version;
       FT_TRACE7(( "Setting rasterizer version %d\n",
@@ -7571,7 +7632,7 @@
     else
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
       if ( ( args[0] & 1 ) != 0 )
-        K = 35;
+        K = TT_INTERPRETER_VERSION_35;
 
     /********************************/
     /* GLYPH ROTATED                */
@@ -7598,7 +7659,10 @@
       K |= 1 << 12;
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode && CUR.rasterizer_version >= 35 )
+
+    if ( SUBPIXEL_HINTING                                    &&
+         CUR.ignore_x_mode                                   &&
+         CUR.rasterizer_version >= TT_INTERPRETER_VERSION_35 )
     {
       /********************************/
       /* HINTING FOR GRAYSCALE        */
@@ -7661,7 +7725,9 @@
         }
       }
     }
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     args[0] = K;
   }
 
@@ -8313,10 +8379,12 @@
 
         case 0x2B:  /* CALL */
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-          if ( !CUR.ignore_x_mode                                         ||
-               !CUR.iup_called                                            ||
-               ( CUR.iup_called                                         &&
-                 !( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) )
+          if ( !SUBPIXEL_HINTING                        ||
+               ( !CUR.ignore_x_mode                   ||
+                 !CUR.iup_called                      ||
+                 ( CUR.iup_called                   &&
+                   !( CUR.sph_tweak_flags         &
+                      SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
             Ins_CALL( EXEC_ARG_ args );
           break;
@@ -8337,10 +8405,12 @@
         case 0x30:  /* IUP */
         case 0x31:  /* IUP */
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-          if ( CUR.ignore_x_mode )
+          if ( SUBPIXEL_HINTING  &&
+               CUR.ignore_x_mode )
             CUR.iup_called = TRUE;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-            Ins_IUP( EXEC_ARG_ args );
+
+          Ins_IUP( EXEC_ARG_ args );
           break;
 
         case 0x32:  /* SHP */
@@ -8500,10 +8570,12 @@
 
         case 0x5D:  /* DELTAP1 */
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-          if ( !CUR.ignore_x_mode                                           ||
-               !CUR.iup_called                                              ||
-               ( CUR.iup_called                                           &&
-                 !( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) )
+          if ( !SUBPIXEL_HINTING                          ||
+               ( !CUR.ignore_x_mode                     ||
+                 !CUR.iup_called                        ||
+                 ( CUR.iup_called                     &&
+                   !( CUR.sph_tweak_flags           &
+                      SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) ) )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
             Ins_DELTAP( EXEC_ARG_ args );
           break;
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -21,6 +21,7 @@
 #include FT_INTERNAL_STREAM_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_DRIVER_H
 
 #include "ttgload.h"
 #include "ttpload.h"
@@ -1259,11 +1260,17 @@
     if ( !TT_New_Context( driver ) )
       return FT_THROW( Could_Not_Find_Context );
 
+#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 */
+
     FT_UNUSED( ttdriver );
 
-#endif
+#endif /* !TT_USE_BYTECODE_INTERPRETER */
 
     return FT_Err_Ok;
   }
--- a/src/truetype/ttobjs.h
+++ b/src/truetype/ttobjs.h
@@ -347,11 +347,12 @@
   /*                                                                       */
   typedef struct  TT_DriverRec_
   {
-    FT_DriverRec     root;
+    FT_DriverRec  root;
+
     TT_ExecContext   context;  /* execution context        */
     TT_GlyphZoneRec  zone;     /* glyph loader points zone */
 
-    void*            extension_component;
+    FT_UInt  interpreter_version;
 
   } TT_DriverRec;
 
--- a/src/truetype/ttsubpix.c
+++ b/src/truetype/ttsubpix.c
@@ -22,6 +22,7 @@
 #include FT_INTERNAL_SFNT_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_OUTLINE_H
+#include FT_TRUETYPE_DRIVER_H
 
 #include "ttsubpix.h"
 
@@ -1027,9 +1028,9 @@
 
     if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
     {
-      if ( loader->exec->rasterizer_version != 35 )
+      if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 )
       {
-        loader->exec->rasterizer_version = 35;
+        loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
         loader->exec->size->cvt_ready    = FALSE;
 
         tt_size_ready_bytecode(
@@ -1037,7 +1038,7 @@
           FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
       }
       else
-        loader->exec->rasterizer_version = 35;
+        loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
     }
     else
     {