shithub: freetype+ttf2subf

Download patch

ref: 7c388ba4911d76856d85bc1b9e0059414c1b05c9
parent: 4e183694917419772396a7d55f39d72a335eb933
author: David Turner <[email protected]>
date: Thu May 25 22:07:40 EDT 2000

added support for multiple master fonts in "type1z". It is
now working, but there is no way currently to change the default
weight vector (tested with custom vectors though).

Note that you should remove the "type1" driver from the
module list to be able to test it..

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -645,7 +645,7 @@
   /*                                                                       */
   /* <Description>                                                         */
   /*    A bit-field constant, used to indicate that a given face contains  */
-  /*    fixed-width characters (like Courier, MonoType, etc).              */
+  /*    fixed-width characters (like Courier, Lucida, MonoType, etc..)     */
   /*                                                                       */
 #define FT_FACE_FLAG_FIXED_WIDTH  4
 
--- a/include/freetype/internal/ftdebug.h
+++ b/include/freetype/internal/ftdebug.h
@@ -170,7 +170,7 @@
   /* print a message and exit */
   FT_EXPORT_DEF(void)  FT_Panic  ( const char*  fmt, ... );
 
-#define FT_ERROR(varformat)  do { FT_XCAT( FT_Message, varformat ) } while(0)
+#define FT_ERROR(varformat)  do { FT_XCAT( FT_Message, varformat ); } while(0)
 
 
 #endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -140,9 +140,14 @@
   } T1_Blend_Flags;
 
   /* maximum number of multiple-masters designs, per-se the spec */
-  #define T1_MAX_MM_DESIGNS  16
-  #define T1_MAX_MM_AXIS     4
+  #define T1_MAX_MM_DESIGNS      16
+  
+  /* maximum number of multiple-masters axis, per-se the spec */
+  #define T1_MAX_MM_AXIS         4
 
+  /* maximum number of elements in a design map */
+  #define T1_MAX_MM_MAP_POINTS   20
+
   /* this structure is used to store the BlendDesignMap entry for an axis */
   typedef struct T1_DesignMap_
   {
@@ -152,6 +157,7 @@
     
   } T1_DesignMap;
 
