shithub: freetype+ttf2subf

Download patch

ref: 813aca51d28704f7ffc470721167738fa8decb3d
parent: 4b3ea5ca8f2ae7223bb1ad24bea07e659eec5f92
author: Werner Lemberg <[email protected]>
date: Sun Feb 14 11:03:15 EST 2016

[cff] Make old CFF engine show MM CFFs (without variations).

The new code only displays the first master in the font.

* src/cff/cffgload.c (cff_decode_parse_charstrings): Add new
parameter to allow function calls from dictionaries also.
<cff_op_blend>: Partially implement it.
Update all callers.
* src/cff/cffgload.h: Updated.

* src/cff/cffparse.c (cff_parser_init): Add new parameter to pass the
number of Multiple Master designs.
Update all callers.
(cff_parse_multiple_master): New function to rudimentarily parse
operator.
(cff_parser_run): Handle `T2' operator.
* src/cff/cffparse.h: Updated.
(CFF_ParserRec): Add `num_designs' field.

* src/cff/cffload.c: Updated.

* src/cff/cfftoken.h: Handle `MultipleMaster' operator.

* src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_designs' field.

* src/sfnt/sfobjs.c (sfnt_init_face): Don't handle `fvar' table for
MM CFFs.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2016-02-14  Werner Lemberg  <[email protected]>
+
+	[cff] Make old CFF engine show MM CFFs (without variations).
+
+	The new code only displays the first master in the font.
+
+	* src/cff/cffgload.c (cff_decode_parse_charstrings): Add new
+	parameter to allow function calls from dictionaries also.
+	<cff_op_blend>: Partially implement it.
+	Update all callers.
+	* src/cff/cffgload.h: Updated.
+
+	* src/cff/cffparse.c (cff_parser_init): Add new parameter to pass the
+	number of Multiple Master designs.
+	Update all callers.
+	(cff_parse_multiple_master): New function to rudimentarily parse
+	operator.
+	(cff_parser_run): Handle `T2' operator.
+	* src/cff/cffparse.h: Updated.
+	(CFF_ParserRec): Add `num_designs' field.
+
+	* src/cff/cffload.c: Updated.
+
+	* src/cff/cfftoken.h: Handle `MultipleMaster' operator.
+
+	* src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_designs' field.
+
+	* src/sfnt/sfobjs.c (sfnt_init_face): Don't handle `fvar' table for
+	MM CFFs.
+
 2016-02-09  Werner Lemberg  <[email protected]>
 
 	[docmaker] Don't emit trailing newlines.
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -826,7 +826,7 @@
       /* the seac operator must not be nested */
       decoder->seac = TRUE;
       error = cff_decoder_parse_charstrings( decoder, charstring,
-                                             charstring_len );
+                                             charstring_len, 0 );
       decoder->seac = FALSE;
 
       cff_free_glyph_data( face, &charstring, charstring_len );
@@ -856,7 +856,7 @@
       /* the seac operator must not be nested */
       decoder->seac = TRUE;
       error = cff_decoder_parse_charstrings( decoder, charstring,
-                                             charstring_len );
+                                             charstring_len, 0 );
       decoder->seac = FALSE;
 
       cff_free_glyph_data( face, &charstring, charstring_len );
@@ -895,6 +895,9 @@
   /*                                                                       */
   /*    charstring_len  :: The length in bytes of the charstring stream.   */
   /*                                                                       */
+  /*    in_dict         :: Set to 1 if function is called from top or      */
+  /*                       private DICT (needed for Multiple Master CFFs). */
+  /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
@@ -901,7 +904,8 @@
   FT_LOCAL_DEF( FT_Error )
   cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
                                  FT_Byte*      charstring_base,
