< prev index next >

src/java.desktop/share/native/libfreetype/src/type1/t1load.c

Print this page

        

@@ -1,65 +1,65 @@
-/***************************************************************************/
-/*                                                                         */
-/*  t1load.c                                                               */
-/*                                                                         */
-/*    Type 1 font loader (body).                                           */
-/*                                                                         */
-/*  Copyright 1996-2018 by                                                 */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/***************************************************************************/
+/****************************************************************************
+ *
+ * t1load.c
+ *
+ *   Type 1 font loader (body).
+ *
+ * Copyright (C) 1996-2019 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
-  /* old loader has several problems: it is slow, complex, difficult to    */
-  /* maintain, and contains incredible hacks to make it accept some        */
-  /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
-  /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
-  /*                                                                       */
-  /* This version is much simpler, much faster and also easier to read and */
-  /* maintain by a great order of magnitude.  The idea behind it is to     */
-  /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
-  /* a Postscript-like interpreter) but rather to perform simple pattern   */
-  /* matching.                                                             */
-  /*                                                                       */
-  /* Indeed, nearly all data definitions follow a simple pattern like      */
-  /*                                                                       */
-  /*  ... /Field <data> ...                                                */
-  /*                                                                       */
-  /* where <data> can be a number, a boolean, a string, or an array of     */
-  /* numbers.  There are a few exceptions, namely the encoding, font name, */
-  /* charstrings, and subrs; they are handled with a special pattern       */
-  /* matching routine.                                                     */
-  /*                                                                       */
-  /* All other common cases are handled very simply.  The matching rules   */
-  /* are defined in the file `t1tokens.h' through the use of several       */
-  /* macros calls PARSE_XXX.  This file is included twice here; the first  */
-  /* time to generate parsing callback functions, the second time to       */
-  /* generate a table of keywords (with pointers to the associated         */
-  /* callback functions).                                                  */
-  /*                                                                       */
-  /* The function `parse_dict' simply scans *linearly* a given dictionary  */
-  /* (either the top-level or private one) and calls the appropriate       */
-  /* callback when it encounters an immediate keyword.                     */
-  /*                                                                       */
-  /* This is by far the fastest way one can find to parse and read all     */
-  /* data.                                                                 */
-  /*                                                                       */
-  /* This led to tremendous code size reduction.  Note that later, the     */
-  /* glyph loader will also be _greatly_ simplified, and the automatic     */
-  /* hinter will replace the clumsy `t1hinter'.                            */
-  /*                                                                       */
-  /*************************************************************************/
+  /**************************************************************************
+   *
+   * This is the new and improved Type 1 data loader for FreeType 2.  The
+   * old loader has several problems: it is slow, complex, difficult to
+   * maintain, and contains incredible hacks to make it accept some
+   * ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of
+   * the Type 1 fonts on my machine still aren't loaded correctly by it.
+   *
+   * This version is much simpler, much faster and also easier to read and
+   * maintain by a great order of magnitude.  The idea behind it is to
+   * _not_ try to read the Type 1 token stream with a state machine (i.e.
+   * a Postscript-like interpreter) but rather to perform simple pattern
+   * matching.
+   *
+   * Indeed, nearly all data definitions follow a simple pattern like
+   *
+   * ... /Field <data> ...
+   *
+   * where <data> can be a number, a boolean, a string, or an array of
+   * numbers.  There are a few exceptions, namely the encoding, font name,
+   * charstrings, and subrs; they are handled with a special pattern
+   * matching routine.
+   *
+   * All other common cases are handled very simply.  The matching rules
+   * are defined in the file `t1tokens.h' through the use of several
+   * macros calls PARSE_XXX.  This file is included twice here; the first
+   * time to generate parsing callback functions, the second time to
+   * generate a table of keywords (with pointers to the associated
+   * callback functions).
+   *
+   * The function `parse_dict' simply scans *linearly* a given dictionary
+   * (either the top-level or private one) and calls the appropriate
+   * callback when it encounters an immediate keyword.
+   *
+   * This is by far the fastest way one can find to parse and read all
+   * data.
+   *
+   * This led to tremendous code size reduction.  Note that later, the
+   * glyph loader will also be _greatly_ simplified, and the automatic
+   * hinter will replace the clumsy `t1hinter'.
+   *
+   */
 
 
 #include <ft2build.h>
 #include FT_INTERNAL_DEBUG_H
 #include FT_CONFIG_CONFIG_H