+
   typedef struct T1_Blend_
   {
     FT_UInt       num_designs;
@@ -161,6 +167,9 @@
     FT_Fixed*     design_pos[ T1_MAX_MM_DESIGNS ];
     T1_DesignMap  design_map[ T1_MAX_MM_AXIS ];
     
+    FT_Fixed*     weight_vector;
+    FT_Fixed*     default_weight_vector;
+    
     T1_FontInfo*  font_infos[ T1_MAX_MM_DESIGNS+1 ];
     T1_Private*   privates  [ T1_MAX_MM_DESIGNS+1 ];
     
@@ -173,7 +182,7 @@
   typedef struct CID_FontDict_
   {
     T1_FontInfo   font_info;
-    T1_Private    private;
+    T1_Private    private_dict;
 
     FT_UInt       num_subrs;
     FT_ULong      subrmap_offset;
--- a/src/type1z/t1gload.c
+++ b/src/type1z/t1gload.c
@@ -205,6 +205,7 @@
     decoder->zone             = 0;
     decoder->flex_state       = 0;
     decoder->num_flex_vectors = 0;
+    decoder->blend            = 0;
 
     /* Clear loader */
     MEM_Set( &decoder->builder, 0, sizeof(decoder->builder) );
@@ -830,6 +831,72 @@
               break;;
             }
 
+          case 12:
+          case 13:
+            {
+              /* counter control hints, clear stack */
+              top = decoder->stack;
+              break;
+            }
+          
+          case 14:
+          case 15:
+          case 16:
+          case 17:
+          case 18: /* multiple masters */
+            {
+              T1_Blend*  blend = decoder->blend;
+              T1_UInt    num_points, nn, mm;
+              T1_Int*    delta;
+              T1_Int*    values;
+              
+              if (!blend)
+              {
+                FT_ERROR(( "T1.Parse_CharStrings: unexpected multiple masters operator !!\n" ));
+                goto Syntax_Error;
+              }
+              
+              num_points = top[1] - 13 + (top[1] == 18);
+              if (top[0] != num_points*blend->num_designs)
+              {
+                FT_ERROR(( "T1.Parse_CharStrings: incorrect number of mm arguments\n" ));
+                goto Syntax_Error;
+              }
+              
+              top       -= blend->num_designs*num_points;
+              if (top < decoder->stack)
+                goto Stack_Underflow;
+
+              /* we want to compute:                                   */
+              /*                                                       */
+              /*  a0*w0 + a1*w1 + ... + ak*wk                          */
+              /*                                                       */
+              /* but we only have the a0, a1-a0, a2-a0, .. ak-a0       */
+              /* however, given that w0 + w1 + ... + wk == 1, we can   */
+              /* rewrite it easily as:                                 */
+              /*                                                       */
+              /*  a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk       */
+              /*                                                       */
+              /* where k == num_designs-1                              */
+              /*                                                       */
+              /* I guess that's why it's written in this "compact"     */
+              /* form..                                                */
+              /*                                                       */
+              /*                                                       */
+              delta  = top + num_points;
+              values = top;
+              for ( nn = 0; nn < num_points; nn++ )
+              {
+                T1_Int  x = values[0];
+                for ( mm = 1; mm < blend->num_designs; mm++ )
+                  x += FT_MulFix( *delta++, blend->weight_vector[mm] );
+
+                *values++ = x;
+              }
+              /* note that "top" will be incremented later by calls to "pop" */
+              break;
+            }
+          
           default:
           Unexpected_OtherSubr:
             FT_ERROR(( "T1.Parse_CharStrings: invalid othersubr [%d %d]!!\n",
@@ -1086,8 +1153,9 @@
           case op_pop:  /****************************************************/
           {
             FT_TRACE4(( " pop" ));
-            FT_ERROR(( "T1.Parse_CharStrings : unexpected POP\n" ));
-            goto Syntax_Error;
+            /* theorically, the arguments are already on the stack */
+            top++;
+            break;
           }
 
 
@@ -1202,6 +1270,7 @@
     T1_Init_Decoder( &decoder );
     T1_Init_Builder( &decoder.builder, face, 0, 0 );
 
+    decoder.blend                = face->blend;
     decoder.builder.metrics_only = 1;
     decoder.builder.load_points  = 0;
 
@@ -1270,6 +1339,7 @@
       T1_Init_Decoder( &decoder );
       T1_Init_Builder( &decoder.builder, face, size, glyph );
 
+      decoder.blend              = ((T1_Face)glyph->root.face)->blend;
       decoder.builder.no_recurse = (FT_Bool)!!(load_flags & FT_LOAD_NO_RECURSE);
 
       /* now load the unscaled outline */
--- a/src/type1z/t1gload.h
+++ b/src/type1z/t1gload.h
@@ -139,6 +139,8 @@
     T1_Int             num_flex_vectors;
     T1_Vector          flex_vectors[7];
 
+    T1_Blend*          blend;  /* for multiple masters */
+
   } T1_Decoder;
 
 
--- a/src/type1z/t1load.c
+++ b/src/type1z/t1load.c
@@ -102,9 +102,12 @@
      {
        /* allocate the blend "private" and "font_info" dictionaries */
        if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) ||
-            ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private )     )
+            ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private )    ||
+            ALLOC_ARRAY( blend->weight_vector, num_designs*2, FT_Fixed )  )
          goto Exit;
   
+       blend->default_weight_vector = blend->weight_vector + num_designs;
+
        blend->font_infos[0] = &face->type1.font_info;
        blend->privates  [0] = &face->type1.private_dict;
        blend->num_designs   = num_designs;
@@ -144,7 +147,7 @@
  }                                  
 
 
- static  void t1_done_blend( T1_Face  face )
+ LOCAL_FUNC  void T1_Done_Blend( T1_Face  face )
  {
    FT_Memory  memory = face->root.memory;
    T1_Blend*  blend  = face->blend;
@@ -169,6 +172,10 @@
        blend->font_infos[n] = 0;
      }
 
+     /* release weight vectors */
+     FREE( blend->weight_vector );
+     blend->default_weight_vector = 0;
+
      /* release axis names */
      for ( n = 0; n < num_axis; n++ )
        FREE( blend->axis_names[n] );
