shithub: freetype+ttf2subf

Download patch

ref: a5fe359596df306666b7f5abc13f1b605359d22c
parent: 610ee58e07090ead529849b2a454bb6c503b4995
author: Infinality <[email protected]>
date: Sat Jan 26 07:29:52 EST 2013

[truetype] Align more to ClearType whitepaper for sph.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,56 @@
+2013-01-26  Infinality  <[email protected]>
+
+	[truetype] Align more to ClearType whitepaper for sph.
+
+	* include/freetype/internal/tttypes.h (TT_FaceRec): Add flags
+	for detected fdefs and compatibility mode.
+
+	* src/truetype/ttgload.c (tt_loader_init): Complete conditional.
+
+	* src/truetype/ttinterp.c: Updated. Remove SPH_DEBUG and replace 
+	with FT_TRACE7.
+	(DO_RS): More conditions.
+	(Ins_FDEF): Add more opcode detection patterns. More specific 
+	conditions when flagging a fdef. Make compatibility mode only turn 
+	on when delta fdefs are found.
+	(Ins_CALL, Ins_LOOPCALL): Set flags for currently executing fdef.
+	(Ins_SHPIX): Remove logic to handle ttfautohinted fonts.  Simplify
+	conditionals where possible. Use & instead of % operator for dumb
+	compilers.
+	(Ins_MIAP): Adjust twilight zone conditional. Ensure ingore_x_mode
+	is on when testing sph conditionals.
+	(Ins_MIRP): Ensure ingore_x_mode is on when testing sph conditionals.
+	Do cvt cutin always when in ignore_x_mode.  Remove test for 
+	ttfautohinted fonts.
+	(Ins_DELTAP): Ensure ingore_x_mode is on when testing sph conditionals.
+	Do cvt cutin always when in ignore_x_mode.  Remove test for 
+	ttfautohinted fonts. Use & instead of % operator for dumb
+	compilers.
+	(Ins_GETINFO): Remove SPH_DEBUG and replace with FT_TRACE7.
+
+	* src/truetype/ttinterp.h: Updated.
+	(TT_ExecContextRec): Remove compatibility_mode variable.  Add variable
+	to indicate when executing in special fdefs for sph.
+
+	* src/truetype/ttobjs.h: Updated.
+	(TT_DefRecord): Add flags to identify special fdefs for sph.
+	(TT_SizeRec): Remove unnecessary ttfautohinted variable.
+
+	* src/truetype/ttsubpix.c: Updated.
+	(COMPATIBILITY_MODE_Rules): Remove all. Auto-detected now.
+	(PIXEL_HINTING_Rules): Remove all. Unnecessary after fixes.
+	(SKIP_NONPIXEL_Y_MOVES_Rules): Remove Ubuntu.
+	(SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions): Add Arial Bold `N'.
+	(SKIP_OFFPIXEL_Y_MOVES_Rules): Remove all. Happens automatically now.
+	(ROUND_NONPIXEL_Y_MOVES_Rules): Remove Ubuntu.
+	(ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions): Remove all.
+	(NORMAL_ROUND_Rules): Remove Verdana.
+	(NO_DELTAP_AFTER_IUP_Rules): Remove all.
+	(sph_set_tweaks): Performance fix. Don't run prep always. Adjust
+	conditional for sph_compatibility_mode.
+
+	* src/truetype/ttsubpix.h: Add new fdef flags for sph.
+
 2013-01-23  Alexei Podtelezhnikov  <[email protected]>
 
 	[base] Fix broken emboldening at small sizes.
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1428,6 +1428,12 @@
     FT_ULong              horz_metrics_offset;
     FT_ULong              vert_metrics_offset;
 
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    FT_ULong              sph_found_func_flags; /* special funcs identified */
+                                                /* for this face            */
+    FT_Bool               sph_compatibility_mode;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
   } TT_FaceRec;
 
 
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -1949,6 +1949,8 @@
         grayscale = grayscale_hinting = TRUE;
         subpixel_hinting = FALSE;
       }
+      else
+        grayscale = grayscale_hinting = FALSE;
 
       if ( FT_IS_TRICKY( glyph->face ) )
         subpixel_hinting = grayscale_hinting = FALSE;
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -34,10 +34,6 @@
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
 
-#define xxxSPH_DEBUG
-#define xxxSPH_DEBUG_MORE_VERBOSE
-
-
   /*************************************************************************/
   /*                                                                       */
   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
@@ -3169,14 +3165,23 @@
        /* subpixel hinting - avoid Typeman Dstroke and */ \
        /* IStroke and Vacuform rounds                  */ \
                                                           \
-       if ( CUR.compatibility_mode           &&           \
-            ( I == 24 || I == 22 || I == 8 ) )            \
+      if ( CUR.ignore_x_mode                          &&  \
+           ( ( I == 24                            &&      \
+               ( CUR.face->sph_found_func_flags &         \
+                 ( SPH_FDEF_SPACING_1 |                   \
+                   SPH_FDEF_SPACING_2 )         ) ) ||    \
+             ( I == 22                      &&            \
+               ( CUR.sph_in_func_flags    &               \
+                 SPH_FDEF_TYPEMAN_STROKES ) )       ||    \
+             ( I == 8                             &&      \
+               ( CUR.face->sph_found_func_flags &         \
+                 SPH_FDEF_VACUFORM_ROUND_1      ) &&      \
+                 CUR.iup_called                   ) ) )   \
          args[0] = 0;                                     \
        else                                               \
          args[0] = CUR.storage[I];                        \
      }                                                    \
    }
-
 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
 #define DO_RS                           \
@@ -4458,10 +4463,59 @@
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     /* arguments to opcodes are skipped by `SKIP_Code' */
-    FT_Byte    opcode_pattern[1][12] = {
-                 /* #0 TTFautohint bytecode (old) */
+    FT_Byte    opcode_pattern[7][12] = {
+                 /* #0 inline delta function 1 */
                  {
+                   0x4B, /* PPEM    */
+                   0x53, /* GTEQ    */
+                   0x23, /* SWAP    */
+                   0x4B, /* PPEM    */
+                   0x51, /* LTEQ    */
+                   0x5A, /* AND     */
+                   0x58, /* IF      */
+                   0x38, /*   SHPIX */
+                   0x1B, /* ELSE    */
+                   0x21, /*   POP   */
+                   0x21, /*   POP   */
+                   0x59  /* EIF     */
+                 },
+                 /* #1 inline delta function 2 */
+                 {
+                   0x4B, /* PPEM    */
+                   0x54, /* EQ      */
+                   0x58, /* IF      */
+                   0x38, /*   SHPIX */
+                   0x1B, /* ELSE    */
+                   0x21, /*   POP   */
+                   0x21, /*   POP   */
+                   0x59  /* EIF     */
+                 },
+                 /* #2 diagonal stroke function */
+                 {
                    0x20, /* DUP     */
+                   0x20, /* DUP     */
+                   0xB0, /* PUSHB_1 */
+                         /*   1     */
+                   0x60, /* ADD     */
+                   0x46, /* GC_cur  */
+                   0xB0, /* PUSHB_1 */
+                         /*   64    */
+                   0x23, /* SWAP    */
+                   0x42  /* WS      */
+                 },
+                 /* #3 VacuFormRound function */
+                 {
+                   0x45, /* RCVT    */
+                   0x23, /* SWAP    */
+                   0x46, /* GC_cur  */
+                   0x60, /* ADD     */
+                   0x20, /* DUP     */
+                   0xB0  /* PUSHB_1 */
+                         /*   38    */
+                 },
+                 /* #4 TTFautohint bytecode (old) */
+                 {
+                   0x20, /* DUP     */
                    0x64, /* ABS     */
                    0xB0, /* PUSHB_1 */
                          /*   32    */
@@ -4470,10 +4524,27 @@
                    0x23, /* SWAP    */
                    0xB0  /* PUSHB_1 */
                  },
+                 /* #5 spacing function 1 */
+                 {
+                   0x01, /* SVTCA_x */
+                   0xB0, /* PUSHB_1 */
+                         /*   24    */
+                   0x43, /* RS      */
+                   0x58  /* IF      */
+                 },
+                 /* #6 spacing function 2 */
+                 {
+                   0x01, /* SVTCA_x */
+                   0x18, /* RTG     */
+                   0xB0, /* PUSHB_1 */
+                         /*   24    */
+                   0x43, /* RS      */
+                   0x58  /* IF      */
+                 },
                };
-    FT_UShort  opcode_patterns   = 1;
-    FT_UShort  opcode_pointer[1] = { 0, };
-    FT_UShort  opcode_size[1]    = { 7, };
+    FT_UShort  opcode_patterns   = 7;
+    FT_UShort  opcode_pointer[7] = {  0, 0, 0, 0, 0, 0, 0 };
+    FT_UShort  opcode_size[7]    = { 12, 8, 8, 6, 7, 4, 5 };
     FT_UShort  i;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
@@ -4515,10 +4586,18 @@
     rec->start        = CUR.IP + 1;
     rec->active       = TRUE;
     rec->inline_delta = FALSE;
+    rec->sph_fdef_flags = 0x0000;
 
     if ( n > CUR.maxFunc )
       CUR.maxFunc = (FT_UInt16)n;
 
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    /* We don't know for sure these are typeman functions, */
+    /* however they are only active when RS 22 is called   */
+    if ( n >= 64 && n <= 66 )
+      rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
+#endif
+
     /* Now skip the whole function definition. */
     /* We don't allow nested IDEFS & FDEFs.    */
 
@@ -4526,33 +4605,85 @@
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
-#ifdef SPH_DEBUG_MORE_VERBOSE
-      printf ( "Opcode: %d ", CUR.opcode );
-#endif
-
       for ( i = 0; i < opcode_patterns; i++ )
       {
         if ( opcode_pointer[i] < opcode_size[i]                 &&
              CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
         {
-#ifdef SPH_DEBUG_MORE_VERBOSE
-          printf( "function %d, opcode ptrn: %d"
-                  "  op# %d: %d FOUND \n",
-                  n, i, opcode_pointer[i], CUR.opcode );
-#endif
           opcode_pointer[i] += 1;
 
           if ( opcode_pointer[i] == opcode_size[i] )
           {
-#ifdef SPH_DEBUG
-            printf( "Function signature %d detected in FDEF %d\n", i, n);
-#endif
 
+            FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n", i, n,
+                        CUR.face->root.family_name,
+                        CUR.face->root.style_name ));
+
             switch ( i )
             {
             case 0:
-              CUR.size->ttfautohinted = TRUE;
+              rec->sph_fdef_flags            |= SPH_FDEF_INLINE_DELTA_1;
+              CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
               break;
+
+            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 )
+              {
+              /* 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:
+              /* 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;
+
             }
             opcode_pointer[i] = 0;
           }
@@ -4562,6 +4693,12 @@
           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 ) );
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
       switch ( CUR.opcode )
@@ -4607,15 +4744,6 @@
 
     CUR.step_ins = FALSE;
 
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    /*
-     *  CUR.ignore_x_mode may be turned off prior to function calls.  This
-     *  ensures it is turned back on.
-     */
-    CUR.ignore_x_mode =  ( CUR.subpixel_hinting || CUR.grayscale_hinting ) &&
-                        !( CUR.sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING );
-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
-
     if ( pRec->Cur_Count > 0 )
     {
       CUR.callTop++;
@@ -4686,6 +4814,9 @@
     if ( !def->active )
       goto Fail;
 
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    CUR.sph_in_func_flags &= def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     /* check the call stack */
     if ( CUR.callTop >= CUR.callSize )
@@ -4708,6 +4839,11 @@
                         def->start );
 
     CUR.step_ins = FALSE;
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    CUR.sph_in_func_flags &= !def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     return;
 
   Fail:
@@ -4764,6 +4900,10 @@
     if ( !def->active )
       goto Fail;
 
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    CUR.sph_in_func_flags &= def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     /* check stack */
     if ( CUR.callTop >= CUR.callSize )
     {
@@ -4788,6 +4928,10 @@
       CUR.step_ins = FALSE;
     }
 
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+    CUR.sph_in_func_flags &= !def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
     return;
 
   Fail:
@@ -5874,7 +6018,7 @@
         /*  If not using ignore_x_mode rendering, allow ZP2 move.          */
         /*  If inline deltas aren't allowed, skip ZP2 move.                */
         /*  If using ignore_x_mode rendering, allow ZP2 point move if:     */
-        /*   - freedom vector is y and compatibility_mode is off           */
+        /*   - freedom vector is y and sph_compatibility_mode is off       */
         /*   - the glyph is composite and the move is in the Y direction   */
         /*   - the glyph is specifically set to allow SHPIX moves          */
         /*   - the move is on a previously Y-touched point                 */
@@ -5891,14 +6035,12 @@
                ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_INLINE_DELTAS ) )
             goto Skip;
 
-          if ( CUR.ignore_x_mode                                   &&
-               !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
+          if ( !CUR.face->sph_compatibility_mode && CUR.GS.freeVector.y != 0 )
             MOVE_Zp2_Point( point, dx, dy, TRUE );
 
-          else if ( CUR.ignore_x_mode && CUR.compatibility_mode )
+          else if ( CUR.face->sph_compatibility_mode )
           {
-            if ( CUR.ignore_x_mode                                         &&
-                ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
+            if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
             {
               dx = FT_PIX_ROUND( B1 + dx ) - B1;
               dy = FT_PIX_ROUND( B1 + dy ) - B1;
@@ -5920,21 +6062,15 @@
           /* reverse any disallowed moves */
           if ( ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
                  CUR.GS.freeVector.y != 0                                  &&
-                 B1 % 64 != 0                                              &&
-                 B2 % 64 != 0                                              &&
+                 ( B1 & 63 ) != 0                                          &&
+                 ( B2 & 63 ) != 0                                          &&
                  B1 != B2                                                  ) ||
-               ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
+               ( CUR.face->sph_compatibility_mode                          &&
                  CUR.GS.freeVector.y != 0                                  &&
-                 B1 % 64 == 0                                              &&
-                 B2 % 64 != 0                                              &&
-                 B1 != B2                                                  &&
-                 !CUR.size->ttfautohinted                                  ) )
-          {
-#ifdef SPH_DEBUG
-            printf( "Reversing ZP2 move\n" );
-#endif
+                 ( B1 & 63 ) == 0                                          &&
+                 ( B2 & 63 ) != 0                                          &&
+                 B1 != B2                                                ) )
             MOVE_Zp2_Point( point, -dx, -dy, TRUE );
-          }
       }
         else
           MOVE_Zp2_Point( point, dx, dy, TRUE );
@@ -6124,8 +6260,9 @@
     if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      /* only adjust legacy fonts x otherwise breaks Calibri italic */
-      if ( CUR.compatibility_mode )
+      /* Only adjust when 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 )
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
         CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
                                             CUR.GS.freeVector.x );
@@ -6134,7 +6271,8 @@
       CUR.zp0.cur[point]   = CUR.zp0.org[point];
     }
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
+    if ( CUR.ignore_x_mode                             &&
+         ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
          distance > 0                                  &&
          CUR.GS.freeVector.y != 0                      )
       distance = 0;
@@ -6352,7 +6490,8 @@
     else
       cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      if ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO )
+      if ( CUR.ignore_x_mode                                 &&
+           ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) )
         cvt_dist = 0;
 #endif
 
@@ -6393,7 +6532,8 @@
         cvt_dist = -cvt_dist;
     }
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.GS.freeVector.y != 0                                 &&
+    if ( CUR.ignore_x_mode                                        &&
+         CUR.GS.freeVector.y != 0                                 &&
          ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
     {
       if ( cur_dist < -64 )
@@ -6432,9 +6572,23 @@
                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
     }
     else
+#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 ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
+          cvt_dist = org_dist;
+      }
       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 */
 
@@ -6461,7 +6615,8 @@
          ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
       distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
 
-    if ( CUR.GS.freeVector.y != 0                               &&
+    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 ) )
@@ -6476,17 +6631,16 @@
     /* Reverse move if necessary */
     if ( CUR.ignore_x_mode )
     {
-      if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
+      if ( CUR.face->sph_compatibility_mode                          &&
            CUR.GS.freeVector.y != 0                                  &&
-           B1 % 64 == 0                                              &&
-           B2 % 64 != 0                                              &&
-           !CUR.size->ttfautohinted                                  )
+           ( B1 & 63 ) == 0                                          &&
+           ( B2 & 63 ) != 0                                          )
         reverse_move = TRUE;
 
       if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
            CUR.GS.freeVector.y != 0                                  &&
-           B2 % 64 != 0                                              &&
-           B1 % 64 != 0                                              )
+           ( B2 & 63 ) != 0                                          &&
+           ( B1 & 63 ) != 0                                          )
         reverse_move = TRUE;
 
       if ( ( CUR.sph_tweak_flags &
@@ -7216,15 +7370,18 @@
               B1 = CUR.zp0.cur[A].y;
             else
               B1 = CUR.zp0.cur[A].x;
-
-            /* Standard Subpixel Hinting:  Allow y move */
-            if ( !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
+#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
             /* Compatibility Mode: Allow x or y move if point touched in
                 Y direction */
-            else if ( CUR.compatibility_mode                                  &&
-                      !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
+            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;
@@ -7233,7 +7390,7 @@
                 B = FT_PIX_ROUND( B1 + B ) - B1;
 
               /*
-              *  Allow delta move if using compatibility_mode, IUP has not
+              *  Allow delta move if using sph_compatibility_mode, IUP has not
               *  been called, and point is touched on Y.
               */
               if ( !CUR.iup_called                            &&
@@ -7245,15 +7402,13 @@
 
             /* Reverse this move if it results in a disallowed move */
             if ( CUR.GS.freeVector.y != 0                     &&
-                 ( ( ( CUR.sph_tweak_flags &
-                        SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
-                        B1 % 64 == 0                      &&
-                        B2 % 64 != 0                      &&
-                        !CUR.size->ttfautohinted          ) ||
+                 ( ( CUR.face->sph_compatibility_mode     &&
+                        ( B1 & 63 ) == 0                  &&
+                        ( B2 & 63 ) != 0                  ) ||
                    ( ( CUR.sph_tweak_flags &
                         SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
-                        B1 % 64 != 0                      &&
-                        B2 % 64 != 0                      ) ) )
+                        ( B1 & 63 ) != 0                  &&
+                        ( B2 & 63 ) != 0                  ) ) )
               CUR_Func_move( &CUR.zp0, A, -B );
           }
 #else
@@ -7397,9 +7552,7 @@
     if ( ( args[0] & 1 ) != 0 && CUR.ignore_x_mode )
     {
       K = CUR.rasterizer_version;
-#ifdef SPH_DEBUG_MORE_VERBOSE
-      printf(" SETTING AS %d\n", CUR.rasterizer_version );
-#endif
+      FT_TRACE7(( "Setting rasterizer version %d\n", CUR.rasterizer_version ));
     }
     else
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
@@ -7871,8 +8024,7 @@
 #endif
 
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    if ( CUR.ignore_x_mode )
-      CUR.iup_called        = FALSE;
+    CUR.iup_called        = FALSE;
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
     /* set CVT functions */
--- a/src/truetype/ttinterp.h
+++ b/src/truetype/ttinterp.h
@@ -269,10 +269,6 @@
     FT_Bool            ignore_x_mode;     /* Standard rendering mode for   */
                                           /* subpixel hinting.  On if gray */
                                           /* or subpixel hinting is on )   */
-    FT_Bool            compatibility_mode;/* Additional exceptions to      */
-                                          /* native TT rules for legacy    */
-                                          /* fonts.  Implies               */
-                                          /* ignore_x_mode.                */
 
     /* The following 4 aren't fully implemented but here for MS rasterizer */
     /* compatibility.                                                      */
@@ -286,8 +282,12 @@
 
     FT_Bool            iup_called;            /* IUP called for glyph?  */
 
-    FT_ULong           sph_tweak_flags;       /* flags to control */
-                                              /* hint tweaks      */
+    FT_ULong           sph_tweak_flags;       /* flags to control  */
+                                              /* hint tweaks       */
+
+    FT_ULong           sph_in_func_flags;     /* flags to indicate if in */
+                                              /* special functions       */
+
 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
   } TT_ExecContextRec;
--- a/src/truetype/ttobjs.h
+++ b/src/truetype/ttobjs.h
@@ -179,6 +179,7 @@
     FT_UInt  opc;          /* function #, or instruction code        */
     FT_Bool  active;       /* is it active?                          */
     FT_Bool  inline_delta; /* is function that defines inline delta? */
+    FT_ULong sph_fdef_flags; /* flags to identify special functions  */
 
   } TT_DefRecord, *TT_DefArray;
 
@@ -334,7 +335,6 @@
 
     FT_Bool            bytecode_ready;
     FT_Bool            cvt_ready;
-    FT_Bool            ttfautohinted;
 
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
--- a/src/truetype/ttsubpix.c
+++ b/src/truetype/ttsubpix.c
@@ -275,32 +275,24 @@
   };
 
 
-  /* Special fixes for known legacy fonts;                                 */
-  /* this is the primary workhorse rule for legacy fonts                   */
-#define COMPATIBILITY_MODE_RULES_SIZE  4
+  /* Force special legacy fixes for fonts;                                 */
+#define COMPATIBILITY_MODE_RULES_SIZE  1
 
   const SPH_TweakRule  COMPATIBILITY_MODE_Rules
                        [COMPATIBILITY_MODE_RULES_SIZE] =
   {
-    { "MS Legacy Fonts", 0, "", 0 },
-    { "Apple Legacy Fonts", 0, "", 0 },
-    { "Misc Legacy Fonts", 0, "", 0 },
-    { "Verdana Clones", 0, "", 0 },
+    { "-", 0, "", 0 },
   };
 
 
   /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting.         */
-#define PIXEL_HINTING_RULES_SIZE  4
+#define PIXEL_HINTING_RULES_SIZE  1
 
   const SPH_TweakRule  PIXEL_HINTING_Rules
                        [PIXEL_HINTING_RULES_SIZE] =
   {
     /* these characters are almost always safe */
-    { "", 0, "", '<' },
-    { "", 0, "", '>' },
-    /* fixes the vanishing stem */
-    { "Times New Roman", 0, "Bold", 'A' },
-    { "Times New Roman", 0, "Bold", 'V' },
+    { "-", 0, "", 0 },
   };
 
 
@@ -328,7 +320,7 @@
 
   /* Skip Y moves that start with a point that is not on a Y pixel         */
   /* boundary and don't move that point to a Y pixel boundary.             */
-#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE  10
+#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE  9
 
   const SPH_TweakRule  SKIP_NONPIXEL_Y_MOVES_Rules
                        [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
@@ -344,7 +336,6 @@
     /* Cyrillic small letter I */
     { "Legacy Sans Fonts", 0, "", 0x438 },
     { "Verdana Clones", 0, "",'N' },
-    { "Ubuntu", 0, "Regular Class", 'N' },
     /* Fix misshapen x */
     { "Verdana", 0, "Bold", 'x' },
     /* Fix misshapen s */
@@ -352,7 +343,7 @@
   };
 
 
-#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  6
+#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  7
 
   const SPH_TweakRule  SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
                        [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
@@ -363,22 +354,18 @@
     { "Verdana", 11, "Bold", 'x' },
     /* Cyrillic small letter I */
     { "Arial", 0, "", 0x438 },
+    { "Arial", 11, "Bold", 'N' },
     { "Trebuchet MS", 0, "Bold", 0 },
   };
 
 
   /* Skip Y moves that move a point off a Y pixel boundary.                */
-  /* This fixes Tahoma, Trebuchet oddities and some issues with `$'.       */
-#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE  5
+#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE  1
 
   const SPH_TweakRule  SKIP_OFFPIXEL_Y_MOVES_Rules
                        [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
   {
-    { "MS Legacy Fonts", 0, "", 0 },
-    { "Apple Legacy Fonts", 0, "", 0 },
-    { "Misc Legacy Fonts", 0, "", 0 },
-    { "Ubuntu", 0, "Regular Class", 0 },
-    { "Verdana Clones", 0, "", 0 },
+    { "-", 0, "", 0 },
   };
 
 
@@ -392,7 +379,7 @@
 
 
   /* Round moves that don't move a point to a Y pixel boundary.            */
-#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE  3
+#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE  2
 
   const SPH_TweakRule  ROUND_NONPIXEL_Y_MOVES_Rules
                        [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
@@ -400,18 +387,15 @@
     /* Droid font instructions don't snap Y to pixels */
     { "Droid Sans", 0, "Regular/Italic Class", 0 },
     { "Droid Sans Mono", 0, "", 0 },
-    { "Ubuntu", 0, "", 0 },
   };
 
 
-#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  3
+#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE  1
 
   const SPH_TweakRule  ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
                        [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
   {
-    { "Droid Sans", 12, "Bold", 0 },
-    { "Droid Sans", 13, "Bold", 0 },
-    { "Droid Sans", 16, "Bold", 0 },
+    { "-", 0, "", 0 },
   };
 
 
@@ -466,14 +450,13 @@
 
 
   /* Don't round to the subpixel grid.  Round to pixel grid.               */
-#define NORMAL_ROUND_RULES_SIZE  2
+#define NORMAL_ROUND_RULES_SIZE  1
 
   const SPH_TweakRule  NORMAL_ROUND_Rules
                        [NORMAL_ROUND_RULES_SIZE] =
   {
-    /* Fix point "explosions" */
+    /* Fix serif thickness */
     { "Courier New", 0, "", 0 },
-    { "Verdana", 10, "Regular", '4' },
   };
 
 
@@ -563,8 +546,7 @@
   static const SPH_TweakRule  DELTAP_SKIP_EXAGGERATED_VALUES_Rules
                               [DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE] =
   {
-    /* Fix vanishing stems */
-    { "Ubuntu", 0, "Regular", 'M' },
+    { "-", 0, "", 0 },
   };
 
 
@@ -583,13 +565,12 @@
 
 
   /* Don't allow DELTAP after IUP.                                         */
-#define NO_DELTAP_AFTER_IUP_RULES_SIZE  2
+#define NO_DELTAP_AFTER_IUP_RULES_SIZE  1
 
   static const SPH_TweakRule  NO_DELTAP_AFTER_IUP_Rules
                               [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
   {
-    { "Arial", 0, "Bold", 'N' },
-    { "Verdana", 0, "Regular", '4' },
+    { "-", 0, "", 0 },
   };
 
 
@@ -1046,16 +1027,23 @@
     TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
     TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
 
-    if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
+    if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 &&
+         loader->exec->rasterizer_version != 35                  )
+    {
       loader->exec->rasterizer_version = 35;
-    else
+      loader->exec->size->cvt_ready = FALSE;
+      tt_size_ready_bytecode( loader->exec->size,
+                          FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
+    }
+    else if ( loader->exec->rasterizer_version  !=
+              SPH_OPTION_SET_RASTERIZER_VERSION )
+    {
       loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
+      loader->exec->size->cvt_ready = FALSE;
+      tt_size_ready_bytecode( loader->exec->size,
+                          FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
+    }
 
-    /* re-execute fpgm always to avoid problems */
-    loader->exec->size->cvt_ready = FALSE;
-    tt_size_ready_bytecode( loader->exec->size,
-                            FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
-
     if ( IS_HINTED( loader->load_flags ) )
     {
       TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
@@ -1064,12 +1052,8 @@
 
     if ( sph_test_tweak( face, family, ppem, style, glyph_index,
            COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
-    {
-      loader->exec->compatibility_mode |= TRUE;
-      loader->exec->ignore_x_mode      |= TRUE;
-    }
-    else
-      loader->exec->compatibility_mode &= FALSE;
+      loader->exec->face->sph_compatibility_mode = TRUE;
+
 
     if ( IS_HINTED( loader->load_flags ) )
     {
--- a/src/truetype/ttsubpix.h
+++ b/src/truetype/ttsubpix.h
@@ -31,6 +31,21 @@
 
   /*************************************************************************/
   /*                                                                       */
+  /* ID flags to identify special functions at FDEF and runtime.           */
+  /*                                                                       */
+  /*                                                                       */
+#define SPH_FDEF_INLINE_DELTA_1                   0x0000001
+#define SPH_FDEF_INLINE_DELTA_2                   0x0000002
+#define SPH_FDEF_DIAGONAL_STROKE                  0x0000004
+#define SPH_FDEF_VACUFORM_ROUND_1                 0x0000008
+#define SPH_FDEF_TTFAUTOHINT_1                    0x0000010
+#define SPH_FDEF_SPACING_1                        0x0000020
+#define SPH_FDEF_SPACING_2                        0x0000040
+#define SPH_FDEF_TYPEMAN_STROKES                  0x0000080
+
+
+  /*************************************************************************/
+  /*                                                                       */
   /* Tweak flags that are set for each glyph by the below rules.           */
   /*                                                                       */
   /*                                                                       */