Commit d52dd7f31d958980331fdffec70588785669a327

Ewald Hew 2017-09-25T08:22:26

Fix Type 1 hinting. Type 1 hinting breaks sometimes when mid-charstring hints should have been in the initial hintmap. This fix adds a preprocessing pass that reads all hints and builds the correct initial hintmap first, before proceeding to build the glyph outline. * src/psaux/psintrp.c (cf2_interpT2CharString): New `initial_map_ready' boolean flag. Ignore outline commands and hint changes on first pass. <cf2_cmdENDCHAR>: Add section to build hintmap and rewind.

diff --git a/ChangeLog b/ChangeLog
index 3ab15c5..7961ebe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2017-09-25  Ewald Hew  <ewaldhew@gmail.com>
 
+	[psaux] Fix Type 1 hinting.
+
+	Type 1 hinting breaks sometimes when mid-charstring hints should
+	have been in the initial hintmap.  This fix adds a preprocessing
+	pass that reads all hints and builds the correct initial hintmap
+	first, before proceeding to build the glyph outline.
+
+	* src/psaux/psintrp.c (cf2_interpT2CharString): New
+	`initial_map_ready' boolean flag.
+	Ignore outline commands and hint changes on first pass.
+	<cf2_cmdENDCHAR>: Add section to build hintmap and rewind.
+
+2017-09-25  Ewald Hew  <ewaldhew@gmail.com>
+
 	[psaux] Add tracing for hints.
 
 	* src/psaux/pshints.c (cf2_hintmap_dump): New function.
diff --git a/src/psaux/psintrp.c b/src/psaux/psintrp.c
index 77f2632..3e0590f 100644
--- a/src/psaux/psintrp.c
+++ b/src/psaux/psintrp.c
@@ -492,6 +492,7 @@
     /* Stuff for Type 1 */
     FT_Int     known_othersubr_result_cnt   = 0;
     FT_Bool    large_int = FALSE;
+    FT_Bool    initial_map_ready = FALSE;
 #define PS_STORAGE_SIZE 3
     CF2_F16Dot16  results[PS_STORAGE_SIZE];   /* for othersubr results */
     FT_Int        result_cnt = 0;
@@ -650,6 +651,20 @@
 
       if ( font->isT1 )
       {
+        if ( !initial_map_ready &&
+             !( op1 == cf2_cmdHSTEM    ||
+                op1 == cf2_cmdVSTEM    ||
+                op1 == cf2_cmdHSBW     ||
+                op1 == cf2_cmdCALLSUBR ||
+                op1 == cf2_cmdRETURN   ||
+                op1 == cf2_cmdESC      ||
+                op1 == cf2_cmdENDCHAR  ||
+                op1 >= 32 /* Numbers */ ) )
+        {
+          cf2_stack_clear( opStack );
+          continue;
+        }
+
         if ( result_cnt > 0 &&
              !( op1 == cf2_cmdCALLSUBR ||
                 op1 == cf2_cmdRETURN   ||
@@ -1478,8 +1493,11 @@
                       if ( builder->metrics_only )
                         goto exit;
 
-                      curX = ADD_INT32( curX, lsb_x );
-                      curY = ADD_INT32( curY, lsb_y );
+                      if ( initial_map_ready )
+                      {
+                        curX = ADD_INT32( curX, lsb_x );
+                        curY = ADD_INT32( curY, lsb_y );
+                      }
                     }
                   }
                   break;
@@ -1647,8 +1665,9 @@
                       if ( arg_cnt != 3 )
                         goto Unexpected_OtherSubr;
 
-                      if ( !decoder->flex_state           ||
-                           decoder->num_flex_vectors != 7 )
+                      if ( initial_map_ready &&
+                           ( !decoder->flex_state           ||
+                             decoder->num_flex_vectors != 7 ) )
                       {
                         FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
                                    " unexpected flex end\n" ));
@@ -1666,6 +1685,9 @@
                       if ( arg_cnt != 0 )
                         goto Unexpected_OtherSubr;
 
+                      if ( !initial_map_ready )
+                        break;
+
                       if ( ps_builder_check_points( &decoder->builder, 6 ) )
                         goto exit;
 
@@ -1682,6 +1704,9 @@
                       if ( arg_cnt != 0 )
                         goto Unexpected_OtherSubr;
 
+                      if ( !initial_map_ready )
+                        break;
+
                       if ( !decoder->flex_state )
                       {
                         FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
@@ -1728,12 +1753,15 @@
                       if ( arg_cnt != 1 )
                         goto Unexpected_OtherSubr;
 
-                      cf2_arrstack_clear( &vStemHintArray );
-                      cf2_arrstack_clear( &hStemHintArray );
+                      if ( initial_map_ready )
+                      {
+                        cf2_arrstack_clear( &vStemHintArray );
+                        cf2_arrstack_clear( &hStemHintArray );
 
-                      cf2_hintmask_init( &hintMask, error );
-                      hintMask.isValid = FALSE;
-                      hintMask.isNew   = TRUE;
+                        cf2_hintmask_init( &hintMask, error );
+                        hintMask.isValid = FALSE;
+                        hintMask.isNew   = TRUE;
+                      }
 
                       known_othersubr_result_cnt = 1;
                       break;
@@ -2281,6 +2309,9 @@
                   {
                     FT_TRACE4(( " setcurrentpoint" ));
 
+                    if ( !initial_map_ready )
+                      break;
+
                     /* From the T1 specification, section 6.4:                */
                     /*                                                        */
                     /*   The setcurrentpoint command is used only in          */
@@ -2351,13 +2382,38 @@
           if ( builder->metrics_only )
             goto exit;
 
-          curX = ADD_INT32( curX, lsb_x );
+          if ( initial_map_ready )
+            curX = ADD_INT32( curX, lsb_x );
         }
         break;
 
       case cf2_cmdENDCHAR:
         FT_TRACE4(( " endchar\n" ));
 
+        if ( font->isT1 && !initial_map_ready )
+        {
+          FT_TRACE5(( "cf2_interpT2CharString (Type 1 mode): "
+                      "Build initial hintmap, rewinding...\n" ));
+
+          /* Trigger initial hintmap build */
+          cf2_glyphpath_moveTo( &glyphPath, curX, curY );
+
+          initial_map_ready = TRUE;
+
+          /* Change hints routine - clear for rewind */
+          cf2_arrstack_clear( &vStemHintArray );
+          cf2_arrstack_clear( &hStemHintArray );
+
+          cf2_hintmask_init( &hintMask, error );
+          hintMask.isValid = FALSE;
+          hintMask.isNew   = TRUE;
+
+          /* Rewind charstring */
+          charstring->ptr = charstring->start;
+
+          break;
+        }
+
         if ( cf2_stack_count( opStack ) == 1 ||
              cf2_stack_count( opStack ) == 5 )
         {