@@ -178,7 +185,6 @@
      {
        T1_DesignMap*  dmap = blend->design_map + n;
        FREE( dmap->design_points );
-       FREE( dmap->blend_points );
        dmap->num_points = 0;
      }
      
@@ -186,6 +192,261 @@
    }
  }
 
+
+ static  void  parse_blend_axis_types( T1_Face  face, T1_Loader*  loader )
+ {
+   T1_Token_Rec  axis_tokens[ T1_MAX_MM_AXIS ];
+   T1_Int        n, num_axis;
+   FT_Error      error = 0;
+   T1_Blend*     blend;
+   FT_Memory     memory;
+
+   /* take an array of objects */
+   T1_ToTokenArray( &loader->parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+   if (num_axis <= 0 || num_axis > T1_MAX_MM_AXIS)
+   {
+     FT_ERROR(( "T1.parse_blend_axis_types: incorrect number of axis: %d\n",
+                num_axis ));
+     error = FT_Err_Invalid_File_Format;
+     goto Exit;
+   }
+   
+   /* allocate blend if necessary */
+   error = t1_allocate_blend( face, 0, (T1_UInt)num_axis );
+   if (error) goto Exit;
+   
+   blend  = face->blend;
+   memory = face->root.memory;
+   
+   /* each token is an immediate containing the name of the axis */
+   for ( n = 0; n < num_axis; n++ )
+   {
+     T1_Token_Rec*  token = axis_tokens + n;
+     T1_Byte*       name;
+     T1_Int         len;
+     
+     /* skip first slash, if any */
+     if (token->start[0] == '/')
+       token->start++;
+       
+     len = token->limit - token->start;
+     if (len <= 0)
+     {
+       error = FT_Err_Invalid_File_Format;
+       goto Exit;
+     }
+       
+     if ( ALLOC( blend->axis_names[n], len+1 ) )
+       goto Exit;
+     
+     name = (T1_Byte*)blend->axis_names[n];
+     MEM_Copy( name, token->start, len );
+     name[len] = 0;
+   }
+
+ Exit:   
+   loader->parser.error = error;
+ }
+ 
+ 
+ static void  parse_blend_design_positions( T1_Face  face, T1_Loader*  loader )
+ {
+   T1_Token_Rec  design_tokens[ T1_MAX_MM_DESIGNS ];
+   T1_Int        num_designs;
+   T1_Int        num_axis;
+   T1_Parser*    parser = &loader->parser;
+   
+   FT_Error      error = 0;
+   T1_Blend*     blend;
+
+   /* get the array of design tokens - compute number of designs */   
+   T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+   if (num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS)
+   {
+     FT_ERROR(( "T1.design positions: incorrect number of designs: %d\n",
+                num_designs ));
+     error = FT_Err_Invalid_File_Format;
+     goto Exit;
+   }
+   
+   {
+     T1_Byte*  old_cursor = parser->cursor;
+     T1_Byte*  old_limit  = parser->limit;
+     T1_UInt   n;
+
+     blend = face->blend;
+     for ( n = 0; n < (T1_UInt)num_designs; n++ )
+     {
+       T1_Token_Rec  axis_tokens[ T1_MAX_MM_DESIGNS ];
+       T1_Token_Rec* token;
+       T1_Int        axis, n_axis;
+
+       /* read axis/coordinates tokens */
+       token = design_tokens + n;
+       parser->cursor = token->start - 1;
+       parser->limit  = token->limit + 1;
+       T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+       
+       if (n == 0)
+       {
+         num_axis = n_axis;
+         error = t1_allocate_blend( face, num_designs, num_axis );
+         if (error) goto Exit;
+         blend = face->blend;
+       }
+       else if (n_axis != num_axis)
+       {
+         FT_ERROR(( "T1.design_positions: incorrect table\n" ));
+         error = FT_Err_Invalid_File_Format;
+         goto Exit;
+       }
+       
+       /* now, read each axis token into the design position */
+       for (axis = 0; axis < n_axis; axis++ )
+       {
+         T1_Token_Rec*  token2 = axis_tokens + axis;
+         parser->cursor = token2->start;
+         parser->limit  = token2->limit;
+         blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+       }
+     }
+     
+     loader->parser.cursor = old_cursor;
+     loader->parser.limit  = old_limit;
+   }
+   
+ Exit:
+   loader->parser.error = error;
+ }
+
+ static void  parse_blend_design_map( T1_Face  face, T1_Loader*  loader )
+ {
+   FT_Error      error  = 0;
+   T1_Parser*    parser = &loader->parser;
+   T1_Blend*     blend;
+   T1_Token_Rec  axis_tokens[ T1_MAX_MM_AXIS ];
+   T1_Int        n, num_axis;
+   T1_Byte*      old_cursor;
+   T1_Byte*      old_limit;
+   FT_Memory     memory = face->root.memory;
+   
+   T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+   if (num_axis <= 0 || num_axis > T1_MAX_MM_AXIS)
+   {
+     FT_ERROR(( "T1.design map: incorrect number of axis: %d\n",
+                num_axis ));
+     error = FT_Err_Invalid_File_Format;
+     goto Exit;
+   }
+   old_cursor = parser->cursor;
+   old_limit  = parser->limit;
+
+   error = t1_allocate_blend( face, 0, num_axis );
+   if (error) goto Exit;
+   blend = face->blend;
+
+   /* now, read each axis design map */
+   for ( n = 0; n < num_axis; n++ )
+   {
+     T1_DesignMap*   map = blend->design_map + n;
+     T1_Token_Rec*   token;
+     T1_Int          p, num_points;
+     
+     token = axis_tokens + n;
+     parser->cursor = token->start;
+     parser->limit  = token->limit;
+     
+     /* count the number of map points */
+     {
+       T1_Byte*  p     = token->start;
+       T1_Byte*  limit = token->limit;
+       
+       num_points = 0;
+       for ( ; p < limit; p++ )
+         if (p[0] == '[')
+           num_points++;
+     }
+     if (num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS)
+     {
+       FT_ERROR(( "T1.design map: incorrect table\n" ));
+       error = FT_Err_Invalid_File_Format;
+       goto Exit;
+     }
+     
+     /* allocate design map data */
+     if ( ALLOC_ARRAY( map->design_points, num_points*2, FT_Fixed ) )
+       goto Exit;
+     map->blend_points = map->design_points + num_points;
+     map->num_points   = (FT_Byte)num_points;
+     
+     for ( p = 0; p < num_points; p++ )
+     {
+       map->design_points[p] = T1_ToInt( parser );
+       map->blend_points [p] = T1_ToFixed( parser, 0 );
+     }
+   }   
+   
+   parser->cursor = old_cursor;
+   parser->limit  = old_limit;
+ Exit:
+   parser->error = error;
+ }
+
+ static void parse_weight_vector( T1_Face   face, T1_Loader*  loader )
+ {
+   FT_Error      error  = 0;
+   T1_Parser*    parser = &loader->parser;
+   T1_Blend*     blend  = face->blend;
+   T1_Token_Rec  master;
+   T1_UInt       n;
+   T1_Byte*      old_cursor;
+   T1_Byte*      old_limit;
+   
+   if (!blend || blend->num_designs == 0)
+   {
+     FT_ERROR(( "t1.weight_vector: too early !!\n" ));
+     error = FT_Err_Invalid_File_Format;
+     goto Exit;
+   }
+   
+   T1_ToToken( parser, &master );
+   if (master.type != t1_token_array)
+   {
+     FT_ERROR(( "t1.weight_vector: incorrect format !!\n" ));
+     error = FT_Err_Invalid_File_Format;
+     goto Exit;
+   }
+   
+   old_cursor = parser->cursor;
+   old_limit  = parser->limit;
+
+   parser->cursor = master.start;
+   parser->limit  = master.limit;
+   for ( n = 0; n < blend->num_designs; n++ )
+   {
+     blend->default_weight_vector[n] =
+     blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
+   }
+   
+   parser->cursor = old_cursor;
+   parser->limit  = old_limit;
+ Exit:
+   parser->error = error;
+ }
+
+ /* the keyword /shareddict appears in some multiple master fonts with a lot */
+ /* of Postscript garbage behind it (that's completely out of spec !!), we   */
+ /* detect it and terminate the parsing                                      */
+ static  void parse_shared_dict( T1_Face  face, T1_Loader*  loader )
+ {
+   T1_Parser*  parser = &loader->parser;
+   
+   UNUSED(face);
+   
+   parser->cursor = parser->limit;
+   parser->error  = 0;
+ }
+ 
  /***************************************************************************/
  /***************************************************************************/
  /*****                                                                 *****/
@@ -802,6 +1063,13 @@
     T1_KEYWORD_CALLBACK( "Encoding", parse_encoding  ),
     T1_KEYWORD_CALLBACK( "Subrs",    parse_subrs     ),
     T1_KEYWORD_CALLBACK( "CharStrings", parse_charstrings ),
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    T1_KEYWORD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions ),
+    T1_KEYWORD_CALLBACK( "BlendDesignMap", parse_blend_design_map ),
+    T1_KEYWORD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types ),
+    T1_KEYWORD_CALLBACK( "WeightVector", parse_weight_vector ),
+    T1_KEYWORD_CALLBACK( "shareddict",   parse_shared_dict ),
+#endif    
     T1_KEYWORD_CALLBACK( 0, 0 )
   };
 