@@ -71,24 +71,24 @@
 #include "t1load.h"
 #include "t1errors.h"
 
 
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
-#define IS_INCREMENTAL  (FT_Bool)( face->root.internal->incremental_interface != 0 )
+#define IS_INCREMENTAL  FT_BOOL( face->root.internal->incremental_interface )
 #else
 #define IS_INCREMENTAL  0
 #endif
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
-  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
-  /* messages during execution.                                            */
-  /*                                                                       */
+  /**************************************************************************
+   *
+   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
+   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+   * messages during execution.
+   */
 #undef  FT_COMPONENT
-#define FT_COMPONENT  trace_t1load
+#define FT_COMPONENT  t1load
 
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
 
 

@@ -220,15 +220,15 @@
 
     return error;
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Given a normalized (blend) coordinate, figure out the design          */
-  /* coordinate appropriate for that value.                                */
-  /*                                                                       */
+  /**************************************************************************
+   *
+   * Given a normalized (blend) coordinate, figure out the design
+   * coordinate appropriate for that value.
+   */
   static FT_Fixed
   mm_axis_unmap( PS_DesignMap  axismap,
                  FT_Fixed      ncv )
   {
     int  j;

@@ -249,15 +249,15 @@
 
     return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Given a vector of weights, one for each design, figure out the        */
-  /* normalized axis coordinates which gave rise to those weights.         */
-  /*                                                                       */
+  /**************************************************************************
+   *
+   * Given a vector of weights, one for each design, figure out the
+   * normalized axis coordinates which gave rise to those weights.
+   */
   static void
   mm_weights_unmap( FT_Fixed*  weights,
                     FT_Fixed*  axiscoords,
                     FT_UInt    axis_count )
   {

@@ -291,15 +291,15 @@
                         weights[11] + weights[10] + weights[9] + weights[8];
     }
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Just a wrapper around T1_Get_Multi_Master to support the different    */
-  /*  arguments needed by the GX var distortable fonts.                    */
-  /*                                                                       */
+  /**************************************************************************
+   *
+   * Just a wrapper around T1_Get_Multi_Master to support the different
+   * arguments needed by the GX var distortable fonts.
+   */
   FT_LOCAL_DEF( FT_Error )
   T1_Get_MM_Var( T1_Face      face,
                  FT_MM_Var*  *master )
   {
     FT_Memory        memory = face->root.memory;

@@ -346,20 +346,17 @@
         mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
       else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
         mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
     }
 
-    if ( blend->num_designs == ( 1U << blend->num_axis ) )
-    {
       mm_weights_unmap( blend->default_weight_vector,
                         axiscoords,
                         blend->num_axis );
 
       for ( i = 0; i < mmaster.num_axis; i++ )
         mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
                                             axiscoords[i] );
-    }
 
     *master = mmvar;
 
   Exit:
     return error;

