Commit 78df3c27b651e3de068437ac35ee2214849badb9

Ewald Hew 2017-10-12T18:13:08

Extract width parsing from Type 1 parser. Duplicate the fast advance width calculations from the old parser. This is to facilitate adding options for compiling out the old parser. * src/psaux/t1decode.{c,h} (t1_decoder_parse_metrics): New function. * include/freetype/internal/psaux.h (T1_Decoder_Funcs): New entry `parse_metrics'. * src/psaux/psauxmod.c: Set the new entry. * src/type1/t1gload.c (T1_Parse_Glyph_And_Get_Char_String), src/cid/cidgload.c (cid_load_glyph): Separate conditional for selecting engine.

diff --git a/ChangeLog b/ChangeLog
index 0c0650f..e973ff8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2017-10-12  Ewald Hew  <ewaldhew@gmail.com>
+
+	Extract width parsing from Type 1 parser.
+
+	Duplicate the fast advance width calculations from the old parser.
+	This is to facilitate adding options for compiling out the old parser.
+
+	* src/psaux/t1decode.{c,h} (t1_decoder_parse_metrics): New function.
+	* include/freetype/internal/psaux.h (T1_Decoder_Funcs): New entry
+	`parse_metrics'.
+	* src/psaux/psauxmod.c: Set the new entry.
+
+	* src/type1/t1gload.c (T1_Parse_Glyph_And_Get_Char_String),
+	src/cid/cidgload.c (cid_load_glyph): Separate
+	conditional for selecting engine.
+
 2017-10-09  Werner Lemberg  <wl@gnu.org>
 
 	* src/base/ftoutln.c (FT_Outline_Translate): Fix integer overflow.
diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h
index 46c238a..96b2f1f 100644
--- a/include/freetype/internal/psaux.h
+++ b/include/freetype/internal/psaux.h
@@ -880,6 +880,11 @@ FT_BEGIN_HEADER
                               FT_UInt     len );
 
     FT_Error
+    (*parse_metrics)( T1_Decoder  decoder,
+                      FT_Byte*    base,
+                      FT_UInt     len );
+
+    FT_Error
     (*parse_charstrings)( PS_Decoder*  decoder,
                           FT_Byte*     charstring_base,
                           FT_ULong     charstring_len );
diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c
index 8541cca..82be440 100644
--- a/src/cid/cidgload.c
+++ b/src/cid/cidgload.c
@@ -183,6 +183,11 @@
                   decoder,
                   charstring + cs_offset,
                   glyph_length - cs_offset );