@@ -864,7 +1132,7 @@
           while (cur2 < limit && is_alpha(*cur2)) cur2++;
           len  = cur2-cur;
 
-          if (len > 0 && len < 20)
+          if (len > 0 && len < 22)
           {
             if (!loader->fontdata)
             {
--- a/src/type1z/t1load.h
+++ b/src/type1z/t1load.h
@@ -46,6 +46,10 @@
   LOCAL_DEF
   T1_Error  T1_Open_Face( T1_Face  face );
 
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+  LOCAL_DEF
+  void T1_Done_Blend( T1_Face  face );
+#endif
 
 #ifdef __cplusplus
   }
--- a/src/type1z/t1objs.c
+++ b/src/type1z/t1objs.c
@@ -138,6 +138,12 @@
     {
       memory = face->root.memory;
 
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+      /* release multiple masters information */
+      T1_Done_Blend( face );
+      face->blend = 0;
+#endif
+
       /* release font info strings */
       {
         T1_FontInfo*  info = &type1->font_info;
--- a/src/type1z/t1parse.c
+++ b/src/type1z/t1parse.c
@@ -621,6 +621,7 @@
   }
 
 
+#if 0
   static
   T1_String*  t1_tostring( T1_Byte* *cursor, T1_Byte* limit, FT_Memory memory )
   {
@@ -670,6 +671,7 @@
     *cursor = cur;
     return result;
   }
+#endif
 
   static
   int  t1_tobool( T1_Byte* *cursor, T1_Byte* limit )
@@ -732,7 +734,7 @@
       /* if this is an array, and we have no blend, an error occurs */
       if (max_objects == 0)
         goto Fail;
-        
+
       count = max_objects;
       index = 1;
     }
@@ -894,6 +896,7 @@
   }
 
 
+#if 0
   LOCAL_FUNC
   T1_String*  T1_ToString( T1_Parser* parser )
   {
@@ -906,7 +909,7 @@
   {
     return t1_tobool( &parser->cursor, parser->limit );
   }
-
+#endif
 
 
   static
--- a/src/type1z/t1parse.h
+++ b/src/type1z/t1parse.h
@@ -280,25 +280,14 @@
                            T1_Fixed*  values,
                            T1_Int     power_ten );
 
+#if 0
   LOCAL_DEF
   T1_String*  T1_ToString( T1_Parser* parser );
 
-
   LOCAL_DEF
   T1_Bool   T1_ToBool( T1_Parser* parser );
-
-#if 0
-  LOCAL_DEF
-  T1_Int  T1_ToImmediate( T1_Parser*  parser );
 #endif
 
-#if 0
-  /* load a single field in an object */
-  LOCAL_DEF
-  T1_Error  T1_Load_Field( T1_Parser*     parser,
-                           void*          object,
-                           T1_Field_Rec*  field );
-#endif