@@ -385,28 +382,35 @@
 
     /* recompute the weight vector from the blend coordinates */
     for ( n = 0; n < blend->num_designs; n++ )
     {
       FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
+      FT_Fixed  factor;
 
 
       for ( m = 0; m < blend->num_axis; m++ )
       {
-        FT_Fixed  factor;
-
-
-        /* get current blend axis position;                  */
         /* use a default value if we don't have a coordinate */
-        factor = m < num_coords ? coords[m] : 0x8000;
-        if ( factor < 0 )
-          factor = 0;
-        if ( factor > 0x10000L )
-          factor = 0x10000L;
+        if ( m >= num_coords )
+        {
+          result >>= 1;
+          continue;
+        }
 
+        /* get current blend axis position */
+        factor = coords[m];
         if ( ( n & ( 1 << m ) ) == 0 )
           factor = 0x10000L - factor;
 
+        if ( factor <= 0 )
+        {
+          result = 0;
+          break;
+        }
+        else if ( factor >= 0x10000L )
+          continue;
+
         result = FT_MulFix( result, factor );
       }
 
       if ( blend->weight_vector[n] != result )
       {

@@ -475,10 +479,79 @@
     return FT_Err_Ok;
   }
 
 
   FT_LOCAL_DEF( FT_Error )
+  T1_Set_MM_WeightVector( T1_Face    face,
+                          FT_UInt    len,
+                          FT_Fixed*  weightvector )
+  {
+    PS_Blend  blend = face->blend;
+    FT_UInt   i, n;
+
+
+    if ( !blend )
+     return FT_THROW( Invalid_Argument );
+
+    if ( !len && !weightvector )
+    {
+      for ( i = 0; i < blend->num_designs; i++ )
+        blend->weight_vector[i] = blend->default_weight_vector[i];
+    }
+    else
+    {
+      if ( !weightvector )
+        return FT_THROW( Invalid_Argument );
+
+      n = len < blend->num_designs ? len : blend->num_designs;
+
+      for ( i = 0; i < n; i++ )
+        blend->weight_vector[i] = weightvector[i];
+
+      for ( ; i < blend->num_designs; i++ )
+        blend->weight_vector[i] = (FT_Fixed)0;
+
+      if ( len )
+        face->root.face_flags |= FT_FACE_FLAG_VARIATION;
+      else
+        face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
+    }
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Get_MM_WeightVector( T1_Face    face,
+                          FT_UInt*   len,
+                          FT_Fixed*  weightvector )
+  {
+    PS_Blend  blend = face->blend;
+    FT_UInt   i;
+
+
+    if ( !blend )
+      return FT_THROW( Invalid_Argument );
+
+    if ( *len < blend->num_designs )
+    {
+      *len = blend->num_designs;
+      return FT_THROW( Invalid_Argument );
+    }
+
+    for ( i = 0; i < blend->num_designs; i++ )
+      weightvector[i] = blend->weight_vector[i];
+    for ( ; i < *len; i++ )
+      weightvector[i] = (FT_Fixed)0;
+
+    *len = blend->num_designs;
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
   T1_Set_MM_Design( T1_Face   face,
                     FT_UInt   num_coords,
                     FT_Long*  coords )
   {
     FT_Error  error;

@@ -571,15 +644,15 @@
 
     return T1_Set_MM_Blend( face, 0, NULL );
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Just a wrapper around T1_Set_MM_Design to support the different       */
-  /* arguments needed by the GX var distortable fonts.                     */
-  /*                                                                       */
+  /**************************************************************************
+   *
+   * Just a wrapper around T1_Set_MM_Design to support the different
+   * arguments needed by the GX var distortable fonts.
+   */
   FT_LOCAL_DEF( FT_Error )
   T1_Set_Var_Design( T1_Face    face,
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {

@@ -717,10 +790,12 @@
     /* allocate blend if necessary */
     error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
     if ( error )
       goto Exit;
 
+    FT_TRACE4(( " [" ));
+
     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++ )

@@ -739,15 +814,17 @@
       {
         error = FT_THROW( Invalid_File_Format );
         goto Exit;
       }
 
+      FT_TRACE4(( " /%.*s", len, token->start ));
+
       name = (FT_Byte*)blend->axis_names[n];
       if ( name )
       {
         FT_TRACE0(( "parse_blend_axis_types:"
-                    " overwriting axis name `%s' with `%*.s'\n",
+                    " overwriting axis name `%s' with `%.*s'\n",
                     name, len, token->start ));
         FT_FREE( name );
       }
 
       if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )

@@ -756,10 +833,12 @@
       name = (FT_Byte*)blend->axis_names[n];
       FT_MEM_COPY( name, token->start, len );
       name[len] = '\0';
     }
 
+    FT_TRACE4(( "]\n" ));
+
   Exit:
     loader->parser.root.error = error;
   }
 
 

@@ -800,10 +879,12 @@
 
 
       blend    = face->blend;
       num_axis = 0;  /* make compiler happy */
 
+      FT_TRACE4(( " [" ));
+
       for ( n = 0; n < num_designs; n++ )
       {
         T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
         T1_Token     token;
         FT_Int       axis, n_axis;

@@ -840,21 +921,26 @@
           error = FT_THROW( Invalid_File_Format );
           goto Exit;
         }
 
         /* now read each axis token into the design position */
+        FT_TRACE4(( " [" )) ;
         for ( axis = 0; axis < n_axis; axis++ )
         {
           T1_Token  token2 = axis_tokens + axis;
 
 
           parser->root.cursor = token2->start;
           parser->root.limit  = token2->limit;
           blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+          FT_TRACE4(( " %f", (double)blend->design_pos[n][axis] / 65536 ));
         }
+        FT_TRACE4(( "]" )) ;
       }
 
+      FT_TRACE4(( "]\n" ));
+
       loader->parser.root.cursor = old_cursor;
       loader->parser.root.limit  = old_limit;
     }
 
   Exit:

@@ -897,10 +983,12 @@
     error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
     if ( error )
       goto Exit;
     blend = face->blend;
 