+      else if ( decoder->builder.metrics_only )
+        error = psaux->t1_decoder_funcs->parse_metrics(
+                  decoder,
+                  charstring + cs_offset,
+                  glyph_length - cs_offset );
       else
       {
         PS_Decoder      psdecoder;
diff --git a/src/psaux/psauxmod.c b/src/psaux/psauxmod.c
index b539b1a..16e887d 100644
--- a/src/psaux/psauxmod.c
+++ b/src/psaux/psauxmod.c
@@ -90,6 +90,7 @@
     t1_decoder_init,               /* init                  */
     t1_decoder_done,               /* done                  */
     t1_decoder_parse_charstrings,  /* parse_charstrings_old */
+    t1_decoder_parse_metrics,      /* parse_metrics         */
     cf2_decoder_parse_charstrings  /* parse_charstrings     */
   };
 
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index e68b76d..61d2462 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -1628,6 +1628,283 @@
     return FT_THROW( Stack_Underflow );
   }
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_decoder_parse_metrics                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Parses a given Type 1 charstrings program to extract width         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    decoder         :: The current Type 1 decoder.                     */
+  /*                                                                       */
+  /*    charstring_base :: The base address of the charstring stream.      */
+  /*                                                                       */
+  /*    charstring_len  :: The length in bytes of the charstring stream.   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  t1_decoder_parse_metrics( T1_Decoder  decoder,
+                            FT_Byte*    charstring_base,
+                            FT_UInt     charstring_len )
+  {
+    T1_Decoder_Zone  zone;
+    FT_Byte*         ip;
+    FT_Byte*         limit;
+    T1_Builder       builder = &decoder->builder;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_Bool          bol = TRUE;
+#endif
+
+
+    /* First of all, initialize the decoder */
+    decoder->top  = decoder->stack;
+    decoder->zone = decoder->zones;
+    zone          = decoder->zones;
+
+    builder->parse_state = T1_Parse_Start;
+
+    FT_TRACE4(( "\n"
+                "Start charstring: get width\n" ));
+
+    zone->base           = charstring_base;
+    limit = zone->limit  = charstring_base + charstring_len;
+    ip    = zone->cursor = zone->base;
+
+    /* now, execute loop */
+    while ( ip < limit )
+    {
+      FT_Long*     top   = decoder->top;
+      T1_Operator  op    = op_none;
+      FT_Int32     value = 0;
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+      if ( bol )
+      {
+        FT_TRACE5(( " (%d)", decoder->top - decoder->stack ));
+        bol = FALSE;
+      }
+#endif
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Decode operator or operand                                        */
+      /*                                                                   */
+      /*                                                                   */
+
+      /* first of all, decompress operator or value */
+      switch ( *ip++ )
+      {
+      case 1:
+      case 3:
+      case 4:
+      case 5:
+      case 6:
+      case 7:
+      case 8:
+      case 9:
+      case 10:
+      case 11:
+      case 14:
+      case 15:
+      case 21:
+      case 22:
+      case 30:
+      case 31:
+        goto No_Width;
+
+      case 13:
+        op = op_hsbw;
+        break;
+
+      case 12:
+        if ( ip >= limit )
+        {
+          FT_ERROR(( "t1_decoder_parse_metrics:"
+                     " invalid escape (12+EOF)\n" ));
+          goto Syntax_Error;
+        }
+
+        switch ( *ip++ )
+        {
+        case 7:
+          op = op_sbw;
+          break;
+
+        default:
+          goto No_Width;
+        }
+        break;
+
+      case 255:    /* four bytes integer */
+        if ( ip + 4 > limit )
+        {
+          FT_ERROR(( "t1_decoder_parse_metrics:"
+                     " unexpected EOF in integer\n" ));
+          goto Syntax_Error;
+        }
+
+        value = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) |
+                            ( (FT_UInt32)ip[1] << 16 ) |
+                            ( (FT_UInt32)ip[2] << 8  ) |
+                              (FT_UInt32)ip[3]         );
+        ip += 4;
+
+        /* According to the specification, values > 32000 or < -32000 must */
+        /* be followed by a `div' operator to make the result be in the    */
+        /* range [-32000;32000].  We expect that the second argument of    */
+        /* `div' is not a large number.  Additionally, we don't handle     */
+        /* stuff like `<large1> <large2> <num> div <num> div' or           */
+        /* <large1> <large2> <num> div div'.  This is probably not allowed */
+        /* anyway.                                                         */
+        if ( value > 32000 || value < -32000 )
+        {
+          FT_ERROR(( "t1_decoder_parse_metrics:"
+                     " large integer found for width\n" ));
+          goto Syntax_Error;
+        }
+        else
+        {
+          value = (FT_Int32)( (FT_UInt32)value << 16 );
+        }
+
+        break;
+
+      default:
+        if ( ip[-1] >= 32 )
+        {
+          if ( ip[-1] < 247 )
+            value = (FT_Int32)ip[-1] - 139;
+          else
+          {
+            if ( ++ip > limit )
+            {
+              FT_ERROR(( "t1_decoder_parse_metrics:"
+                         " unexpected EOF in integer\n" ));
+              goto Syntax_Error;
+            }
+
+            if ( ip[-2] < 251 )
+              value =    ( ( ip[-2] - 247 ) * 256 ) + ip[-1] + 108;
+            else
+              value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 );
+          }
+
+          value = (FT_Int32)( (FT_UInt32)value << 16 );
+        }
+        else
+        {
+          FT_ERROR(( "t1_decoder_parse_metrics:"
+                     " invalid byte (%d)\n", ip[-1] ));
+          goto Syntax_Error;
+        }
+      }
+
+      /*********************************************************************/
+      /*                                                                   */
+      /*  Push value on stack, or process operator                         */
+      /*                                                                   */
+      /*                                                                   */
+      if ( op == op_none )
+      {
+        if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
+        {
+          FT_ERROR(( "t1_decoder_parse_metrics: stack overflow\n" ));
+          goto Syntax_Error;
+        }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+          FT_TRACE4(( " %d", value / 65536 ));
+#endif
+
+        *top++       = value;
+        decoder->top = top;
+      }
+      else  /* general operator */
+      {
+        FT_Int  num_args = t1_args_count[op];
+
+
+        FT_ASSERT( num_args >= 0 );
+
+        if ( top - decoder->stack < num_args )
+          goto Stack_Underflow;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+        if ( top - decoder->stack != num_args )
+          FT_TRACE0(( "t1_decoder_parse_metrics:"
+                      " too much operands on the stack"
+                      " (seen %d, expected %d)\n",
+                      top - decoder->stack, num_args ));
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+        top -= num_args;
+
+        switch ( op )
+        {
+        case op_hsbw:
+          FT_TRACE4(( " hsbw" ));
+
+          builder->parse_state = T1_Parse_Have_Width;
+
+          builder->left_bearing.x = ADD_LONG( builder->left_bearing.x,
+                                              top[0] );
+
+          builder->advance.x = top[1];
+          builder->advance.y = 0;
+
+          /* we only want to compute the glyph's metrics */
+          /* (lsb + advance width), not load the rest of */
+          /* it; so exit immediately                     */
+          return FT_Err_Ok;
+
+        case op_sbw:
+          FT_TRACE4(( " sbw" ));
+
+          builder->parse_state = T1_Parse_Have_Width;
+
+          builder->left_bearing.x = ADD_LONG( builder->left_bearing.x,
+                                              top[0] );
+          builder->left_bearing.y = ADD_LONG( builder->left_bearing.y,
+                                              top[1] );
+
+          builder->advance.x = top[2];
+          builder->advance.y = top[3];
+
+          /* we only want to compute the glyph's metrics */
+          /* (lsb + advance width), not load the rest of */
+          /* it; so exit immediately                     */
+          return FT_Err_Ok;
+
+        default:
+          FT_ERROR(( "t1_decoder_parse_metrics:"
+                     " unhandled opcode %d\n", op ));
+          goto Syntax_Error;
+        }
+
+      } /* general operator processing */
+
+    } /* while ip < limit */
+
+    FT_TRACE4(( "..end..\n\n" ));
+
+  No_Width:
+    FT_ERROR(( "t1_decoder_parse_metrics:"
+               " no width, found op %d instead\n",
+               ip[-1] ));
+  Syntax_Error:
+    return FT_THROW( Syntax_Error );
+
+  Stack_Underflow:
+    return FT_THROW( Stack_Underflow );
+  }
 
   /* parse a single Type 1 glyph */
   FT_LOCAL_DEF( FT_Error )