-                                 FT_ULong      charstring_len )
+                                 FT_ULong      charstring_len,
+                                 FT_Bool       in_dict )
   {
     FT_Error           error;
     CFF_Decoder_Zone*  zone;
@@ -913,6 +917,8 @@
     FT_Fixed*          stack;
     FT_Int             charstring_type =
                          decoder->cff->top_font.font_dict.charstring_type;
+    FT_UShort          num_designs =
+                         decoder->cff->top_font.font_dict.num_designs;
 
     T2_Hints_Funcs     hinter;
 
@@ -1241,6 +1247,44 @@
         if ( op == cff_op_unknown )
           continue;
 
+        /* in Multiple Master CFFs, T2 charstrings can appear in */
+        /* dictionaries, but some operators are prohibited       */
+        if ( in_dict )
+        {
+          switch ( op )
+          {
+          case cff_op_hstem:
+          case cff_op_vstem:
+          case cff_op_vmoveto:
+          case cff_op_rlineto:
+          case cff_op_hlineto:
+          case cff_op_vlineto:
+          case cff_op_rrcurveto:
+          case cff_op_hstemhm:
+          case cff_op_hintmask:
+          case cff_op_cntrmask:
+          case cff_op_rmoveto:
+          case cff_op_hmoveto:
+          case cff_op_vstemhm:
+          case cff_op_rcurveline:
+          case cff_op_rlinecurve:
+          case cff_op_vvcurveto:
+          case cff_op_hhcurveto:
+          case cff_op_vhcurveto:
+          case cff_op_hvcurveto:
+          case cff_op_hflex:
+          case cff_op_flex:
+          case cff_op_hflex1:
+          case cff_op_flex1:
+          case cff_op_callsubr:
+          case cff_op_callgsubr:
+            goto MM_Error;
+
+          default:
+            break;
+          }
+        }
+
         /* check arguments */
         req_args = cff_argument_counts[op];
         if ( req_args & CFF_COUNT_CHECK_WIDTH )
@@ -1278,7 +1322,9 @@
             case cff_op_endchar:
               /* If there is a width specified for endchar, we either have */
               /* 1 argument or 5 arguments.  We like to argue.             */
-              set_width_ok = ( num_args == 5 ) || ( num_args == 1 );
+              set_width_ok = in_dict
+                               ? 0
+                               : ( ( num_args == 5 ) || ( num_args == 1 ) );
               break;
 
             default:
@@ -1971,6 +2017,10 @@
             return error;
 
         case cff_op_endchar:
+          /* in dictionaries, `endchar' simply indicates end of data */
+          if ( in_dict )
+            return error;
+
           FT_TRACE4(( " endchar\n" ));
 
           /* We are going to emulate the seac operator. */
@@ -2236,10 +2286,26 @@
         case cff_op_blend:
           /* this operator was removed from the Type2 specification */
           /* in version 16-March-2000                               */
-          FT_TRACE4(( " blend\n" ));
+          {
+            FT_Int  num_results = (FT_Int)( args[0] >> 16 );
 
-          goto Unimplemented;
 
+            FT_TRACE4(( " blend\n" ));
+
+            if ( num_results < 0 )
+              goto Syntax_Error;
+
+            if ( num_results * (FT_Int)num_designs > num_args )
+              goto Stack_Underflow;
+
+            /* since we currently don't handle interpolation of multiple */
+            /* master fonts, return the `num_results' values of the      */
+            /* first master                                              */
+            args     -= num_results * ( num_designs - 1 );
+            num_args -= num_results * ( num_designs - 1 );
+          }
+          break;
+
         case cff_op_dotsection:
           /* this operator is deprecated and ignored by the parser */
           FT_TRACE4(( " dotsection\n" ));
@@ -2535,6 +2601,11 @@
   Fail:
     return error;
 
+  MM_Error:
+    FT_TRACE4(( "cff_decoder_parse_charstrings:"
+                " invalid opcode found in top DICT charstring\n"));
+    return FT_THROW( Invalid_File_Format );
+
   Syntax_Error:
     FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" ));
     return FT_THROW( Invalid_File_Format );
@@ -2608,7 +2679,8 @@
         if ( !error )
           error = cff_decoder_parse_charstrings( &decoder,
                                                  charstring,
-                                                 charstring_len );
+                                                 charstring_len,
+                                                 0 );
 
         cff_free_glyph_data( face, &charstring, &charstring_len );
       }
@@ -2859,7 +2931,8 @@
       if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
         error = cff_decoder_parse_charstrings( &decoder,
                                                charstring,
-                                               charstring_len );
+                                               charstring_len,
+                                               0 );
       else
 #endif
       {
--- a/src/cff/cffgload.h
+++ b/src/cff/cffgload.h
@@ -227,7 +227,8 @@
   FT_LOCAL( FT_Error )
   cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
                                  FT_Byte*      charstring_base,
-                                 FT_ULong      charstring_len );
+                                 FT_ULong      charstring_len,
+                                 FT_Bool       in_dict );
 #endif
 
   FT_LOCAL( FT_Error )
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -1316,7 +1316,11 @@
     CFF_Private      priv = &font->private_dict;
 
 
-    cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict, library );
+    cff_parser_init( &parser,
+                     CFF_CODE_TOPDICT,
+                     &font->font_dict,
+                     library,
+                     0 );
 
     /* set defaults */
     FT_MEM_ZERO( top, sizeof ( *top ) );
