shithub: freetype+ttf2subf

Download patch

ref: 1c9a1cab3f6f5d3387094726e5958a29afd2e2c2
parent: 1fb6eea7d12ca6fe6649cfee191dc56240f8cc89
author: David Turner <[email protected]>
date: Wed May 24 17:12:02 EDT 2000

important modifications to the Type1z driver
these are used to prepare for multiple master fonts

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/internal/t1types.h
+++ b/include/freetype/internal/t1types.h
@@ -29,7 +29,6 @@
 #endif
 
 
-
 /*************************************************************************/
 /*************************************************************************/
 /*************************************************************************/
@@ -391,6 +390,9 @@
     FT_CharMapRec charmaprecs[2];
     FT_CharMap    charmaps[2];
     PS_Unicodes   unicode_map;
+
+    /* support for multiple masters */
+    T1_Blend*     blend;
 
   } T1_FaceRec;
 
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -84,8 +84,8 @@
     FT_Int       blue_shift;
     FT_Int       blue_fuzz;
 
-    FT_UShort    standard_width;
-    FT_UShort    standard_height;
+    FT_UShort    standard_width[1];
+    FT_UShort    standard_height[1];
 
     FT_Byte      num_snap_widths;
     FT_Byte      num_snap_heights;
@@ -116,10 +116,8 @@
   */
   typedef enum
   {
-    t1_blend_none = 0,
-
     /* required fields in a FontInfo blend dictionary */
-    t1_blend_underline_position,
+    t1_blend_underline_position = 0,
     t1_blend_underline_thickness,
     t1_blend_italic_angle,
 
@@ -139,38 +137,35 @@
     /* never remove */
     t1_blend_max
 
-  } T1_Flags;
+  } 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
 
-  typedef struct T1_Blend_Pos
+  /* this structure is used to store the BlendDesignMap entry for an axis */
+  typedef struct T1_DesignMap_
   {
-    FT_Fixed  min;
-    FT_Fixed  max;
+    FT_Byte    num_points;
+    FT_Fixed*  design_points;
+    FT_Fixed*  blend_points;
+    
+  } T1_DesignMap;
 
-  } T1_Blend_Pos;
-
- /*************************************************************************
-  *
-  * <Struct>
-  *    T1_Blend
-  *
-  * <Description>
-  *    A structure used to describe the multiple-master fonts information
-  *    of a given Type 1 font.
-  *
-  */
   typedef struct T1_Blend_
   {
-    FT_Int       num_axis;
-    FT_String*   axis_types[4];
-
-    /* XXXX : add /BlendDesignMap entries */
-
-    FT_Int       num_blends;
-    T1_Flags*    flags    [17];
-    T1_Private*  privates [17];
-    T1_FontInfo* fontinfos[17];
-
+    FT_UInt       num_designs;
+    FT_UInt       num_axis;
+    
+    FT_String*    axis_names[ T1_MAX_MM_AXIS ];
+    FT_Fixed*     design_pos[ T1_MAX_MM_DESIGNS ];
+    T1_DesignMap  design_map[ T1_MAX_MM_AXIS ];
+    
+    T1_FontInfo*  font_infos[ T1_MAX_MM_DESIGNS+1 ];
+    T1_Private*   privates  [ T1_MAX_MM_DESIGNS+1 ];
+    
+    FT_ULong      blend_bitflags;
+  
   } T1_Blend;
 
 
--- a/src/type1/t1hinter.c
+++ b/src/type1/t1hinter.c
@@ -291,7 +291,7 @@
 
     /* start with horizontal snap zones */
     direction      = 0;
-    standard_width = priv->standard_width;
+    standard_width = priv->standard_width[0];
     n_zones        = priv->num_snap_widths;
     base_zone      = hints->snap_widths;
     orgs           = priv->stem_snap_widths;
@@ -458,7 +458,7 @@
 
       /* continue with vertical snap zone */
       direction++;
-      standard_width = priv->standard_height;
+      standard_width = priv->standard_height[0];
       n_zones        = priv->num_snap_heights;
       base_zone      = hints->snap_heights;
       orgs           = priv->stem_snap_heights;
--- a/src/type1/t1objs.c
+++ b/src/type1/t1objs.c
@@ -330,7 +330,7 @@
 
         /* now compute the maximum advance width */
 
-        root->max_advance_width = type1->private_dict.standard_width;
+        root->max_advance_width = type1->private_dict.standard_width[0];
 
         /* compute max advance width for proportional fonts */
         if (!type1->font_info.is_fixed_pitch)
