Commit 8ed9eaf1cccd3112870939fbb932dd31fca95589

Werner Lemberg 2016-02-15T20:41:58

[cff] Partially handle `load' and `store' ops in old CFF engine. Now all glyphs of MM CFFs like `ITCGaramondMM-It.otf' can be displayed. * src/cff/cffgload.c (cff_decoder_parse_charstrings) <cff_op_store, cff_op_load>: Partially implement it. * src/cff/cffparse.c (cff_parser_init): Add new parameter to pass the number of Multiple Master axes. Update all callers. (cff_parse_multiple_master): Get number of axes. (cff_parser_run) <opcode 31>: Updated. * src/cff/cffparse.h: Updated. (CFF_ParserRec): Add `num_axes' field. * src/cff/cffload.c: Updated. * src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_axes' field.

diff --git a/ChangeLog b/ChangeLog
index b884755..ceb6166 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
 2016-02-15  Werner Lemberg  <wl@gnu.org>
 
+	[cff] Partially handle `load' and `store' ops in old CFF engine.
+
+	Now all glyphs of MM CFFs like `ITCGaramondMM-It.otf' can be
+	displayed.
+
+	* src/cff/cffgload.c (cff_decoder_parse_charstrings) <cff_op_store,
+	cff_op_load>: Partially implement it.
+
+	* src/cff/cffparse.c (cff_parser_init): Add new parameter to pass
+	the number of Multiple Master axes.
+	Update all callers.
+	(cff_parse_multiple_master): Get number of axes.
+	(cff_parser_run) <opcode 31>: Updated.
+	* src/cff/cffparse.h: Updated.
+	(CFF_ParserRec): Add `num_axes' field.
+
+	* src/cff/cffload.c: Updated.
+
+	* src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_axes' field.
+
+2016-02-15  Werner Lemberg  <wl@gnu.org>
+
 	[cff] Correctly trace SIDs that contain NULL bytes.
 
 	We need this to properly trace Multiple Master CFFs, which contain
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index 2a2f60f..752c18e 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -919,6 +919,8 @@
                          decoder->cff->top_font.font_dict.charstring_type;
     FT_UShort          num_designs =
                          decoder->cff->top_font.font_dict.num_designs;
+    FT_UShort          num_axes =
+                         decoder->cff->top_font.font_dict.num_axes;
 
     T2_Hints_Funcs     hinter;
 
@@ -2248,6 +2250,10 @@
 
             FT_TRACE4(( " put\n" ));
 
+            /* the Type2 specification before version 16-March-2000 */
+            /* didn't give a hard-coded size limit of the temporary */
+            /* storage array; instead, an argument of the           */
+            /* `MultipleMaster' operator set the size               */
             if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS )
               decoder->buildchar[idx] = val;
           }
@@ -2272,16 +2278,43 @@
         case cff_op_store:
           /* this operator was removed from the Type2 specification */
           /* in version 16-March-2000                               */
-          FT_TRACE4(( " store\n"));
 
-          goto Unimplemented;
+          /* since we currently don't handle interpolation of multiple */
+          /* master fonts, this is a no-op                             */
+          FT_TRACE4(( " store\n"));
+          break;
 
         case cff_op_load:
           /* this operator was removed from the Type2 specification */
           /* in version 16-March-2000                               */
-          FT_TRACE4(( " load\n" ));
+          {
+            FT_Int  reg_idx = (FT_Int)args[0];
+            FT_Int  idx     = (FT_Int)args[1];
+            FT_Int  count   = (FT_Int)args[2];
 
-          goto Unimplemented;
+
+            FT_TRACE4(( " load\n" ));
+
+            /* since we currently don't handle interpolation of multiple */
+            /* master fonts, we store a vector [1 0 0 ...] in the        */
+            /* temporary storage array regardless of the Registry index  */
+            if ( reg_idx >= 0 && reg_idx <= 2             &&
+                 idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS &&
+                 count >= 0 && count <= num_axes          )
+            {
+              FT_Int  end, i;
+
+
+              end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS );
+
+              if ( idx < end )
+                decoder->buildchar[idx] = 1 << 16;
+
+              for ( i = idx + 1; i < end; i++ )
+                decoder->buildchar[i] = 0;
+            }
+          }
+          break;
 
         case cff_op_blend:
           /* this operator was removed from the Type2 specification */
