shithub: freetype+ttf2subf

Download patch

ref: 1a380e02d1668d559a073d75200e3866d37b8e4d
parent: 4af3c4d7ee1de7d4e7591578092cac4f1a124d49
author: Werner Lemberg <[email protected]>
date: Fri Jul 14 14:28:08 EDT 2006

* freetype2/include/freetype/internal/psaux.h: New macros
IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT,
IS_PS_XDIGIT, and IS_PS_BASE85 (from freetype2/src/psaux/psconv.h).
(T1_FieldLocation): Add T1_FIELD_LOCATION_LOADER,
T1_FIELD_LOCATION_FACE, and T1_FIELD_LOCATION_BLEND.
(T1_DecoderRec): New fields `buildchar' and `face'.
(IS_PS_TOKEN): New macro.

* freetype2/include/freetype/internal/t1types.h (T1_FaceRec): New
fields `ndv_idx', `cdv_idx', and `len_buildchar'.

* freetype2/include/freetype/t1tables.h (PS_BlendRec): New fields
`default_design_vector' and `num_default_design_vector'.

* freetype2/src/psaux/psconv.h: Move macros IS_PS_NEWLINE,
IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT,
and IS_PS_BASE85 to freetype2/include/freetype/internal/psaux.h.

* freetype2/src/psaux/psobjs.c (ps_parser_to_token_array): Allow
`token' argument to be NULL if we want only to count the number of
tokens.
(ps_tocoordarray): Allow `coords' argument to be NULL if we just
want to skip the array.
(ps_tofixedarray): Allow `values' argument to be NULL if we just
want to skip the array.

* freetype2/src/psaux/t1decode.c (t1_decoder_parse_charstrings): Add
support for (partially commented out) othersubrs 19-25, 27, and 28.
(t1_decoder_init): Initialize new fields `face' and `buildchar'.
(t1_decoder_done): Release new field `buildchar'.

* freetype2/src/type1/t1load.c (parse_buildchar, parse_private): New
functions.
(t1_keywords): Register them.
(t1_allocate_blend): Updated.
(t1_load_keyword): Handle field types T1_FIELD_LOCATION_LOADER,
T1_FIELD_LOCATION_FACE and T1_FIELD_LOCATION_BLEND.
(parse_dict): Remove `keyword_flags' argument.
Use new macro IS_PS_TOKEN.
Changed function so that later PostScript definitions override
earlier ones.
(t1_init_loader): Initialize new field `keywords_encountered'.
(T1_Open_Face): Initialize new fields `ndv_idx', `cdv_idx', and
`len_buildchar'.
Remove `keywords_flags'.