diff --git a/src/psaux/t1decode.h b/src/psaux/t1decode.h
index 1ca7e01..420d120 100644
--- a/src/psaux/t1decode.h
+++ b/src/psaux/t1decode.h
@@ -43,6 +43,10 @@ FT_BEGIN_HEADER
   t1_decoder_parse_charstrings( T1_Decoder  decoder,
                                 FT_Byte*    base,
                                 FT_UInt     len );
+  FT_LOCAL( FT_Error )
+  t1_decoder_parse_metrics( T1_Decoder  decoder,
+                            FT_Byte*    charstring_base,
+                            FT_UInt     charstring_len );
 
   FT_LOCAL( FT_Error )
   t1_decoder_init( T1_Decoder           decoder,
diff --git a/src/type1/t1gload.c b/src/type1/t1gload.c
index 30ca186..53f89b2 100644
--- a/src/type1/t1gload.c
+++ b/src/type1/t1gload.c
@@ -90,6 +90,11 @@
                   decoder,
                   (FT_Byte*)char_string->pointer,
                   (FT_UInt)char_string->length );
+      else if ( decoder->builder.metrics_only )
+        error = decoder_funcs->parse_metrics(
+                  decoder,
+                  (FT_Byte*)char_string->pointer,
+                  (FT_UInt)char_string->length );
       else
       {
         CFF_SubFontRec  subfont;