@@ -2577,7 +2610,6 @@
           break;
 
         default:
-        Unimplemented:
           FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
 
           if ( ip[-1] == 12 )
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index 920f10b..9d3846c 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -1325,6 +1325,7 @@
                      CFF_CODE_TOPDICT,
                      &font->font_dict,
                      library,
+                     0,
                      0 );
 
     /* set defaults */
@@ -1383,7 +1384,8 @@
                        CFF_CODE_PRIVATE,
                        priv,
                        library,
-                       top->num_designs );
+                       top->num_designs,
+                       top->num_axes );
 
       if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
            FT_FRAME_ENTER( font->font_dict.private_size )                 )
diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c
index 616023a..921c1a1 100644
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -41,7 +41,8 @@
                    FT_UInt     code,
                    void*       object,
                    FT_Library  library,
-                   FT_UShort   num_designs )
+                   FT_UShort   num_designs,
+                   FT_UShort   num_axes )
   {
     FT_MEM_ZERO( parser, sizeof ( *parser ) );
 
@@ -50,6 +51,7 @@
     parser->object      = object;
     parser->library     = library;
     parser->num_designs = num_designs;
+    parser->num_axes    = num_axes;
   }
 
 
@@ -682,7 +684,11 @@
       else
       {
         dict->num_designs   = (FT_UShort)num_designs;
+        dict->num_axes      = (FT_UShort)( parser->top - parser->stack - 4 );
+
         parser->num_designs = dict->num_designs;
+        parser->num_axes    = dict->num_axes;
+
         error = FT_Err_Ok;
       }
     }
@@ -1075,6 +1081,7 @@
         FT_MEM_ZERO( &cff_rec, sizeof ( cff_rec ) );
 
         cff_rec.top_font.font_dict.num_designs = parser->num_designs;
+        cff_rec.top_font.font_dict.num_axes    = parser->num_axes;
         decoder.cff                            = &cff_rec;
 
         error = cff_decoder_parse_charstrings( &decoder,
diff --git a/src/cff/cffparse.h b/src/cff/cffparse.h
index 682ada0..a95970e 100644
--- a/src/cff/cffparse.h
+++ b/src/cff/cffparse.h
@@ -36,18 +36,19 @@ FT_BEGIN_HEADER
 
   typedef struct  CFF_ParserRec_
   {
-    FT_Library library;
-    FT_Byte*   start;
-    FT_Byte*   limit;
-    FT_Byte*   cursor;
+    FT_Library  library;
+    FT_Byte*    start;
+    FT_Byte*    limit;
+    FT_Byte*    cursor;
 
-    FT_Byte*   stack[CFF_MAX_STACK_DEPTH + 1];
-    FT_Byte**  top;
+    FT_Byte*    stack[CFF_MAX_STACK_DEPTH + 1];
+    FT_Byte**   top;
 
-    FT_UInt    object_code;
-    void*      object;
+    FT_UInt     object_code;
+    void*       object;
 
-    FT_UShort  num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
+    FT_UShort   num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
+    FT_UShort   num_axes;    /* a copy of `CFF_FontRecDict->num_axes'    */
 
   } CFF_ParserRec, *CFF_Parser;
 
@@ -57,7 +58,8 @@ FT_BEGIN_HEADER
                    FT_UInt     code,
                    void*       object,
                    FT_Library  library,
-                   FT_UShort   num_designs );
+                   FT_UShort   num_designs,
+                   FT_UShort   num_axes );
 
   FT_LOCAL( FT_Error )
   cff_parser_run( CFF_Parser  parser,
diff --git a/src/cff/cfftypes.h b/src/cff/cfftypes.h
index b2320fd..4426c7e 100644
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -145,10 +145,11 @@ FT_BEGIN_HEADER
     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         */
+    /* the next fields come from the data of the deprecated          */
+    /* `MultipleMaster' operator; they are needed to parse the (also */
+    /* deprecated) `blend' operator in Type 2 charstrings            */
     FT_UShort  num_designs;
+    FT_UShort  num_axes;
 
   } CFF_FontRecDictRec, *CFF_FontRecDict;