--- a/src/type1z/t1load.c
+++ b/src/type1z/t1load.c
@@ -70,84 +70,314 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_t1load
 
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                    MULTIPLE MASTERS SUPPORT                     *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ static  T1_Error  t1_allocate_blend( T1_Face   face,
+                                      T1_UInt   num_designs,
+                                      T1_UInt   num_axis )
+ {
+   T1_Blend*  blend;
+   FT_Memory  memory = face->root.memory;
+   T1_Error   error  = 0;
+   
+   blend = face->blend;
+   if (!blend)
+   {
+     if ( ALLOC( blend, sizeof(*blend) ) )
+       goto Exit;
+       
+     face->blend = blend;
+   }
+   
+   /* allocate design data if needed */
+   if (num_designs > 0)
+   {
+     if (blend->num_designs == 0)
+     {
+       /* 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 )     )
+         goto Exit;
+  
+       blend->font_infos[0] = &face->type1.font_info;
+       blend->privates  [0] = &face->type1.private_dict;
+       blend->num_designs   = num_designs;
+     }
+     else if (blend->num_designs != num_designs)
+       goto Fail;
+   }
+   
+   /* allocate axis data if needed */
+   if (num_axis > 0)
+   {
+     if (blend->num_axis != 0 && blend->num_axis != num_axis)
+       goto Fail;
+       
+     blend->num_axis = num_axis;
+   }
+   
+   /* allocate the blend design pos table if needed */
+   num_designs = blend->num_designs;
+   num_axis    = blend->num_axis;
+   if ( num_designs && num_axis && blend->design_pos[0] == 0)
+   {
+     FT_UInt  n;
+     
+     if ( ALLOC_ARRAY( blend->design_pos[0], num_designs*num_axis, FT_Fixed ) )
+       goto Exit;
+       
+     for ( n = 1; n < num_designs; n++ )
+       blend->design_pos[n] = blend->design_pos[0] + num_axis*n;       
+   }
+   
+ Exit:
+   return error;
+ Fail:
+   error = -1;
+   goto Exit;
+ }                                  
+
+
+ static  void t1_done_blend( T1_Face  face )
+ {
+   FT_Memory  memory = face->root.memory;
+   T1_Blend*  blend  = face->blend;
+   
+   if (blend)
+   {
+     T1_UInt  num_designs = blend->num_designs;
+     T1_UInt  num_axis    = blend->num_axis;
+     T1_UInt  n;
+          
+     /* release design pos table */
+     FREE( blend->design_pos[0] );
+     for ( n = 1; n < num_designs; n++ )
+       blend->design_pos[n] = 0;
+
+     /* release blend "private" and "font info" dictionaries */
+     FREE( blend->privates[1] );
+     FREE( blend->font_infos[1] );
+     for ( n = 0; n < num_designs; n++ )
+     {
+       blend->privates  [n] = 0;
+       blend->font_infos[n] = 0;
+     }
+
+     /* release axis names */
+     for ( n = 0; n < num_axis; n++ )
+       FREE( blend->axis_names[n] );
+     
+     /* release design map */
+     for ( n = 0; n < num_axis; n++ )
+     {
+       T1_DesignMap*  dmap = blend->design_map + n;
+       FREE( dmap->design_points );
+       FREE( dmap->blend_points );
+       dmap->num_points = 0;
+     }
+     
+     FREE( face->blend );
+   }
+ }
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                      TYPE 1 SYMBOL PARSING                      *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ /*********************************************************************
+  *
+  *  First of all, define the token field static variables. This is
+  *  a set of T1_Field_Rec variables used later..
+  *
+  *********************************************************************/
+
+#define T1_NEW_STRING( _name, _field ) \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_STRING( T1TYPE, _field );
+
+#define T1_NEW_BOOL( _name, _field )   \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_BOOL( T1TYPE, _field );
+   
+#define T1_NEW_NUM( _name, _field )    \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_NUM( T1TYPE, _field );
+   
+#define T1_NEW_FIXED( _name, _field )  \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_FIXED( T1TYPE, _field, _power );
+
+#define T1_NEW_NUM_TABLE( _name, _field, _max, _count ) \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_NUM_ARRAY( T1TYPE, _field, _count, _max );
+   
+#define T1_NEW_FIXED_TABLE( _name, _field, _max, _count ) \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_FIXED_ARRAY( T1TYPE, _field, _count, _max );
+
+#define T1_NEW_NUM_TABLE2( _name, _field, _max ) \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_NUM_ARRAY2( T1TYPE, _field, _max );
+   
+#define T1_NEW_FIXED_TABLE2( _name, _field, _max ) \
+   static const  T1_Field_Rec  t1_field_ ## _field = T1_FIELD_FIXED_ARRAY2( T1TYPE, _field, _max );
+
+
+#define T1_FONTINFO_STRING(n,f)        T1_NEW_STRING(n,f)
+#define T1_FONTINFO_NUM(n,f)           T1_NEW_NUM(n,f)
+#define T1_FONTINFO_BOOL(n,f)          T1_NEW_BOOL(n,f)
+#define T1_PRIVATE_NUM(n,f)            T1_NEW_NUM(n,f)
+#define T1_PRIVATE_FIXED(n,f)          T1_NEW_FIXED(n,f)
+#define T1_PRIVATE_NUM_TABLE(n,f,m,c)  T1_NEW_NUM_TABLE(n,f,m,c)
+#define T1_PRIVATE_NUM_TABLE2(n,f,m)   T1_NEW_NUM_TABLE2(n,f,m)
+#define T1_TOPDICT_NUM(n,f)            T1_NEW_NUM(n,f)
+#define T1_TOPDICT_NUM_FIXED2(n,f,m)   T1_NEW_FIXED_TABLE2(n,f,m)
+
+/* including this file defines all field variables */
+#include <t1tokens.h>
+
+ /*********************************************************************
+  *
+  *  Second, define the keyword variables. This is a set of T1_KeyWord
+  *  structures used to model the way each keyword is "loaded"..
+  *
+  *********************************************************************/
+
   typedef  void  (*T1_Parse_Func)( T1_Face   face, T1_Loader*  loader );
 
+  typedef enum T1_KeyWord_Type_
+  {
+    t1_keyword_callback = 0,
+    t1_keyword_field,
+    t1_keyword_field_table
+    
+  } T1_KeyWord_Type;
+  
+  typedef enum T1_KeyWord_Location_
+  {
+    t1_keyword_type1 = 0,
+    t1_keyword_font_info,
+    t1_keyword_private
+  
+  } T1_KeyWord_Location;
+  
   typedef  struct T1_KeyWord_
   {
-    const char*    name;
-    T1_Parse_Func  parsing;
+    const char*          name;
+    T1_KeyWord_Type      type;
+    T1_KeyWord_Location  location;
+    T1_Parse_Func        parsing;
+    const T1_Field_Rec*  field;
 
   } T1_KeyWord;
 
-  /* some handy macros used to easily define parsing callback functions */
-  /* each callback is in charge of loading a value and storing it in a  */
-  /* given field of the Type 1 face..                                   */
 
-#define PARSE_(x)  static void FT_XCAT(parse_,x) ( T1_Face  face, T1_Loader* loader )
+#define T1_KEYWORD_CALLBACK( name, callback )  \
+         { name, t1_keyword_callback, t1_keyword_type1, callback, 0 }
 
-#define FIELD   FACE.x
+#define T1_KEYWORD_TYPE1( name, f ) \
+         { name, t1_keyword_field, t1_keyword_type1, 0, &t1_field_ ## f }
+         
+#define T1_KEYWORD_FONTINFO( name, f ) \
+         { name, t1_keyword_field, t1_keyword_font_info, 0, &t1_field_ ## f }
 
-#define PARSE_STRING(s,x)   PARSE_(x)                               \
-        {                                                           \
-          FACE.x = T1_ToString(&loader->parser);                  \
-          FT_TRACE2(( "type1.parse_%s: \"%s\"\n", #x, FACE.x ));   \
-        }
+#define T1_KEYWORD_PRIVATE( name, f ) \
+         { name, t1_keyword_field, t1_keyword_private, 0, &t1_field_ ## f }
 
-#define PARSE_NUM(s,x,t)  PARSE_(x)                                 \
-        {                                                           \
-          FACE.x = (t)T1_ToInt(&loader->parser);                  \
-          FT_TRACE2(( "type1.parse_%s: \"%d\"\n", #x, FACE.x ));   \
-        }
+#define T1_KEYWORD_FONTINFO_TABLE( name, f ) \
+         { name, t1_keyword_field_table, t1_keyword_font_info, 0, &t1_field_ ## f }
 
-#define PARSE_INT(s,x)   PARSE_(x)                                  \
-        {                                                           \
-          FACE.x = T1_ToInt(&loader->parser);                     \
-          FT_TRACE2(( "type1.parse_%s: \"%d\"\n", #x, FACE.x ));   \
-        }
+#define T1_KEYWORD_PRIVATE_TABLE( name, f ) \
+         { name, t1_keyword_field_table, t1_keyword_private, 0, &t1_field_ ## f }
 
-#define PARSE_BOOL(s,x)   PARSE_(x)                                 \
-        {                                                           \
-          FACE.x = T1_ToBool(&loader->parser);                    \
-          FT_TRACE2(( "type1.parse_%s : \"%s\"\n",                \
-                       #x, FACE.x ? "true" : "false" ));              \
-        }
+#undef  T1_FONTINFO_STRING
+#undef  T1_FONTINFO_NUM
+#undef  T1_FONTINFO_BOOL
+#undef  T1_PRIVATE_NUM
+#undef  T1_PRIVATE_FIXED
+#undef  T1_PRIVATE_NUM_TABLE
+#undef  T1_PRIVATE_NUM_TABLE2
+#undef  T1_TOPDICT_NUM
+#undef  T1_TOPDICT_NUM_FIXED2
 
-#define PARSE_FIXED(s,x)   PARSE_(x)                                        \
-        {                                                                   \
-          FACE.x = T1_ToFixed(&loader->parser,3);                         \
-          FT_TRACE2(( "type1.parse_%s: \"%f\"\n", #x, FACE.x/65536.0 ));   \
-        }
+#define T1_FONTINFO_STRING(n,f)        T1_KEYWORD_FONTINFO(n,f),
+#define T1_FONTINFO_NUM(n,f)           T1_KEYWORD_FONTINFO(n,f),
+#define T1_FONTINFO_BOOL(n,f)          T1_KEYWORD_FONTINFO(n,f),
+#define T1_PRIVATE_NUM(n,f)            T1_KEYWORD_PRIVATE(n,f),
+#define T1_PRIVATE_FIXED(n,f)          T1_KEYWORD_PRIVATE(n,f),
+#define T1_PRIVATE_NUM_TABLE(n,f,m,c)  T1_KEYWORD_PRIVATE_TABLE(n,f),
+#define T1_PRIVATE_NUM_TABLE2(n,f,m)   T1_KEYWORD_PRIVATE_TABLE(n,f),
+#define T1_TOPDICT_NUM(n,f)            T1_KEYWORD_TYPE1(n,f),
+#define T1_TOPDICT_NUM_FIXED2(n,f,m)   T1_KEYWORD_TYPE1(n,f),
 
-#define PARSE_COORDS(s,c,m,x)   PARSE_(x)                                         \
-        {                                                                         \
-          FACE.c = T1_ToCoordArray(&loader->parser, m, (T1_Short*)FACE.x );   \
-          FT_TRACE2(( "type1.parse_%s\n", #x ));                                   \
-        }
 
-#define PARSE_FIXEDS(s,c,m,x)   PARSE_(x)                                           \
-        {                                                                           \
-          FACE.c = T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)FACE.x, 3 );  \
-          FT_TRACE2(( "type1.parse_%s\n", #x ));                                     \
+  static  T1_Error   t1_load_keyword( T1_Face     face,
+                                      T1_Loader*  loader,
+                                      T1_KeyWord* keyword )
+  {
+    T1_Error  error;
+    void*     dummy_object;
+    void**    objects;
+    T1_UInt   max_objects;
+    T1_Blend* blend = face->blend;
+    
+    /* if the keyword has a dedicated callback, call it */
+    if (keyword->type == t1_keyword_callback)
+    {
+      keyword->parsing( face, loader );
+      error = loader->parser.error;
+      goto Exit;
+    }
+    
+    /* now, the keyword is either a simple field, or a table of fields */
+    /* we are now going to take care of it..                           */
+    switch (keyword->location)
+    {
+      case t1_keyword_font_info:
+        {
+          dummy_object = &face->type1.font_info;
+          objects      = &dummy_object;
+          max_objects  = 0;
+          if (blend)
+          {
+            objects     = (void**)blend->font_infos;
+            max_objects = blend->num_designs;
+          }
         }
-
-
-#define PARSE_COORDS2(s,m,x)   PARSE_(x)                                     \
-        {                                                                    \
-          (void)T1_ToCoordArray( &loader->parser, m, (T1_Short*)&FACE.x );  \
-          FT_TRACE2(( "type1.parse_%s\n", #x ));                              \
+        break;
+        
+      case t1_keyword_private:
+        {
+          dummy_object = &face->type1.private_dict;
+          objects      = &dummy_object;
+          max_objects  = 0;
+          if (blend)
+          {
+            objects     = (void**)blend->privates;
+            max_objects = blend->num_designs;
+          }
         }
+        break;
+      
+      default:
+        dummy_object = &face->type1;
+        objects      = &dummy_object;
+        max_objects  = 0;
+    }
+    
+    if (keyword->type == t1_keyword_field_table)
+      error = T1_Load_Field_Table( &loader->parser, keyword->field, objects, max_objects, 0 );
+    else
+      error = T1_Load_Field( &loader->parser, keyword->field, objects, max_objects, 0 );
+    
+  Exit:
+    return error;
+  }                                
 
-#define PARSE_FIXEDS2(s,m,x)   PARSE_(x)                                           \
-        {                                                                           \
-          (void)T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)&FACE.x, 3 );  \
-          FT_TRACE2(( "type1.parse_%s\n", #x ));                                     \
-        }
 
-
-/* define all parsing callbacks */
-#include <t1tokens.h>
-
-
   static
   int  is_space( char c )
   {
@@ -274,6 +504,22 @@
   }
 
   static
+  void  parse_font_matrix( T1_Face  face, T1_Loader*  loader )
+  {
+    T1_Parser*  parser = &loader->parser;
+    FT_Matrix*  matrix = &face->type1.font_matrix;
+    T1_Fixed    temp[4];
+
+    (void)T1_ToFixedArray( parser, 4, temp, 3 );
+    matrix->xx = temp[0];
+    matrix->yx = temp[1];
+    matrix->xy = temp[2];
+    matrix->yy = temp[3];
+  }
+
+
+
+  static
   void  parse_encoding( T1_Face  face, T1_Loader*  loader )
   {
     T1_Parser*  parser = &loader->parser;
@@ -542,40 +788,21 @@
   }
 
 
-#undef PARSE_STRING
-#undef PARSE_INT
-#undef PARSE_NUM
-#undef PARSE_BOOL
-#undef PARSE_FIXED
-#undef PARSE_COORDS
-#undef PARSE_FIXEDS
-#undef PARSE_COORDS2
-#undef PARSE_FIXEDS2
 
-#undef PARSE_
-#define PARSE_(s,x)   { s, parse_##x },
 
-#define PARSE_STRING(s,x)      PARSE_(s,x)
-#define PARSE_INT(s,x)         PARSE_(s,x)
-#define PARSE_NUM(s,x,t)       PARSE_(s,x)
-#define PARSE_BOOL(s,x)        PARSE_(s,x)
-#define PARSE_FIXED(s,x)       PARSE_(s,x)
-#define PARSE_COORDS(s,c,m,x)  PARSE_(s,x)
-#define PARSE_FIXEDS(s,c,m,x)  PARSE_(s,x)
-#define PARSE_COORDS2(s,m,x)   PARSE_(s,x)
-#define PARSE_FIXEDS2(s,m,x)   PARSE_(s,x)
-
   static
   const T1_KeyWord  t1_keywords[] =
   {
-#include <t1tokens.h>
+#include <t1tokens.h>  
+    
     /* now add the special functions... */
-    { "FontName",    parse_font_name   },
-    { "FontBBox",    parse_font_bbox   },
-    { "Encoding",    parse_encoding    },
-    { "Subrs",       parse_subrs       },
-    { "CharStrings", parse_charstrings },
-    { 0, 0 }
+    T1_KEYWORD_CALLBACK( "FontName", parse_font_name ),
+    T1_KEYWORD_CALLBACK( "FontBBox", parse_font_bbox ),
+    T1_KEYWORD_CALLBACK( "FontMatrix", parse_font_matrix ),
+    T1_KEYWORD_CALLBACK( "Encoding", parse_encoding  ),
+    T1_KEYWORD_CALLBACK( "Subrs",    parse_subrs     ),
+    T1_KEYWORD_CALLBACK( "CharStrings", parse_charstrings ),
+    T1_KEYWORD_CALLBACK( 0, 0 )
   };
 
 
@@ -585,7 +812,7 @@
                         T1_Byte*    base,
                         T1_Long     size )
   {
-    T1_Parser*  parser = &loader->parser;
+    T1_Parser*  parser   = &loader->parser;
 
     parser->cursor = base;
     parser->limit  = base + size;
@@ -597,8 +824,37 @@
 
       for ( ;cur < limit; cur++ )
       {
+        /* look for "FontDirectory", which causes problems on some fonts */
+        if ( *cur == 'F' && cur+25 < limit &&
+             strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+        {
+          T1_Byte*  cur2;
+          
+          /* skip the "FontDirectory" keyword */
+          cur += 13;
+          cur2 = cur;
+          
+          /* lookup the 'known' keyword */
+          while (cur < limit && *cur != 'k' && strncmp( (char*)cur, "known", 5 ) )
+            cur++;
+          
+          if (cur < limit)
+          {
+            T1_Token_Rec  token;
+            
+            /* skip the "known" keyword and the token following it */
+            cur += 5;
+            loader->parser.cursor = cur;
+            T1_ToToken( &loader->parser, &token );
+            
+            /* if the last token was an array, skip it !! */
+            if (token.type == t1_token_array)
+              cur2 = parser->cursor;
+          }
+          cur = cur2;
+        }
         /* look for immediates */
-        if (*cur == '/' && cur+2 < limit)
+        else if (*cur == '/' && cur+2 < limit)
         {
           T1_Byte* cur2;
           T1_Int   len;
@@ -610,38 +866,46 @@
 
           if (len > 0 && len < 20)
           {
-            /* now, compare the immediate name to the keyword table */
-            T1_KeyWord*  keyword = (T1_KeyWord*)t1_keywords;
-
-            for (;;)
+            if (!loader->fontdata)
             {
-              T1_Byte*  name;
-
-              name = (T1_Byte*)keyword->name;
-              if (!name) break;
-
-              if ( cur[0] == name[0] &&
-                   len == (T1_Int)strlen((const char*)name) )
+              if ( strncmp( (char*)cur, "FontInfo", 8 ) == 0 )
+                loader->fontdata = 1;
+            }
+            else
+            {
+              /* now, compare the immediate name to the keyword table */
+              T1_KeyWord*  keyword = (T1_KeyWord*)t1_keywords;
+  
+              for (;;)
               {
-                T1_Int  n;
-                for ( n = 1; n < len; n++ )
-                  if (cur[n] != name[n])
-                    break;
-
-                if (n >= len)
+                T1_Byte*  name;
+  
+                name = (T1_Byte*)keyword->name;
+                if (!name) break;
+  
+                if ( cur[0] == name[0] &&
+                     len == (T1_Int)strlen((const char*)name) )
                 {
-                  /* we found it - run the parsing callback !! */
-                  parser->cursor = cur2;
-                  skip_whitespace( parser );
-                  keyword->parsing( face, loader );
-                  if (parser->error)
-                    return parser->error;
-
-                  cur = parser->cursor;
-                  break;
+                  T1_Int  n;
+                  for ( n = 1; n < len; n++ )
+                    if (cur[n] != name[n])
+                      break;
+  
+                  if (n >= len)
+                  {
+                    /* we found it - run the parsing callback !! */
+                    parser->cursor = cur2;
+                    skip_whitespace( parser );
+                    parser->error = t1_load_keyword( face, loader, keyword );
+                    if (parser->error)
+                      return parser->error;
+  
+                    cur = parser->cursor;
+                    break;
+                  }
                 }
+                keyword++;
               }
-              keyword++;
             }
           }
         }
@@ -664,6 +928,7 @@
     loader->charstrings.init    = 0;
     loader->glyph_names.init    = 0;
     loader->subrs.init          = 0;
+    loader->fontdata            = 0;
   }
 
   static
--- a/src/type1z/t1load.h
+++ b/src/type1z/t1load.h
@@ -39,6 +39,7 @@
 
     T1_Int           num_subrs;
     T1_Table         subrs;
+    T1_Bool          fontdata;
 
   } T1_Loader;
 
--- a/src/type1z/t1objs.c
+++ b/src/type1z/t1objs.c
@@ -298,7 +298,7 @@
 
         /* now compute the maximum advance width */
 
-        root->max_advance_width = face->type1.private_dict.standard_width;
+        root->max_advance_width = face->type1.private_dict.standard_width[0];
 
         /* compute max advance width for proportional fonts */
         if (!face->type1.font_info.is_fixed_pitch)
--- a/src/type1z/t1parse.c
+++ b/src/type1z/t1parse.c
@@ -39,6 +39,18 @@
 #define FT_COMPONENT  trace_t1load
 
 /*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+/*****                                                               *****/
+/*****           IMPLEMENTATION OF T1_TABLE OBJECT                   *****/
+/*****                                                               *****/
+/*****                                                               *****/
+/*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+
+
+/*************************************************************************/
 /*                                                                       */
 /* <Function> T1_New_Table                                               */
 /*                                                                       */
@@ -221,6 +233,163 @@
     }
   }
 
+/*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+/*****                                                               *****/
+/*****               INPUT STREAM PARSER                             *****/
+/*****                                                               *****/
+/*****                                                               *****/
+/*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+
+  #define IS_T1_WHITESPACE(c)  ( (c) == ' '  || (c) == '\t' )
+  #define IS_T1_LINESPACE(c)   ( (c) == '\r' || (c) == '\n' )
+
+  #define IS_T1_SPACE(c)  ( IS_T1_WHITESPACE(c) || IS_T1_LINESPACE(c) )
+
+  LOCAL_FUNC
+  void     T1_Skip_Spaces( T1_Parser*  parser )
+  {
+    T1_Byte* cur   = parser->cursor;
+    T1_Byte* limit = parser->limit;
+
+    while (cur < limit)
+    {
+      T1_Byte  c = *cur;
+      if (!IS_T1_SPACE(c))
+        break;
+      cur++;
+    }
+    parser->cursor = cur;
+  }
+
+  LOCAL_FUNC
+  void  T1_ToToken( T1_Parser*     parser,
+                    T1_Token_Rec*  token )
+  {
+    T1_Byte*  cur;
+    T1_Byte*  limit;
+    T1_Byte   starter, ender;
+    T1_Int    embed;
+
+    token->type  = t1_token_none;
+    token->start = 0;
+    token->limit = 0;
+
+    /* first of all, skip space */
+    T1_Skip_Spaces(parser);
+
+    cur   = parser->cursor;
+    limit = parser->limit;
+
+    if ( cur < limit )
+    {
+      switch (*cur)
+      {
+        /************* check for strings ***********************/
+        case '(':
+          token->type = t1_token_string;
+          ender = ')';
+          goto Lookup_Ender;
+
+        /************* check for programs/array ****************/
+        case '{':
+          token->type = t1_token_array;
+          ender = '}';
+          goto Lookup_Ender;
+
+        /************* check for table/array ******************/
+        case '[':
+          token->type = t1_token_array;
+          ender = ']';
+
+        Lookup_Ender:
+          embed   = 1;
+          starter = *cur++;
+          token->start = cur;
+          while (cur < limit)
+          {
+            if (*cur == starter)
+              embed++;
+            else if (*cur == ender)
+            {
+              embed--;
+              if (embed <= 0)
+              {
+                token->limit = cur++;
+                break;
+              }
+            }
+            cur++;
+          }
+          break;
+
+        /* **************** otherwise, it's any token **********/
+        default:
+          token->start = cur++;
+          token->type  = t1_token_any;
+          while (cur < limit && !IS_T1_SPACE(*cur))
+            cur++;
+
+          token->limit = cur;
+      }
+
+      if (!token->limit)
+      {
+        token->start = 0;
+        token->type  = t1_token_none;
+      }
+
+      parser->cursor = cur;
+    }
+  }
+
+
+  LOCAL_FUNC
+  void  T1_ToTokenArray( T1_Parser*     parser,
+                         T1_Token_Rec*  tokens,
+                         T1_UInt        max_tokens,
+                         T1_Int        *pnum_tokens )
+  {
+    T1_Token_Rec  master;
+
+    *pnum_tokens = -1;
+
+    T1_ToToken( parser, &master );
+    if (master.type == t1_token_array)
+    {
+      T1_Byte*       old_cursor = parser->cursor;
+      T1_Byte*       old_limit  = parser->limit;
+      T1_Token_Rec*  cur        = tokens;
+      T1_Token_Rec*  limit      = cur + max_tokens;
+
+      parser->cursor = master.start;
+      parser->limit  = master.limit;
+
+      while (parser->cursor < parser->limit)
+      {
+        T1_Token_Rec  token;
+        
+        T1_ToToken( parser, &token );
+        if (!token.type)
+          break;
+          
+        if (cur < limit)
+          *cur = token;
+          
+        cur++;
+      }
+
+      *pnum_tokens = cur - tokens;
+
+      parser->cursor = old_cursor;
+      parser->limit  = old_limit;
+    }
+  }
+
+
   static
   T1_Long  t1_toint( T1_Byte* *cursor,
                      T1_Byte*  limit )
@@ -533,7 +702,166 @@
   }
 
 
+
+ /* Loads a simple field (i.e. non-table) into the current list of objects */
   LOCAL_FUNC
+  T1_Error  T1_Load_Field( T1_Parser*           parser,
+                           const T1_Field_Rec*  field,
+                           void**               objects,
+                           T1_UInt              max_objects,
+                           T1_ULong*            pflags )
+  {
+    T1_Token_Rec  token;
+    T1_Byte*      cur;
+    T1_Byte*      limit;
+    T1_UInt       count;
+    T1_UInt       index;
+    T1_Error      error;
+
+    T1_ToToken( parser, &token );
+    if (!token.type)
+      goto Fail;
+
+    count = 1;
+    index = 0;
+    cur   = token.start;
+    limit = token.limit;
+
+    if (token.type == t1_token_array)
+    {
+      /* if this is an array, and we have no blend, an error occurs */
+      if (max_objects == 0)
+        goto Fail;
+        
+      count = max_objects;
+      index = 1;
+    }
+
+    for ( ; count > 0; count--, index++ )
+    {
+      T1_Byte*   q = (T1_Byte*)objects[index] + field->offset;
+      T1_Long    val;
+      T1_String* string;
+
+      switch (field->type)
+      {
+        case t1_field_bool:
+          {
+            val = t1_tobool( &cur, limit );
+            goto Store_Integer;
+          }
+
+        case t1_field_fixed:
+          {
+            val = t1_tofixed( &cur, limit, 3 );
+            goto Store_Integer;
+          }
+
+        case t1_field_integer:
+          {
+            val = t1_toint( &cur, limit );
+          Store_Integer:
+            switch (field->size)
+            {
+              case 1:  *(T1_Byte*)q   = (T1_Byte)val;   break;
+              case 2:  *(T1_UShort*)q = (T1_UShort)val; break;
+              default: *(T1_Long*)q   = val;
+            }
+          }
+          break;
+
+        case t1_field_string:
+          {
+            FT_Memory  memory = parser->memory;
+            FT_UInt    len    = limit-cur;
+            
+            if ( ALLOC( string, len+1 ) )
+              goto Exit;
+              
+            MEM_Copy( string, cur, len );
+            string[len] = 0;              
+
+            *(T1_String**)q = string;
+          }
+          break;
+          
+        default:
+          /* an error occured */
+          goto Fail;
+      }
+    }
+    if (pflags)
+      *pflags |= 1L << field->flag_bit;
+    error    = 0;
+
+  Exit:
+    return error;
+  Fail:
+    error = T1_Err_Invalid_File_Format;
+    goto Exit;
+  }
+
+
+#define T1_MAX_TABLE_ELEMENTS  32
+
+  LOCAL_FUNC
+  T1_Error  T1_Load_Field_Table( T1_Parser*           parser,
+                                 const T1_Field_Rec*  field,
+                                 void**               objects,
+                                 T1_UInt              max_objects,
+                                 T1_ULong*            pflags )
+  {
+    T1_Token_Rec  elements[T1_MAX_TABLE_ELEMENTS];
+    T1_Token_Rec* token;
+    T1_Int        num_elements;
+    T1_Error      error = 0;
+    T1_Byte*      old_cursor;
+    T1_Byte*      old_limit;
+    T1_Field_Rec  fieldrec = *(T1_Field_Rec*)field;
+    
+    T1_ToTokenArray( parser, elements, 32, &num_elements );
+    if (num_elements < 0)
+      goto Fail;
+
+    if (num_elements > T1_MAX_TABLE_ELEMENTS)
+      num_elements = T1_MAX_TABLE_ELEMENTS;
+
+    old_cursor = parser->cursor;
+    old_limit  = parser->limit;
+
+    /* we store the elements count */
+    *(T1_Byte*)((T1_Byte*)objects[0] + field->count_offset) = num_elements;
+
+    /* we now load each element, adjusting the field.offset on each one */
+    token = elements;
+    for ( ; num_elements > 0; num_elements--, token++ )
+    {
+      parser->cursor = token->start;
+      parser->limit  = token->limit;
+      T1_Load_Field( parser, &fieldrec, objects, max_objects, 0 );
+      fieldrec.offset += fieldrec.size;
+    }
+
+    if (pflags)
+      *pflags |= 1L << field->flag_bit;
+      
+    parser->cursor = old_cursor;
+    parser->limit  = old_limit;
+
+  Exit:
+    return error;
+  Fail:
+    error = T1_Err_Invalid_File_Format;
+    goto Exit;
+  }
+
+
+
+
+
+
+
+  LOCAL_FUNC
   T1_Long  T1_ToInt  ( T1_Parser*  parser )
   {
     return t1_toint( &parser->cursor, parser->limit );
@@ -580,41 +908,6 @@
   }
 
 
-#if 0
-  /* load a single field in an object */
-  LOCAL_FUNC
-  T1_Error  T1_Load_Field( T1_Parser*     parser,
-                           void*          object,
-                           T1_Field_Rec*  field )
-  {
-    FT_Byte*  p       = (FT_Byte*)object + field->offset;
-    FT_Byte** pcursor = &parser->cursor;
-    FT_Byte*  limit   = parser->limit;
-    
-    switch (field->type)
-    {
-      case t1_field_boolean:
-        *(T1_Bool*)p = t1_tobool( pcursor, limit );
-        break;
-        
-      case t1_field_string:
-        *(T1_String**)p = t1_tostring( pcursor, limit, parser->memory );
-        break;
-        
-      case t1_field_int:
-        *(T1_Long*)p = t1_toint( pcursor, limit );
-        break;
-        
-      case t1_field_fixed:
-        *(T1_Fixed*)p = t1_tofixed( pcursor, limit, field->power_ten );
-        break;
-        
-      default:
-        return T1_Err_Invalid_Argument;
-    }
-    return 0;
-  }                           
-#endif
 
   static
   FT_Error  read_pfb_tag( FT_Stream  stream, T1_UShort *tag, T1_Long*  size )
--- a/src/type1z/t1parse.h
+++ b/src/type1z/t1parse.h
@@ -38,6 +38,29 @@
 #endif
 
 
+  /* simple enumeration type used to identify token types */
+  typedef enum T1_Token_Type_
+  {
+    t1_token_none = 0,
+    t1_token_any,
+    t1_token_string,
+    t1_token_array,
+    
+    /* do not remove */
+    t1_token_max
+    
+  } T1_Token_Type;
+
+  /* a simple structure used to identify tokens */
+  typedef struct T1_Token_Rec_
+  {
+    T1_Byte*       start;   /* first character of token in input stream */
+    T1_Byte*       limit;   /* first character after the token          */
+    T1_Token_Type  type;    /* type of token..                          */
+  
+  } T1_Token_Rec;  
+
+  /* enumeration type used to identify object fields */
   typedef enum T1_Field_Type_
   {
     t1_field_none = 0,
@@ -45,22 +68,84 @@
     t1_field_integer,
     t1_field_fixed,
     t1_field_string,
+    t1_field_integer_array,
     t1_field_fixed_array,
-    t1_field_coord_array
     
+    /* do not remove */
+    t1_field_max
+    
   } T1_Field_Type;
-  
-  
+
+  /* structure type used to model object fields */
   typedef struct T1_Field_Rec_
   {
-    T1_Field_Type  type;      /* type of field                        */
-    FT_UInt        offset;    /* offset of field in object            */
-    FT_UInt        size;      /* size of field in bytes               */
-    T1_Int         array_max; /* maximum number of elements for array */
-    T1_Int         power_ten; /* power of ten for "fixed" fields      */
-    
+    T1_Field_Type  type;          /* type of field                        */
+    T1_UInt        offset;        /* offset of field in object            */
+    T1_UInt        size;          /* size of field in bytes               */
+    T1_UInt        array_max;     /* maximum number of elements for array */
+    T1_UInt        count_offset;  /* offset of element count for arrays   */
+    T1_Int         flag_bit;      /* bit number for field flag            */
+   
   } T1_Field_Rec;
-  
+
+#define T1_FIELD_REF(s,f)  (((s*)0)->f)
+
+#define T1_FIELD_BOOL( _ftype, _fname )               \
+    { t1_field_bool,                                  \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),   \
+      sizeof(T1_FIELD_REF(_ftype,_fname)),            \
+      0, 0, 0 }
+
+#define T1_FIELD_NUM( _ftype, _fname )                \
+    { t1_field_integer,                               \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),   \
+      sizeof(T1_FIELD_REF(_ftype,_fname)),            \
+      0, 0, 0 }
+
+#define T1_FIELD_FIXED( _ftype, _fname, _power )      \
+    { t1_field_fixed,                                 \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),   \
+      sizeof(T1_FIELD_REF(_ftype,_fname)),            \
+      0, 0, 0 }
+
+#define T1_FIELD_STRING( _ftype, _fname )             \
+    { t1_field_string,                                \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),   \
+      sizeof(T1_FIELD_REF(_ftype,_fname)),            \
+      0, 0, 0 }
+
+#define T1_FIELD_NUM_ARRAY( _ftype, _fname, _fcount, _fmax ) \
+    { t1_field_integer,                                      \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),          \
+      sizeof(T1_FIELD_REF(_ftype,_fname)[0]),                \
+      _fmax,                                                 \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fcount),         \
+      0 }
+
+#define T1_FIELD_FIXED_ARRAY( _ftype, _fname, _fcount, _fmax ) \
+    { t1_field_fixed,                                          \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),            \
+      sizeof(T1_FIELD_REF(_ftype,_fname)[0]),                  \
+      _fmax,                                                   \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fcount),           \
+      0 }
+
+#define T1_FIELD_NUM_ARRAY2( _ftype, _fname, _fmax )         \
+    { t1_field_integer,                                      \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),          \
+      sizeof(T1_FIELD_REF(_ftype,_fname)[0]),                \
+      _fmax,                                                 \
+      0, 0 }
+
+#define T1_FIELD_FIXED_ARRAY2( _ftype, _fname, _fmax )         \
+    { t1_field_fixed,                                          \
+      (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname),            \
+      sizeof(T1_FIELD_REF(_ftype,_fname)[0]),                  \
+      _fmax,                                                   \
+      0, 0 }
+
+
+
 /*************************************************************************
  *
  * <Struct> T1_Table
@@ -214,6 +299,32 @@
                            void*          object,
                            T1_Field_Rec*  field );
 #endif
+
+
+
+
+
+  LOCAL_DEF
+  void      T1_Skip_Spaces( T1_Parser*  parser );
+
+  LOCAL_DEF
+  void      T1_ToToken( T1_Parser*    parser,
+                        T1_Token_Rec* token );
+
+  LOCAL_DEF
+  T1_Error  T1_Load_Field( T1_Parser*           parser,
+                           const T1_Field_Rec*  field,
+                           void**               objects,
+                           T1_UInt              max_objects,
+                           T1_ULong*            pflags );
+
+  LOCAL_DEF
+  T1_Error  T1_Load_Field_Table( T1_Parser*           parser,
+                                 const T1_Field_Rec*  field,
+                                 void**               objects,
+                                 T1_UInt              max_objects,
+                                 T1_ULong*            pflags );
+
 
   LOCAL_DEF
   T1_Error  T1_New_Parser( T1_Parser*  parser,
--- a/src/type1z/t1tokens.h
+++ b/src/type1z/t1tokens.h
@@ -17,6 +17,52 @@
  *
  ******************************************************************/
 
+#undef  T1TYPE
+#define T1TYPE  T1_FontInfo
+
+  T1_FONTINFO_STRING( "version", version )
+  T1_FONTINFO_STRING( "Notice", notice )
+  T1_FONTINFO_STRING( "FullName", full_name )
+  T1_FONTINFO_STRING( "FamilyName", family_name )
+  T1_FONTINFO_STRING( "Weight", weight )
+
+  T1_FONTINFO_NUM( "ItalicAngle", italic_angle )
+  T1_FONTINFO_BOOL( "isFixedPitch", is_fixed_pitch )
+  T1_FONTINFO_NUM( "UnderlinePosition", underline_position )
+  T1_FONTINFO_NUM( "UnderlineThickness", underline_thickness )
+
+#undef  T1TYPE
+#define T1TYPE  T1_Private
+
+  T1_PRIVATE_NUM  ( "UniqueID", unique_id )
+  T1_PRIVATE_NUM  ( "lenIV", lenIV )
+  T1_PRIVATE_NUM  ( "LanguageGroup", language_group )
+  T1_PRIVATE_NUM  ( "password", password )
+  
+  T1_PRIVATE_FIXED( "BlueScale", blue_scale )
+  T1_PRIVATE_NUM  ( "BlueShift", blue_shift )
+  T1_PRIVATE_NUM  ( "BlueFuzz",  blue_fuzz )
+  
+  T1_PRIVATE_NUM_TABLE( "BlueValues", blue_values, 14, num_blues )
+  T1_PRIVATE_NUM_TABLE( "OtherBlues", other_blues, 10, num_other_blues )
+  T1_PRIVATE_NUM_TABLE( "FamilyBlues", family_blues, 14, num_family_blues )
+  T1_PRIVATE_NUM_TABLE( "FamilyOtherBlues", family_other_blues, 10, num_family_other_blues )
+
+  T1_PRIVATE_NUM_TABLE2( "StdHW", standard_width,  1 )
+  T1_PRIVATE_NUM_TABLE2( "StdVW", standard_height, 1 )
+  T1_PRIVATE_NUM_TABLE2( "MinFeature", min_feature, 2 )
+  
+  T1_PRIVATE_NUM_TABLE ( "StemSnapH", stem_snap_widths, 12, num_snap_widths )
+  T1_PRIVATE_NUM_TABLE ( "StemSnapV", stem_snap_heights, 12, num_snap_heights )
+
+#undef  T1TYPE
+#define T1TYPE  T1_Font
+
+  T1_TOPDICT_NUM( "PaintType", paint_type )
+  T1_TOPDICT_NUM( "FontType", font_type )
+  T1_TOPDICT_NUM( "StrokeWidth", stroke_width )
+
+#if 0
  /* define the font info dictionary parsing callbacks */
 #undef  FACE
 #define FACE  (face->type1.font_info)
@@ -75,5 +121,5 @@
    PARSE_INT( "StrokeWidth", stroke_width )
 
 #undef FACE
-
+#endif