+    FT_TRACE4(( " [" ));
+
     /* now read each axis design map */
     for ( n = 0; n < num_axis; n++ )
     {
       PS_DesignMap  map = blend->design_map + n;
       T1_Token      axis_token;

@@ -913,10 +1001,12 @@
       parser->root.cursor = axis_token->start;
       parser->root.limit  = axis_token->limit;
       T1_ToTokenArray( parser, point_tokens,
                        T1_MAX_MM_MAP_POINTS, &num_points );
 
+      FT_TRACE4(( " [" ));
+
       if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
       {
         FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
         error = FT_THROW( Invalid_File_Format );
         goto Exit;

@@ -946,13 +1036,21 @@
         parser->root.cursor = point_token->start + 1;
         parser->root.limit  = point_token->limit - 1;
 
         map->design_points[p] = T1_ToInt( parser );
         map->blend_points [p] = T1_ToFixed( parser, 0 );
+
+        FT_TRACE4(( " [%d %f]",
+                    map->design_points[p],
+                    (double)map->blend_points[p] / 65536 ));
       }
+
+      FT_TRACE4(( "]" ));
     }
 
+    FT_TRACE4(( "]\n" ));
+
     parser->root.cursor = old_cursor;
     parser->root.limit  = old_limit;
 
   Exit:
     parser->root.error = error;

@@ -1008,20 +1106,26 @@
     }
 
     old_cursor = parser->root.cursor;
     old_limit  = parser->root.limit;
 
+    FT_TRACE4(( "[" ));
+
     for ( n = 0; n < num_designs; n++ )
     {
       token = design_tokens + n;
       parser->root.cursor = token->start;
       parser->root.limit  = token->limit;
 
       blend->default_weight_vector[n] =
       blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
+
+      FT_TRACE4(( " %f", (double)blend->weight_vector[n] / 65536 ));
     }
 
+    FT_TRACE4(( "]\n" ));
+
     parser->root.cursor = old_cursor;
     parser->root.limit  = old_limit;
 
   Exit:
     parser->root.error = error;

@@ -1034,10 +1138,24 @@
   parse_buildchar( T1_Face    face,
                    T1_Loader  loader )
   {
     face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
                                                     0, NULL, 0 );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    {
+      FT_UInt  i;
+
+
+      FT_TRACE4(( " [" ));
+      for ( i = 0; i < face->len_buildchar; i++ )
+        FT_TRACE4(( " 0" ));
+
+      FT_TRACE4(( "]\n" ));
+    }
+#endif
+
     return;
   }
 
 
 #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */

@@ -1069,10 +1187,12 @@
       blend = NULL;
 
     /* if the keyword has a dedicated callback, call it */
     if ( field->type == T1_FIELD_TYPE_CALLBACK )
     {
+      FT_TRACE4(( "  %s", field->ident ));
+
       field->reader( (FT_Face)face, loader );
       error = loader->parser.root.error;
       goto Exit;
     }
 

@@ -1146,10 +1266,12 @@
       dummy_object = &face->type1;
       objects      = &dummy_object;
       max_objects  = 0;
     }
 
+    FT_TRACE4(( "  %s", field->ident ));
+
     if ( *objects )
     {
       if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
            field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
         error = T1_Load_Field_Table( &loader->parser, field,

@@ -1165,10 +1287,12 @@
                   "                 (probably due to missing keywords)\n",
                  field->ident ));
       error = FT_Err_Ok;
     }
 
+    FT_TRACE4(( "\n" ));
+
   Exit:
     return error;
   }
 
 

@@ -1177,10 +1301,12 @@
                  T1_Loader  loader )
   {
     FT_UNUSED( face );
 
     loader->keywords_encountered |= T1_PRIVATE;
+
+    FT_TRACE4(( "\n" ));
   }
 
 
   /* return 1 in case of success */
 

@@ -1256,10 +1382,18 @@
     {
       parser->root.error = FT_THROW( Invalid_File_Format );
       return;
     }
 
+    FT_TRACE4(( " [%f %f %f %f %f %f]\n",
+                (double)temp[0] / 65536 / 1000,
+                (double)temp[1] / 65536 / 1000,
+                (double)temp[2] / 65536 / 1000,
+                (double)temp[3] / 65536 / 1000,
+                (double)temp[4] / 65536 / 1000,
+                (double)temp[5] / 65536 / 1000 ));
+
     temp_scale = FT_ABS( temp[3] );
 
     if ( temp_scale == 0 )
     {
       FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));

@@ -1278,16 +1412,22 @@
       temp[2] = FT_DivFix( temp[2], temp_scale );
       temp[4] = FT_DivFix( temp[4], temp_scale );
       temp[5] = FT_DivFix( temp[5], temp_scale );
       temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
     }