@@ -1370,7 +1374,11 @@
       priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
       priv->blue_scale       = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
 
-      cff_parser_init( &parser, CFF_CODE_PRIVATE, priv, library );
+      cff_parser_init( &parser,
+                       CFF_CODE_PRIVATE,
+                       priv,
+                       library,
+                       top->num_designs );
 
       if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
            FT_FRAME_ENTER( font->font_dict.private_size )                 )
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -39,7 +39,8 @@
   cff_parser_init( CFF_Parser  parser,
                    FT_UInt     code,
                    void*       object,
-                   FT_Library  library)
+                   FT_Library  library,
+                   FT_UShort   num_designs )
   {
     FT_MEM_ZERO( parser, sizeof ( *parser ) );
 
@@ -47,6 +48,7 @@
     parser->object_code = code;
     parser->object      = object;
     parser->library     = library;
+    parser->num_designs = num_designs;
   }
 
 
@@ -649,7 +651,48 @@
   }
 
 
+  /* We assume that the `MultipleMaster' operator comes before any */
+  /* top DICT operators that contain T2 charstrings.  Otherwise,   */
+  /* `num_designs' is zero, leading to errors in handling the      */
+  /* `blend' operator later on.                                    */
+
   static FT_Error
+  cff_parse_multiple_master( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_Error         error;
+
+
+    FT_TRACE1(( "Multiple Master CFFs not supported yet,"
+                " handling first master design only\n" ));
+
+    error = FT_ERR( Stack_Underflow );
+
+    /* currently, we handle only the first argument */
+    if ( parser->top >= parser->stack + 5 )
+    {
+      FT_Long  num_designs = cff_parse_num( parser->stack );
+
+
+      if ( num_designs > 16 || num_designs < 2 )
+      {
+        FT_ERROR(( "cff_parse_multiple_master:"
+                   " Invalid number of designs\n" ));
+        error = FT_THROW( Invalid_File_Format );
+      }
+      else
+      {
+        dict->num_designs   = (FT_UShort)num_designs;
+        parser->num_designs = dict->num_designs;
+        error = FT_Err_Ok;
+      }
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
   cff_parse_cid_ros( CFF_Parser  parser )
   {
     CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
@@ -972,7 +1015,7 @@
         if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
           goto Stack_Overflow;
 
-        *parser->top ++ = p;
+        *parser->top++ = p;
 
         /* now, skip it */
         if ( v == 30 )
@@ -1000,6 +1043,133 @@
           p += 4;
         else if ( v > 246 )
           p += 1;
+      }
+      else if ( v == 31 )
+      {
+        /* a Type 2 charstring */
+
+        CFF_Decoder  decoder;
+        CFF_FontRec  cff_rec;
+        FT_Byte*     charstring_base;
+        FT_ULong     charstring_len;
+
+        FT_Fixed*  stack;
+        FT_Byte*   q;
+
+
+        charstring_base = ++p;
+
+        /* search `endchar' operator */
+        for (;;)
+        {
+          if ( p >= limit )
+            goto Exit;
+          if ( *p == 14 )
+            break;
+          p++;
+        }
+
+        charstring_len = (FT_ULong)( p - charstring_base ) + 1;
+
+        /* construct CFF_Decoder object */
+        FT_MEM_ZERO( &decoder, sizeof ( decoder ) );
+        FT_MEM_ZERO( &cff_rec, sizeof ( cff_rec ) );
+
+        cff_rec.top_font.font_dict.num_designs = parser->num_designs;
+        decoder.cff                            = &cff_rec;
+
+        error = cff_decoder_parse_charstrings( &decoder,
+                                               charstring_base,
+                                               charstring_len,
+                                               1 );
+
+        /* Now copy the stack data in the temporary decoder object,    */
+        /* converting it back to charstring number representations     */
+        /* (this is ugly, I know).                                     */
+        /*                                                             */
+        /* We overwrite the original top DICT charstring under the     */
+        /* assumption that the charstring representation of the result */
+        /* of `cff_decoder_parse_charstrings' is shorter, which should */
+        /* be always true.                                             */
+
+        q     = charstring_base - 1;
+        stack = decoder.stack;
+
+        while ( stack < decoder.top )
+        {
+          FT_ULong  num;
+          FT_Bool   neg;
+
+
+          if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
+            goto Stack_Overflow;
+
+          *parser->top++ = q;
+
+          if ( *stack < 0 )
+          {
+            num = (FT_ULong)-*stack;
+            neg = 1;
+          }
+          else
+          {
+            num = (FT_ULong)*stack;
+            neg = 0;
+          }
+
+          if ( num & 0xFFFFU )
+          {
+            if ( neg )
+              num = (FT_ULong)-num;
+
+            *q++ = 255;
+            *q++ = ( num & 0xFF000000U ) >> 24;
+            *q++ = ( num & 0x00FF0000U ) >> 16;
+            *q++ = ( num & 0x0000FF00U ) >>  8;
+            *q++ =   num & 0x000000FFU;
+          }
+          else
+          {
+            num >>= 16;
+
+            if ( neg )
+            {
+              if ( num <= 107 )
+                *q++ = (FT_Byte)( 139 - num );
+              else if ( num <= 1131 )
+              {
+                *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
+                *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+              }
+              else
+              {
+                num = (FT_ULong)-num;
+
+                *q++ = 28;
+                *q++ = (FT_Byte)( num >> 8 );
+                *q++ = (FT_Byte)( num & 0xFF );
+              }
+            }
+            else
+            {
+              if ( num <= 107 )
+                *q++ = (FT_Byte)( num + 139 );
+              else if ( num <= 1131 )
+              {
+                *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
+                *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+              }
+              else
+              {
+                *q++ = 28;
+                *q++ = (FT_Byte)( num >> 8 );
+                *q++ = (FT_Byte)( num & 0xFF );
+              }
+            }
+          }
+
+          stack++;
+        }
       }
       else
       {
--- a/src/cff/cffparse.h
+++ b/src/cff/cffparse.h
@@ -47,6 +47,8 @@
     FT_UInt    object_code;
     void*      object;
 
+    FT_UShort  num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
+
   } CFF_ParserRec, *CFF_Parser;
 
 
@@ -54,7 +56,8 @@
   cff_parser_init( CFF_Parser  parser,
                    FT_UInt     code,
                    void*       object,
-                   FT_Library  library);
+                   FT_Library  library,
+                   FT_UShort   num_designs );
 
   FT_LOCAL( FT_Error )
   cff_parser_run( CFF_Parser  parser,
--- a/src/cff/cfftoken.h
+++ b/src/cff/cfftoken.h
@@ -38,6 +38,9 @@
   CFF_FIELD_NUM     ( 13,    unique_id,           "UniqueID" )
   CFF_FIELD_CALLBACK( 5,     font_bbox,           "FontBBox" )
   CFF_FIELD_NUM     ( 0x108, stroke_width,        "StrokeWidth" )
+#if 0
+  CFF_FIELD_DELTA   ( 14,    xuid, 16,            "XUID" )
+#endif
   CFF_FIELD_NUM     ( 15,    charset_offset,      "charset" )
   CFF_FIELD_NUM     ( 16,    encoding_offset,     "Encoding" )
   CFF_FIELD_NUM     ( 17,    charstrings_offset,  "CharStrings" )
@@ -48,8 +51,13 @@
 #if 0
   CFF_FIELD_STRING  ( 0x116, base_font_name,      "BaseFontName" )
   CFF_FIELD_DELTA   ( 0x117, base_font_blend, 16, "BaseFontBlend" )
+#endif
+
+  /* the next two operators were removed from the Type2 specification */
+  /* in version 16-March-2000                                         */
   CFF_FIELD_CALLBACK( 0x118, multiple_master,     "MultipleMaster" )
-  CFF_FIELD_CALLBACK( 0x119, blend_axis_types,    "BlendAxisTypes" )
+#if 0
+  CFF_FIELD_CALLBACK( 0x11A, blend_axis_types,    "BlendAxisTypes" )
 #endif
 
   CFF_FIELD_CALLBACK( 0x11E, cid_ros,              "ROS" )
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -145,6 +145,11 @@
     FT_ULong   cid_fd_select_offset;
     FT_UInt    cid_font_name;
 
+    /* the next field comes from the data of the deprecated       */
+    /* `MultipleMaster' operator; it is needed to parse the (also */
+    /* deprecated) `blend' operator in Type 2 charstrings         */
+    FT_UShort  num_designs;
+
   } CFF_FontRecDictRec, *CFF_FontRecDict;
 
 
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -949,6 +949,10 @@
              instance_size * num_instances > fvar_len )
         num_instances = 0;
 
+      /* we don't support Multiple Master CFFs yet */
+      if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) )
+        num_instances = 0;
+
       /* we support at most 2^15 - 1 instances */
       if ( num_instances >= ( 1U << 15 ) - 1 )
       {