* freetype2/src/type1/t1load.h (T1_LoaderRect): New field
`keywords_encountered'.
(T1_PRIVATE, T1_FONTDIR_AFTER_PRIVATE): New macros.

* freetype2/src/type1/t1tokens.h [!T1_CONFIG_OPTION_NO_MM_SUPPORT]:
New entries for parsing /NDV, /CDV, and /DesignVector.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2006-07-14  Jens Claudius  <[email protected]>
+
+	* freetype2/include/freetype/internal/psaux.h: New macros
+	IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT,
+	IS_PS_XDIGIT, and IS_PS_BASE85 (from freetype2/src/psaux/psconv.h).
+	(T1_FieldLocation): Add T1_FIELD_LOCATION_LOADER,
+	T1_FIELD_LOCATION_FACE, and T1_FIELD_LOCATION_BLEND.
+	(T1_DecoderRec): New fields `buildchar' and `face'.
+	(IS_PS_TOKEN): New macro.
+
+	* freetype2/include/freetype/internal/t1types.h (T1_FaceRec): New
+	fields `ndv_idx', `cdv_idx', and `len_buildchar'.
+
+	* freetype2/include/freetype/t1tables.h (PS_BlendRec): New fields
+	`default_design_vector' and `num_default_design_vector'.
+
+	* freetype2/src/psaux/psconv.h: Move macros IS_PS_NEWLINE,
+	IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT,
+	and IS_PS_BASE85 to freetype2/include/freetype/internal/psaux.h.
+
+	* freetype2/src/psaux/psobjs.c (ps_parser_to_token_array): Allow
+	`token' argument to be NULL if we want only to count the number of
+	tokens.
+	(ps_tocoordarray): Allow `coords' argument to be NULL if we just
+	want to skip the array.
+	(ps_tofixedarray): Allow `values' argument to be NULL if we just
+	want to skip the array.
+
+	* freetype2/src/psaux/t1decode.c (t1_decoder_parse_charstrings): Add
+	support for (partially commented out) othersubrs 19-25, 27, and 28.
+	(t1_decoder_init): Initialize new fields `face' and `buildchar'.
+	(t1_decoder_done): Release new field `buildchar'.
+
+	* freetype2/src/type1/t1load.c (parse_buildchar, parse_private): New
+	functions.
+	(t1_keywords): Register them.
+	(t1_allocate_blend): Updated.
+	(t1_load_keyword): Handle field types T1_FIELD_LOCATION_LOADER,
+	T1_FIELD_LOCATION_FACE and T1_FIELD_LOCATION_BLEND.
+	(parse_dict): Remove `keyword_flags' argument.
+	Use new macro IS_PS_TOKEN.
+	Changed function so that later PostScript definitions override
+	earlier ones.
+	(t1_init_loader): Initialize new field `keywords_encountered'.
+	(T1_Open_Face): Initialize new fields `ndv_idx', `cdv_idx', and
+	`len_buildchar'.
+	Remove `keywords_flags'.
+
+	* freetype2/src/type1/t1load.h (T1_LoaderRect): New field
+	`keywords_encountered'.
+	(T1_PRIVATE, T1_FONTDIR_AFTER_PRIVATE): New macros.
+
+	* freetype2/src/type1/t1tokens.h [!T1_CONFIG_OPTION_NO_MM_SUPPORT]:
+	New entries for parsing /NDV, /CDV, and /DesignVector.
+
 2006-07-07  Werner Lemberg  <[email protected]>
 
 	Add many checks to protect against malformed PCF files.
--- a/include/freetype/internal/psaux.h
+++ b/include/freetype/internal/psaux.h
@@ -199,6 +199,9 @@
     T1_FIELD_LOCATION_FONT_INFO,
     T1_FIELD_LOCATION_PRIVATE,
     T1_FIELD_LOCATION_BBOX,
+    T1_FIELD_LOCATION_LOADER,
+    T1_FIELD_LOCATION_FACE,
+    T1_FIELD_LOCATION_BLEND,
 
     /* do not remove */
     T1_FIELD_LOCATION_MAX
@@ -683,6 +686,10 @@
     T1_Decoder_Callback  parse_callback;
     T1_Decoder_FuncsRec  funcs;
 
+    FT_Int*              buildchar;
+
+    T1_Face              face;
+
   } T1_DecoderRec;
 
 
@@ -712,8 +719,10 @@
 
   } AFM_Parser_FuncsRec;
 
+
   typedef struct AFM_StreamRec_*  AFM_Stream;
 
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -800,6 +809,57 @@
 
   /* backwards-compatible type definition */
   typedef PSAux_ServiceRec   PSAux_Interface;
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                 Some convenience functions                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define IS_PS_NEWLINE( ch ) \
+  ( (ch) == '\r' ||         \
+    (ch) == '\n' )
+
+#define IS_PS_SPACE( ch )  \
+  ( (ch) == ' '         || \
+    IS_PS_NEWLINE( ch ) || \
+    (ch) == '\t'        || \
+    (ch) == '\f'        || \
+    (ch) == '\0' )
+
+#define IS_PS_SPECIAL( ch )       \
+  ( (ch) == '/'                || \
+    (ch) == '(' || (ch) == ')' || \
+    (ch) == '<' || (ch) == '>' || \
+    (ch) == '[' || (ch) == ']' || \
+    (ch) == '{' || (ch) == '}' || \
+    (ch) == '%'                )
+
+#define IS_PS_DELIM( ch )  \
+  ( IS_PS_SPACE( ch )   || \
+    IS_PS_SPECIAL( ch ) )
+
+#define IS_PS_DIGIT( ch )        \
+  ( (ch) >= '0' && (ch) <= '9' )
+
+#define IS_PS_XDIGIT( ch )            \
+  ( IS_PS_DIGIT( ch )              || \
+    ( (ch) >= 'A' && (ch) <= 'F' ) || \
+    ( (ch) >= 'a' && (ch) <= 'f' ) )
+
+#define IS_PS_BASE85( ch )       \
+  ( (ch) >= '!' && (ch) <= 'u' )
+
+#define IS_PS_TOKEN( cur, limit, token )                                \
+  ( (char)(cur)[0] == (token)[0]                                     && \
+    ( (cur) + sizeof ( (token) ) == (limit) ||                          \
+      ( (cur) + sizeof( (token) ) < (limit)          &&                 \
+        IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) )             && \
+    ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 )
+
 
 FT_END_HEADER
 
--- a/include/freetype/internal/t1types.h
+++ b/include/freetype/internal/t1types.h
@@ -208,6 +208,16 @@
     /* support for Multiple Masters fonts */
     PS_Blend        blend;
 
+    /* undocumented, optional: indices of subroutines that express      */
+    /* the NormalizeDesignVector and the ConvertDesignVector procedure, */
+    /* respectively, as Type 2 charstrings; -1 if keywords not present  */
+    FT_Int           ndv_idx;
+    FT_Int           cdv_idx;
+
+    /* undocumented, optional: has the same meaning as len_buildchar */
+    /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25    */
+    FT_UInt          len_buildchar;
+
     /* since version 2.1 - interface to PostScript hinter */
     const void*     pshinter;
 
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -5,7 +5,7 @@
 /*    Basic Type 1/Type 2 tables definitions and interface (specification  */
 /*    only).                                                               */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2006 by                         */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -255,6 +255,15 @@
     FT_ULong         blend_bitflags;
 
     FT_BBox*         bboxes    [T1_MAX_MM_DESIGNS + 1];
+
+    /* since 2.2.2 */
+
+    /* undocumented, optional: the default design instance;   */
+    /* corresponds to default_weight_vector --                */
+    /* num_default_design_vector == 0 means it is not present */
+    /* in the font and associated metrics files               */
+    FT_UInt          default_design_vector[T1_MAX_MM_DESIGNS];
+    FT_UInt          num_default_design_vector;
 
   } PS_BlendRec, *PS_Blend;
 
--- a/src/psaux/psconv.h
+++ b/src/psaux/psconv.h
@@ -63,42 +63,6 @@
                        FT_UShort*  seed );
 
 
-#define IS_PS_NEWLINE( ch ) \
-  ( ( ch ) == '\r' ||       \
-    ( ch ) == '\n' )
-
-#define IS_PS_SPACE( ch )  \
-  ( ( ch ) == ' '       || \
-    IS_PS_NEWLINE( ch ) || \
-    ( ch ) == '\t'      || \
-    ( ch ) == '\f'      || \
-    ( ch ) == '\0' )
-
-#define IS_PS_SPECIAL( ch ) \
-  ( ( ch ) == '/' ||        \
-    ( ch ) == '(' ||        \
-    ( ch ) == ')' ||        \
-    ( ch ) == '<' ||        \
-    ( ch ) == '>' ||        \
-    ( ch ) == '[' ||        \
-    ( ch ) == ']' ||        \
-    ( ch ) == '{' ||        \
-    ( ch ) == '}' ||        \
-    ( ch ) == '%' )
-
-#define IS_PS_DELIM( ch )  \
-  ( IS_PS_SPACE( ch )   || \
-    IS_PS_SPECIAL( ch ) )
-
-#define IS_PS_DIGIT( ch )  ( ( ch ) >= '0' && ( ch ) <= '9' )
-
-#define IS_PS_XDIGIT( ch )                \
-  ( IS_PS_DIGIT( ( ch ) )              || \
-    ( ( ch ) >= 'A' && ( ch ) <= 'F' ) || \
-    ( ( ch ) >= 'a' && ( ch ) <= 'f' ) )
-
-#define IS_PS_BASE85( ch ) ( ( ch ) >= '!' && ( ch ) <= 'u' )
-
 FT_END_HEADER
 
 #endif /* __PSCONV_H__ */
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -698,6 +698,9 @@
   }
 
 
+  /* NB: `tokens' can be NULL if we only want to count */
+  /* the number of array elements                      */
+
   FT_LOCAL_DEF( void )
   ps_parser_to_token_array( PS_Parser  parser,
                             T1_Token   tokens,
@@ -733,7 +736,7 @@
         if ( !token.type )
           break;
 
-        if ( cur < limit )
+        if ( tokens != NULL && cur < limit )
           *cur = token;
 
         cur++;
@@ -748,6 +751,8 @@
 
 
   /* first character must be a delimiter or a part of a number */
+  /* NB: `coords' can be NULL if we just want to skip the      */
+  /*     array; in this case we ignore `max_coords'            */
 
   static FT_Int
   ps_tocoordarray( FT_Byte*  *acur,
@@ -780,21 +785,26 @@
     /* now, read the coordinates */
     while ( cur < limit )
     {
+      FT_Short dummy;
+
+
       /* skip whitespace in front of data */
       skip_spaces( &cur, limit );
       if ( cur >= limit )
         goto Exit;
 
-      if ( count >= max_coords )
+      if ( coords != NULL && count >= max_coords )
         break;
 
-      if ( c == ender )
+      if ( *cur == ender )
       {
         cur++;
         break;
       }
 
-      coords[count] =
+      /* call PS_Conv_ToFixed() even if coords == NULL */
+      /* to properly parse number at `cur'             */
+      *( coords != NULL ? &coords[count] : &dummy ) =
         (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
       count++;
 
@@ -809,6 +819,8 @@
 
 
   /* first character must be a delimiter or a part of a number */
+  /* NB: `values' can be NULL if we just want to skip the      */
+  /*     array in this case we ignore `max_values'             */
 
   static FT_Int
   ps_tofixedarray( FT_Byte*  *acur,
@@ -842,21 +854,27 @@
     /* now, read the values */
     while ( cur < limit )
     {
+      FT_Fixed dummy;
+
+
       /* skip whitespace in front of data */
       skip_spaces( &cur, limit );
       if ( cur >= limit )
         goto Exit;
 
-      if ( count >= max_values )
+      if ( values != NULL && count >= max_values )
         break;
 
-      if ( c == ender )
+      if ( *cur == ender )
       {
         cur++;
         break;
       }
 
-      values[count] = PS_Conv_ToFixed( &cur, limit, power_ten );
+      /* call PS_Conv_ToFixed() even if coords == NULL */
+      /* to properly parse number at `cur'             */
+      *( values != NULL ? &values[count] : &dummy ) =
+        PS_Conv_ToFixed( &cur, limit, power_ten );
       count++;
 
       if ( !ender )
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -348,6 +348,14 @@
 
     hinter = (T1_Hints_Funcs)builder->hints_funcs;
 
+    /* a font that reads BuildCharArray without setting */
+    /* its values first is buggy, but ...               */
+    if ( decoder->face->len_buildchar > 0 )
+      memset( &decoder->buildchar[0],
+              0,
+              sizeof( decoder->buildchar[0] ) *
+                decoder->face->len_buildchar );
+
     FT_TRACE4(( "\nStart charstring\n" ));
 
     zone->base           = charstring_base;
@@ -582,12 +590,9 @@
         subr_no = (FT_Int)top[1];
         arg_cnt = (FT_Int)top[0];
 
-        if ( arg_cnt > top - decoder->stack )
-          goto Stack_Underflow;
-
         /***********************************************************/
         /*                                                         */
-        /* remove all operands to callsubr from the stack          */
+        /* remove all operands to callothersubr from the stack     */
         /*                                                         */
         /* for handled othersubrs, where we know the number of     */
         /* arguments, we increase the stack by the value of        */
@@ -596,11 +601,30 @@
         /* for unhandled othersubrs the following pops adjust the  */
         /* stack pointer as necessary                              */
 
+        if ( arg_cnt > top - decoder->stack )
+          goto Stack_Underflow;
+
         top -= arg_cnt;
 
         known_othersubr_result_cnt   = 0;
         unknown_othersubr_result_cnt = 0;
 
+        /* XXX TODO: The checks to `arg_count == <whatever>'       */
+        /* might not be correct; an othersubr expects a certain    */
+        /* number of operands on the PostScript stack (as opposed  */
+        /* to the T1 stack) but it doesn't have to put them there  */
+        /* by itself; previous othersubrs might have left the      */
+        /* operands there if they were not followed by an          */
+        /* appropriate number of pops                              */
+        /*                                                         */
+        /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
+        /* accept a font that contains charstrings like            */
+        /*                                                         */
+        /*     100 200 2 20 callothersubr                          */
+        /*     300 1 20 callothersubr pop                          */
+        /*                                                         */
+        /* Perhaps this is the reason why BuildCharArray exists.   */
+
         switch ( subr_no )
         {
         case 1:                     /* start flex feature */
@@ -726,6 +750,158 @@
             break;
           }
 
+#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
+
+          /* We cannot yet enable these since currently  */
+          /* our T1 stack stores integers which lack the */
+          /* precision to express the values             */
+
+        case 19:
+          /* <idx> 1 19 callothersubr                             */
+          /* => replace elements starting from index cvi( <idx> ) */
+          /*    of BuildCharArray with WeightVector               */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+
+            if ( arg_cnt != 1 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[0];
+
+            if ( idx < 0                                                 ||
+                 idx + blend->num_designs > decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            memcpy( &decoder->buildchar[idx],
+                    blend->weight_vector,
+                    blend->num_designs *
+                      sizeof( blend->weight_vector[ 0 ] ) );
+          }
+          break;
+
+        case 20:
+          /* <arg1> <arg2> 2 20 callothersubr pop   */
+          /* ==> push <arg1> + <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] += top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 21:
+          /* <arg1> <arg2> 2 21 callothersubr pop   */
+          /* ==> push <arg1> - <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] -= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 22:
+          /* <arg1> <arg2> 2 22 callothersubr pop   */
+          /* ==> push <arg1> * <arg2> onto T1 stack */
+          if ( arg_cnt != 2 )
+            goto Unexpected_OtherSubr;
+
+          top[0] *= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+        case 23:
+          /* <arg1> <arg2> 2 23 callothersubr pop   */
+          /* ==> push <arg1> / <arg2> onto T1 stack */
+          if ( arg_cnt != 2 || top[1] == 0 )
+            goto Unexpected_OtherSubr;
+
+          top[0] /= top[1]; /* XXX (over|under)flow */
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */
+
+        case 24:
+          /* <val> <idx> 2 24 callothersubr              */
+          /* => set BuildCharArray[cvi( <idx> )] = <val> */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+            if ( arg_cnt != 2 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[1];
+
+            if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            decoder->buildchar[idx] = top[0];
+          }
+          break;
+
+        case 25:
+          /* <idx> 1 25 callothersubr pop       */
+          /* => push BuildCharArray[cvi( idx )] */
+          /*    onto T1 stack                   */
+          {
+            FT_Int    idx;
+            PS_Blend  blend = decoder->blend;
+
+            if ( arg_cnt != 1 || blend == NULL )
+              goto Unexpected_OtherSubr;
+
+            idx = top[0];
+
+            if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar )
+              goto Unexpected_OtherSubr;
+
+            top[0] = decoder->buildchar[idx];
+          }
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#if 0
+        case 26:
+          /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
+          /*                      leave mark on T1 stack                    */
+          /* <val> <idx>      ==> set BuildCharArray[cvi( <idx> )] = <val>  */
+          XXX who has left his mark on the (PostScript) stack ?;
+          break;
+#endif
+
+        case 27:
+          /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
+          /* ==> push <res1> onto T1 stack if <val1> <= <val2>,  */
+          /*     otherwise push <res2>                          */
+          if ( arg_cnt != 4 )
+            goto Unexpected_OtherSubr;
+
+          if ( top[2] > top[3] )
+            top[0] = top[1];
+
+          known_othersubr_result_cnt = 1;
+          break;
+
+#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
+        case 28:
+          /* 0 28 callothersubr pop                               */
+          /* => push random value from interval [0, 1) onto stack */
+          if ( arg_cnt != 0 )
+            goto Unexpected_OtherSubr;
+
+          top[0] = FT_rand();
+          known_othersubr_result_cnt = 1;
+          break;
+#endif
+
         default:
           FT_ERROR(( "t1_decoder_parse_charstrings: "
                      "unknown othersubr [%d %d], wish me luck!\n",
@@ -805,8 +981,30 @@
           /* add current outline to the glyph slot */
           FT_GlyphLoader_Add( builder->loader );
 
+          FT_TRACE4(( "\n" ));
+
+          /* the compiler should optimize away this empty loop but ... */
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+          if ( decoder->face->len_buildchar > 0 )
+          {
+            FT_UInt  i;
+
+
+            FT_TRACE4(( "BuildCharArray = [ " ));
+
+            for ( i = 0; i < decoder->face->len_buildchar; ++i )
+              FT_TRACE4(( "%d ", decoder->buildchar[ i ] ));
+
+            FT_TRACE4(( "]\n" ));
+          }
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+          FT_TRACE4(( "\n" ));
+
           /* return now! */
-          FT_TRACE4(( "\n\n" ));
           return PSaux_Err_Ok;
 
         case op_hsbw:
@@ -1225,6 +1423,10 @@
                    FT_Render_Mode       hint_mode,
                    T1_Decoder_Callback  parse_callback )
   {
+    FT_Error   error;
+    FT_Memory  memory = face->memory;
+
+
     FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
 
     /* retrieve PSNames interface from list of current modules */
@@ -1243,6 +1445,18 @@
       decoder->psnames = psnames;
     }
 
+    decoder->face = (T1_Face) face;
+
+    if ( decoder->face->len_buildchar > 0 )
+    {
+      if ( FT_NEW_ARRAY( decoder->buildchar, decoder->face->len_buildchar ) )
+      {
+        FT_ERROR(( "t1_decoder_init: " ));
+        FT_ERROR(( "cannot allocate memory for BuildCharArray\n" ));
+        return error;
+      }
+    }
+
     t1_builder_init( &decoder->builder, face, size, slot, hinting );
 
     decoder->num_glyphs     = (FT_UInt)face->num_glyphs;
@@ -1261,7 +1475,12 @@
   FT_LOCAL_DEF( void )
   t1_decoder_done( T1_Decoder  decoder )
   {
+    FT_Memory  memory = decoder->face->root.memory;
+
+
     t1_builder_done( &decoder->builder );
+
+    FT_FREE( decoder->buildchar );
   }
 
 
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -107,6 +107,8 @@
       if ( FT_NEW( blend ) )
         goto Exit;
 
+      blend->num_default_design_vector = 0;
+
       face->blend = blend;
     }
 
@@ -877,6 +879,18 @@
   }
 
 
+  /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
+  /* we're only interested in the number of array elements */
+  static void
+  parse_buildchar( T1_Face    face,
+                   T1_Loader  loader )
+  {
+    face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
+
+    return;
+  }
+
+
 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
 
 
@@ -950,6 +964,26 @@
       }
       break;
 
+    case T1_FIELD_LOCATION_LOADER:
+      dummy_object = loader;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+
+    case T1_FIELD_LOCATION_FACE:
+      dummy_object = face;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    case T1_FIELD_LOCATION_BLEND:
+      dummy_object = face->blend;
+      objects      = &dummy_object;
+      max_objects  = 0;
+      break;
+#endif
+
     default:
       dummy_object = &face->type1;
       objects      = &dummy_object;
@@ -969,6 +1003,16 @@
   }
 
 
+  static void
+  parse_private( T1_Face    face,
+                 T1_Loader  loader )
+  {
+    FT_UNUSED( face );
+
+    loader->keywords_encountered |= T1_PRIVATE;
+  }
+
+
   static int
   is_space( FT_Byte  c )
   {
@@ -1681,6 +1725,7 @@
     T1_FIELD_CALLBACK( "Encoding", parse_encoding )
     T1_FIELD_CALLBACK( "Subrs", parse_subrs )
     T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+    T1_FIELD_CALLBACK( "Private", parse_private )
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
     T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
@@ -1687,6 +1732,7 @@
     T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
     T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
     T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+    T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar )
 #endif
 
     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
@@ -1701,8 +1747,7 @@
   parse_dict( T1_Face    face,
               T1_Loader  loader,
               FT_Byte*   base,
-              FT_Long    size,
-              FT_Byte*   keyword_flags )
+              FT_Long    size )
   {
     T1_Parser  parser = &loader->parser;
     FT_Byte   *limit, *start_binary = NULL;
@@ -1724,31 +1769,23 @@
 
       cur = parser->root.cursor;
 
-      /* cur[5] must be a token delimiter;                 */
-      /* eexec encryption is optional, so look for `eexec' */
-      if ( *cur == 'e' && cur + 5 < limit            &&
-           ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
+      /* look for `eexec' */
+      if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
         break;
 
-      /* cur[9] must be a token delimiter;                 */
       /* look for `closefile' which ends the eexec section */
-      else if ( *cur == 'c' && cur + 9 < limit                &&
-                ft_strncmp( (char*)cur, "closefile", 9 ) == 0 )
+      else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
         break;
 
-#ifdef TO_BE_DONE
       /* in a synthetic font the base font starts after a           */
       /* `FontDictionary' token that is placed after a Private dict */
-
-      /* cur[13] must be a token delimiter */
-      else if ( *cur == 'F' && cur + 13 < limit                    &&
-                ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+      else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
       {
-        if ( loader->private_encountered )
-          loader->fontdir_after_private = 1;
+        if ( loader->keywords_encountered & T1_PRIVATE )
+          loader->keywords_encountered |=
+            T1_FONTDIR_AFTER_PRIVATE;
         parser->root.cursor += 13;
       }
-#endif
 
       /* check whether we have an integer */
       else if ( ft_isdigit( *cur ) )
@@ -1807,8 +1844,7 @@
         if ( len > 0 && len < 22 && parser->root.cursor < limit )
         {
           /* now compare the immediate name to the keyword table */
-          T1_Field  keyword      = (T1_Field)t1_keywords;
-          FT_Byte*  keyword_flag = keyword_flags;
+          T1_Field  keyword = (T1_Field)t1_keywords;
 
 
           for (;;)
@@ -1824,21 +1860,28 @@
                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
                  ft_memcmp( cur, name, len ) == 0                   )
             {
-              /* We found it -- run the parsing callback! */
-              /* We only record the first instance of any */
-              /* field to deal adequately with synthetic  */
-              /* fonts; /Subrs and /CharStrings are       */
-              /* handled specially.                       */
-              if ( keyword_flag[0] == 0                               ||
-                   ft_strcmp( (const char*)name, "Subrs" ) == 0       ||
-                   ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
+              /* We found it -- run the parsing callback!     */
+              /* We record every instance of every field      */
+              /* (until we reach the base font of a           */
+              /* synthetic font) to deal adequately with      */
+              /* multiple master fonts; this is also          */
+              /* necessary because later PostScript           */
+              /* definitions override earlier ones            */
+
+              /* Once we encounter `FontDirectory' after      */
+              /* `/Private', we know that this is a synthetic */
+              /* font; except for `/CharStrings' we are not   */
+              /* interested in anything that follows this     */
+              /* `FontDirectory'                              */
+
+              if ( !( loader->keywords_encountered                &
+                      T1_FONTDIR_AFTER_PRIVATE ) ||
+                   ft_strcmp((const char*)name, "CharStrings") == 0 )
               {
                 parser->root.error = t1_load_keyword( face,
                                                       loader,
                                                       keyword );
-                if ( parser->root.error == T1_Err_Ok )
-                  keyword_flag[0] = 1;
-                else
+                if ( parser->root.error != T1_Err_Ok )
                 {
                   if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore )
                     parser->root.error = T1_Err_Ok;
@@ -1850,7 +1893,6 @@
             }
 
             keyword++;
-            keyword_flag++;
           }
         }
 
@@ -1883,12 +1925,13 @@
     loader->num_chars  = 0;
 
     /* initialize the tables -- simply set their `init' field to 0 */
-    loader->encoding_table.init = 0;
-    loader->charstrings.init    = 0;
-    loader->glyph_names.init    = 0;
-    loader->subrs.init          = 0;
-    loader->swap_table.init     = 0;
-    loader->fontdata            = 0;
+    loader->encoding_table.init  = 0;
+    loader->charstrings.init     = 0;
+    loader->glyph_names.init     = 0;
+    loader->subrs.init           = 0;
+    loader->swap_table.init      = 0;
+    loader->fontdata             = 0;
+    loader->keywords_encountered = 0;
   }
 
 
@@ -1918,7 +1961,6 @@
     T1_Font        type1 = &face->type1;
     PS_Private     priv  = &type1->private_dict;
     FT_Error       error;
-    FT_Byte        keyword_flags[T1_FIELD_COUNT];
 
     PSAux_Service  psaux = (PSAux_Service)face->psaux;
 
@@ -1926,6 +1968,10 @@
     t1_init_loader( &loader, face );
 
     /* default values */
+    face->ndv_idx          = -1;
+    face->cdv_idx          = -1;
+    face->len_buildchar    = 0;
+
     priv->blue_shift       = 7;
     priv->blue_fuzz        = 1;
     priv->lenIV            = 4;
@@ -1940,16 +1986,8 @@
     if ( error )
       goto Exit;
 
-    {
-      FT_UInt  n;
-
-
-      for ( n = 0; n < T1_FIELD_COUNT; n++ )
-        keyword_flags[n] = 0;
-    }
-
-    error = parse_dict( face, &loader, parser->base_dict, parser->base_len,
-                        keyword_flags );
+    error = parse_dict( face, &loader,
+                        parser->base_dict, parser->base_len );
     if ( error )
       goto Exit;
 
@@ -1957,9 +1995,8 @@
     if ( error )
       goto Exit;
 
-    error = parse_dict( face, &loader, parser->private_dict,
-                        parser->private_len,
-                        keyword_flags );
+    error = parse_dict( face, &loader,
+                        parser->private_dict, parser->private_len );
     if ( error )
       goto Exit;
 
@@ -1967,6 +2004,19 @@
     priv->num_blue_values &= ~1;
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+    if ( face->blend                                                     &&
+         face->blend->num_default_design_vector != 0                     &&
+         face->blend->num_default_design_vector != face->blend->num_axis )
+    {
+      /* we don't use it currently so just warn, reset, and ignore */
+      FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
+                 "while there are %u axes.\n",
+                 face->blend->num_default_design_vector,
+                 face->blend->num_axis ));
+
+      face->blend->num_default_design_vector = 0;
+    }
 
     /* the following can happen for MM instances; we then treat the */
     /* font as a normal PS font                                     */
--- a/src/type1/t1load.h
+++ b/src/type1/t1load.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Type 1 font loader (specification).                                  */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2004 by                                     */
+/*  Copyright 1996-2001, 2002, 2004, 2006 by                               */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -48,7 +48,16 @@
     PS_TableRec   subrs;
     FT_Bool       fontdata;
 
+    FT_UInt       keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */
+
   } T1_LoaderRec, *T1_Loader;
+
+
+  /* treatment of some keywords differs depending on whether */
+  /* they preceed or follow certain other keywords           */
+
+#define T1_PRIVATE                ( 1 << 0 )
+#define T1_FONTDIR_AFTER_PRIVATE  ( 1 << 1 )
 
 
   FT_LOCAL( FT_Error )
--- a/src/type1/t1tokens.h
+++ b/src/type1/t1tokens.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Type 1 tokenizer (specification).                                    */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2006 by                         */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -73,6 +73,7 @@
   T1_FIELD_NUM  ( "FontType", font_type )
   T1_FIELD_FIXED( "StrokeWidth", stroke_width )
 
+
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  FT_BBox
 #undef  T1CODE
@@ -79,6 +80,28 @@
 #define T1CODE        T1_FIELD_LOCATION_BBOX
 
   T1_FIELD_BBOX("FontBBox", xMin )
+
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  T1_FaceRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FACE
+
+  T1_FIELD_NUM      ( "NDV", ndv_idx )
+  T1_FIELD_NUM      ( "CDV", cdv_idx )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_BlendRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_BLEND
+
+  T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, T1_MAX_MM_DESIGNS )
+
+
+#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
 
 
 /* END */