-
     matrix->xx = temp[0];
     matrix->yx = temp[1];
     matrix->xy = temp[2];
     matrix->yy = temp[3];
 
+    if ( !FT_Matrix_Check( matrix ) )
+    {
+      FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
+      parser->root.error = FT_THROW( Invalid_File_Format );
+      return;
+    }
+
     /* note that the offsets must be expressed in integer font units */
     offset->x = temp[4] >> 16;
     offset->y = temp[5] >> 16;
   }
 

@@ -1492,32 +1632,53 @@
         }
 
         T1_Skip_Spaces( parser );
       }
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE4(( " [" ));
+
+      /* XXX show encoding vector */
+      FT_TRACE4(( "..." ));
+
+      FT_TRACE4(( "]\n" ));
+#endif
+
       face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
       parser->root.cursor       = cur;
     }
 
     /* Otherwise, we should have either `StandardEncoding', */
     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
     else
     {
       if ( cur + 17 < limit                                            &&
            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+      {
         face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+        FT_TRACE4(( " StandardEncoding\n" ));
+      }
 
       else if ( cur + 15 < limit                                          &&
                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+      {
         face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+        FT_TRACE4(( " ExpertEncoding\n" ));
+      }
 
       else if ( cur + 18 < limit                                             &&
                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+      {
         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+        FT_TRACE4(( " ISOLatin1Encoding\n" ));
+      }
 
       else
+      {
         parser->root.error = FT_ERR( Ignore );
+        FT_TRACE4(( "<unknown>\n" ));
+      }
     }
   }
 
 
   static void

@@ -1694,10 +1855,19 @@
     }
 
     if ( !loader->num_subrs )
       loader->num_subrs = num_subrs;
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE4(( " <" ));
+
+      /* XXX show subrs? */
+      FT_TRACE4(( "%d elements", num_subrs ));
+
+      FT_TRACE4(( ">\n" ));
+#endif
+
     return;
 
   Fail:
     parser->root.error = error;
   }

@@ -2015,23 +2185,32 @@
 
       /* we added a glyph. */
       loader->num_glyphs += 1;
     }
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE4(( " <" ));
+
+      /* XXX show charstrings? */
+      FT_TRACE4(( "%d elements", loader->num_glyphs ));
+
+      FT_TRACE4(( ">\n" ));
+#endif
+
     return;
 
   Fail:
     parser->root.error = error;
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Define the token field static variables.  This is a set of            */
-  /* T1_FieldRec variables.                                                */
-  /*                                                                       */
-  /*************************************************************************/
+  /**************************************************************************
+   *
+   * Define the token field static variables.  This is a set of
+   * T1_FieldRec variables.
+   *
+   */
 
 
   static
   const T1_FieldRec  t1_keywords[] =
   {

@@ -2214,10 +2393,11 @@
               const FT_UInt dict =
                 ( loader->keywords_encountered & T1_PRIVATE )
                     ? T1_FIELD_DICT_PRIVATE
                     : T1_FIELD_DICT_FONTDICT;
 
+
               if ( !( dict & keyword->dict ) )
               {
                 FT_TRACE1(( "parse_dict: found `%s' but ignoring it"
                             " since it is in the wrong dictionary\n",
                             keyword->ident ));

@@ -2328,29 +2508,41 @@
                             face->root.memory,
                             psaux );
     if ( error )
       goto Exit;
 
+    FT_TRACE4(( " top dictionary:\n" ));
     error = parse_dict( face, &loader,
                         parser->base_dict, parser->base_len );
     if ( error )
       goto Exit;
 
     error = T1_Get_Private_Dict( parser, psaux );
     if ( error )
       goto Exit;
 
+    FT_TRACE4(( " private dictionary:\n" ));
     error = parse_dict( face, &loader,
                         parser->private_dict, parser->private_len );
     if ( error )
       goto Exit;
 
     /* ensure even-ness of `num_blue_values' */
     priv->num_blue_values &= ~1;
 
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
 
+    /* we don't support Multiple Master fonts with intermediate designs; */
+    /* this implies that `num_designs' must be equal to `2^^num_axis'    */
+    if ( face->blend                                                 &&
+         face->blend->num_designs != ( 1U << face->blend->num_axis ) )
+    {
+      FT_ERROR(( "T1_Open_Face:"
+                 " number-of-designs != 2 ^^ number-of-axes\n" ));
+      T1_Done_Blend( face );
+    }
+
     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 */
< prev index next >