• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /***************************************************************************/
2  /*                                                                         */
3  /*  t1load.c                                                               */
4  /*                                                                         */
5  /*    Type 1 font loader (body).                                           */
6  /*                                                                         */
7  /*  Copyright 1996-2014 by                                                 */
8  /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9  /*                                                                         */
10  /*  This file is part of the FreeType project, and may only be used,       */
11  /*  modified, and distributed under the terms of the FreeType project      */
12  /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13  /*  this file you indicate that you have read the license and              */
14  /*  understand and accept it fully.                                        */
15  /*                                                                         */
16  /***************************************************************************/
17  
18  
19    /*************************************************************************/
20    /*                                                                       */
21    /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
22    /* old loader has several problems: it is slow, complex, difficult to    */
23    /* maintain, and contains incredible hacks to make it accept some        */
24    /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
25    /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
26    /*                                                                       */
27    /* This version is much simpler, much faster and also easier to read and */
28    /* maintain by a great order of magnitude.  The idea behind it is to     */
29    /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
30    /* a Postscript-like interpreter) but rather to perform simple pattern   */
31    /* matching.                                                             */
32    /*                                                                       */
33    /* Indeed, nearly all data definitions follow a simple pattern like      */
34    /*                                                                       */
35    /*  ... /Field <data> ...                                                */
36    /*                                                                       */
37    /* where <data> can be a number, a boolean, a string, or an array of     */
38    /* numbers.  There are a few exceptions, namely the encoding, font name, */
39    /* charstrings, and subrs; they are handled with a special pattern       */
40    /* matching routine.                                                     */
41    /*                                                                       */
42    /* All other common cases are handled very simply.  The matching rules   */
43    /* are defined in the file `t1tokens.h' through the use of several       */
44    /* macros calls PARSE_XXX.  This file is included twice here; the first  */
45    /* time to generate parsing callback functions, the second time to       */
46    /* generate a table of keywords (with pointers to the associated         */
47    /* callback functions).                                                  */
48    /*                                                                       */
49    /* The function `parse_dict' simply scans *linearly* a given dictionary  */
50    /* (either the top-level or private one) and calls the appropriate       */
51    /* callback when it encounters an immediate keyword.                     */
52    /*                                                                       */
53    /* This is by far the fastest way one can find to parse and read all     */
54    /* data.                                                                 */
55    /*                                                                       */
56    /* This led to tremendous code size reduction.  Note that later, the     */
57    /* glyph loader will also be _greatly_ simplified, and the automatic     */
58    /* hinter will replace the clumsy `t1hinter'.                            */
59    /*                                                                       */
60    /*************************************************************************/
61  
62  
63  #include <ft2build.h>
64  #include FT_INTERNAL_DEBUG_H
65  #include FT_CONFIG_CONFIG_H
66  #include FT_MULTIPLE_MASTERS_H
67  #include FT_INTERNAL_TYPE1_TYPES_H
68  #include FT_INTERNAL_CALC_H
69  
70  #include "t1load.h"
71  #include "t1errors.h"
72  
73  
74  #ifdef FT_CONFIG_OPTION_INCREMENTAL
75  #define IS_INCREMENTAL  (FT_Bool)( face->root.internal->incremental_interface != 0 )
76  #else
77  #define IS_INCREMENTAL  0
78  #endif
79  
80  
81    /*************************************************************************/
82    /*                                                                       */
83    /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
84    /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
85    /* messages during execution.                                            */
86    /*                                                                       */
87  #undef  FT_COMPONENT
88  #define FT_COMPONENT  trace_t1load
89  
90  
91  #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
92  
93  
94    /*************************************************************************/
95    /*************************************************************************/
96    /*****                                                               *****/
97    /*****                    MULTIPLE MASTERS SUPPORT                   *****/
98    /*****                                                               *****/
99    /*************************************************************************/
100    /*************************************************************************/
101  
102    static FT_Error
t1_allocate_blend(T1_Face face,FT_UInt num_designs,FT_UInt num_axis)103    t1_allocate_blend( T1_Face  face,
104                       FT_UInt  num_designs,
105                       FT_UInt  num_axis )
106    {
107      PS_Blend   blend;
108      FT_Memory  memory = face->root.memory;
109      FT_Error   error  = FT_Err_Ok;
110  
111  
112      blend = face->blend;
113      if ( !blend )
114      {
115        if ( FT_NEW( blend ) )
116          goto Exit;
117  
118        blend->num_default_design_vector = 0;
119  
120        face->blend = blend;
121      }
122  
123      /* allocate design data if needed */
124      if ( num_designs > 0 )
125      {
126        if ( blend->num_designs == 0 )
127        {
128          FT_UInt  nn;
129  
130  
131          /* allocate the blend `private' and `font_info' dictionaries */
132          if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs     ) ||
133               FT_NEW_ARRAY( blend->privates  [1], num_designs     ) ||
134               FT_NEW_ARRAY( blend->bboxes    [1], num_designs     ) ||
135               FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
136            goto Exit;
137  
138          blend->default_weight_vector = blend->weight_vector + num_designs;
139  
140          blend->font_infos[0] = &face->type1.font_info;
141          blend->privates  [0] = &face->type1.private_dict;
142          blend->bboxes    [0] = &face->type1.font_bbox;
143  
144          for ( nn = 2; nn <= num_designs; nn++ )
145          {
146            blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
147            blend->privates  [nn] = blend->privates  [nn - 1] + 1;
148            blend->bboxes    [nn] = blend->bboxes    [nn - 1] + 1;
149          }
150  
151          blend->num_designs = num_designs;
152        }
153        else if ( blend->num_designs != num_designs )
154          goto Fail;
155      }
156  
157      /* allocate axis data if needed */
158      if ( num_axis > 0 )
159      {
160        if ( blend->num_axis != 0 && blend->num_axis != num_axis )
161          goto Fail;
162  
163        blend->num_axis = num_axis;
164      }
165  
166      /* allocate the blend design pos table if needed */
167      num_designs = blend->num_designs;
168      num_axis    = blend->num_axis;
169      if ( num_designs && num_axis && blend->design_pos[0] == 0 )
170      {
171        FT_UInt  n;
172  
173  
174        if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
175          goto Exit;
176  
177        for ( n = 1; n < num_designs; n++ )
178          blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
179      }
180  
181    Exit:
182      return error;
183  
184    Fail:
185      error = FT_THROW( Invalid_File_Format );
186      goto Exit;
187    }
188  
189  
190    FT_LOCAL_DEF( FT_Error )
T1_Get_Multi_Master(T1_Face face,FT_Multi_Master * master)191    T1_Get_Multi_Master( T1_Face           face,
192                         FT_Multi_Master*  master )
193    {
194      PS_Blend  blend = face->blend;
195      FT_UInt   n;
196      FT_Error  error;
197  
198  
199      error = FT_THROW( Invalid_Argument );
200  
201      if ( blend )
202      {
203        master->num_axis    = blend->num_axis;
204        master->num_designs = blend->num_designs;
205  
206        for ( n = 0; n < blend->num_axis; n++ )
207        {
208          FT_MM_Axis*   axis = master->axis + n;
209          PS_DesignMap  map = blend->design_map + n;
210  
211  
212          axis->name    = blend->axis_names[n];
213          axis->minimum = map->design_points[0];
214          axis->maximum = map->design_points[map->num_points - 1];
215        }
216  
217        error = FT_Err_Ok;
218      }
219  
220      return error;
221    }
222  
223  
224    /*************************************************************************/
225    /*                                                                       */
226    /* Given a normalized (blend) coordinate, figure out the design          */
227    /* coordinate appropriate for that value.                                */
228    /*                                                                       */
229    FT_LOCAL_DEF( FT_Fixed )
mm_axis_unmap(PS_DesignMap axismap,FT_Fixed ncv)230    mm_axis_unmap( PS_DesignMap  axismap,
231                   FT_Fixed      ncv )
232    {
233      int  j;
234  
235  
236      if ( ncv <= axismap->blend_points[0] )
237        return INT_TO_FIXED( axismap->design_points[0] );
238  
239      for ( j = 1; j < axismap->num_points; ++j )
240      {
241        if ( ncv <= axismap->blend_points[j] )
242          return INT_TO_FIXED( axismap->design_points[j - 1] ) +
243                 ( axismap->design_points[j] - axismap->design_points[j - 1] ) *
244                 FT_DivFix( ncv - axismap->blend_points[j - 1],
245                            axismap->blend_points[j] -
246                              axismap->blend_points[j - 1] );
247      }
248  
249      return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
250    }
251  
252  
253    /*************************************************************************/
254    /*                                                                       */
255    /* Given a vector of weights, one for each design, figure out the        */
256    /* normalized axis coordinates which gave rise to those weights.         */
257    /*                                                                       */
258    FT_LOCAL_DEF( void )
mm_weights_unmap(FT_Fixed * weights,FT_Fixed * axiscoords,FT_UInt axis_count)259    mm_weights_unmap( FT_Fixed*  weights,
260                      FT_Fixed*  axiscoords,
261                      FT_UInt    axis_count )
262    {
263      FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
264  
265      if ( axis_count == 1 )
266        axiscoords[0] = weights[1];
267  
268      else if ( axis_count == 2 )
269      {
270        axiscoords[0] = weights[3] + weights[1];
271        axiscoords[1] = weights[3] + weights[2];
272      }
273  
274      else if ( axis_count == 3 )
275      {
276        axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
277        axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
278        axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
279      }
280  
281      else
282      {
283        axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
284                          weights[7] + weights[5] + weights[3] + weights[1];
285        axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
286                          weights[7] + weights[6] + weights[3] + weights[2];
287        axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
288                          weights[7] + weights[6] + weights[5] + weights[4];
289        axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
290                          weights[11] + weights[10] + weights[9] + weights[8];
291      }
292    }
293  
294  
295    /*************************************************************************/
296    /*                                                                       */
297    /* Just a wrapper around T1_Get_Multi_Master to support the different    */
298    /*  arguments needed by the GX var distortable fonts.                    */
299    /*                                                                       */
300    FT_LOCAL_DEF( FT_Error )
T1_Get_MM_Var(T1_Face face,FT_MM_Var ** master)301    T1_Get_MM_Var( T1_Face      face,
302                   FT_MM_Var*  *master )
303    {
304      FT_Memory        memory = face->root.memory;
305      FT_MM_Var       *mmvar = NULL;
306      FT_Multi_Master  mmaster;
307      FT_Error         error;
308      FT_UInt          i;
309      FT_Fixed         axiscoords[T1_MAX_MM_AXIS];
310      PS_Blend         blend = face->blend;
311  
312  
313      error = T1_Get_Multi_Master( face, &mmaster );
314      if ( error )
315        goto Exit;
316      if ( FT_ALLOC( mmvar,
317                     sizeof ( FT_MM_Var ) +
318                       mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
319        goto Exit;
320  
321      mmvar->num_axis        = mmaster.num_axis;
322      mmvar->num_designs     = mmaster.num_designs;
323      mmvar->num_namedstyles = ~0U;                        /* Does not apply */
324      mmvar->axis            = (FT_Var_Axis*)&mmvar[1];
325                                        /* Point to axes after MM_Var struct */
326      mmvar->namedstyle      = NULL;
327  
328      for ( i = 0 ; i < mmaster.num_axis; ++i )
329      {
330        mmvar->axis[i].name    = mmaster.axis[i].name;
331        mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum);
332        mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum);
333        mmvar->axis[i].def     = ( mmvar->axis[i].minimum +
334                                     mmvar->axis[i].maximum ) / 2;
335                              /* Does not apply.  But this value is in range */
336        mmvar->axis[i].strid   = ~0U;                      /* Does not apply */
337        mmvar->axis[i].tag     = ~0U;                      /* Does not apply */
338  
339        if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
340          mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
341        else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
342          mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
343        else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
344          mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
345      }
346  
347      if ( blend->num_designs == ( 1U << blend->num_axis ) )
348      {
349        mm_weights_unmap( blend->default_weight_vector,
350                          axiscoords,
351                          blend->num_axis );
352  
353        for ( i = 0; i < mmaster.num_axis; ++i )
354          mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
355                                              axiscoords[i] );
356      }
357  
358      *master = mmvar;
359  
360    Exit:
361      return error;
362    }
363  
364  
365    FT_LOCAL_DEF( FT_Error )
T1_Set_MM_Blend(T1_Face face,FT_UInt num_coords,FT_Fixed * coords)366    T1_Set_MM_Blend( T1_Face    face,
367                     FT_UInt    num_coords,
368                     FT_Fixed*  coords )
369    {
370      PS_Blend  blend = face->blend;
371      FT_Error  error;
372      FT_UInt   n, m;
373  
374  
375      error = FT_ERR( Invalid_Argument );
376  
377      if ( blend && blend->num_axis == num_coords )
378      {
379        /* recompute the weight vector from the blend coordinates */
380        for ( n = 0; n < blend->num_designs; n++ )
381        {
382          FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
383  
384  
385          for ( m = 0; m < blend->num_axis; m++ )
386          {
387            FT_Fixed  factor;
388  
389  
390            /* get current blend axis position */
391            factor = coords[m];
392            if ( factor < 0 )
393              factor = 0;
394            if ( factor > 0x10000L )
395              factor = 0x10000L;
396  
397            if ( ( n & ( 1 << m ) ) == 0 )
398              factor = 0x10000L - factor;
399  
400            result = FT_MulFix( result, factor );
401          }
402          blend->weight_vector[n] = result;
403        }
404  
405        error = FT_Err_Ok;
406      }
407  
408      return error;
409    }
410  
411  
412    FT_LOCAL_DEF( FT_Error )
T1_Set_MM_Design(T1_Face face,FT_UInt num_coords,FT_Long * coords)413    T1_Set_MM_Design( T1_Face   face,
414                      FT_UInt   num_coords,
415                      FT_Long*  coords )
416    {
417      PS_Blend  blend = face->blend;
418      FT_Error  error;
419      FT_UInt   n, p;
420  
421  
422      error = FT_ERR( Invalid_Argument );
423      if ( blend && blend->num_axis == num_coords )
424      {
425        /* compute the blend coordinates through the blend design map */
426        FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
427  
428  
429        for ( n = 0; n < blend->num_axis; n++ )
430        {
431          FT_Long       design  = coords[n];
432          FT_Fixed      the_blend;
433          PS_DesignMap  map     = blend->design_map + n;
434          FT_Long*      designs = map->design_points;
435          FT_Fixed*     blends  = map->blend_points;
436          FT_Int        before  = -1, after = -1;
437  
438  
439          for ( p = 0; p < (FT_UInt)map->num_points; p++ )
440          {
441            FT_Long  p_design = designs[p];
442  
443  
444            /* exact match? */
445            if ( design == p_design )
446            {
447              the_blend = blends[p];
448              goto Found;
449            }
450  
451            if ( design < p_design )
452            {
453              after = p;
454              break;
455            }
456  
457            before = p;
458          }
459  
460          /* now interpolate if necessary */
461          if ( before < 0 )
462            the_blend = blends[0];
463  
464          else if ( after < 0 )
465            the_blend = blends[map->num_points - 1];
466  
467          else
468            the_blend = FT_MulDiv( design         - designs[before],
469                                   blends [after] - blends [before],
470                                   designs[after] - designs[before] );
471  
472        Found:
473          final_blends[n] = the_blend;
474        }
475  
476        error = T1_Set_MM_Blend( face, num_coords, final_blends );
477      }
478  
479      return error;
480    }
481  
482  
483    /*************************************************************************/
484    /*                                                                       */
485    /* Just a wrapper around T1_Set_MM_Design to support the different       */
486    /* arguments needed by the GX var distortable fonts.                     */
487    /*                                                                       */
488    FT_LOCAL_DEF( FT_Error )
T1_Set_Var_Design(T1_Face face,FT_UInt num_coords,FT_Fixed * coords)489    T1_Set_Var_Design( T1_Face    face,
490                       FT_UInt    num_coords,
491                       FT_Fixed*  coords )
492    {
493       FT_Long   lcoords[4];          /* maximum axis count is 4 */
494       FT_UInt   i;
495       FT_Error  error;
496  
497  
498       error = FT_ERR( Invalid_Argument );
499       if ( num_coords <= 4 && num_coords > 0 )
500       {
501         for ( i = 0; i < num_coords; ++i )
502           lcoords[i] = FIXED_TO_INT( coords[i] );
503         error = T1_Set_MM_Design( face, num_coords, lcoords );
504       }
505  
506       return error;
507    }
508  
509  
510    FT_LOCAL_DEF( void )
T1_Done_Blend(T1_Face face)511    T1_Done_Blend( T1_Face  face )
512    {
513      FT_Memory  memory = face->root.memory;
514      PS_Blend   blend  = face->blend;
515  
516  
517      if ( blend )
518      {
519        FT_UInt  num_designs = blend->num_designs;
520        FT_UInt  num_axis    = blend->num_axis;
521        FT_UInt  n;
522  
523  
524        /* release design pos table */
525        FT_FREE( blend->design_pos[0] );
526        for ( n = 1; n < num_designs; n++ )
527          blend->design_pos[n] = NULL;
528  
529        /* release blend `private' and `font info' dictionaries */
530        FT_FREE( blend->privates[1] );
531        FT_FREE( blend->font_infos[1] );
532        FT_FREE( blend->bboxes[1] );
533  
534        for ( n = 0; n < num_designs; n++ )
535        {
536          blend->privates  [n] = NULL;
537          blend->font_infos[n] = NULL;
538          blend->bboxes    [n] = NULL;
539        }
540  
541        /* release weight vectors */
542        FT_FREE( blend->weight_vector );
543        blend->default_weight_vector = NULL;
544  
545        /* release axis names */
546        for ( n = 0; n < num_axis; n++ )
547          FT_FREE( blend->axis_names[n] );
548  
549        /* release design map */
550        for ( n = 0; n < num_axis; n++ )
551        {
552          PS_DesignMap  dmap = blend->design_map + n;
553  
554  
555          FT_FREE( dmap->design_points );
556          dmap->num_points = 0;
557        }
558  
559        FT_FREE( face->blend );
560      }
561    }
562  
563  
564    static void
parse_blend_axis_types(T1_Face face,T1_Loader loader)565    parse_blend_axis_types( T1_Face    face,
566                            T1_Loader  loader )
567    {
568      T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
569      FT_Int       n, num_axis;
570      FT_Error     error = FT_Err_Ok;
571      PS_Blend     blend;
572      FT_Memory    memory;
573  
574  
575      /* take an array of objects */
576      T1_ToTokenArray( &loader->parser, axis_tokens,
577                       T1_MAX_MM_AXIS, &num_axis );
578      if ( num_axis < 0 )
579      {
580        error = FT_ERR( Ignore );
581        goto Exit;
582      }
583      if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
584      {
585        FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
586                   num_axis ));
587        error = FT_THROW( Invalid_File_Format );
588        goto Exit;
589      }
590  
591      /* allocate blend if necessary */
592      error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
593      if ( error )
594        goto Exit;
595  
596      blend  = face->blend;
597      memory = face->root.memory;
598  
599      /* each token is an immediate containing the name of the axis */
600      for ( n = 0; n < num_axis; n++ )
601      {
602        T1_Token    token = axis_tokens + n;
603        FT_Byte*    name;
604        FT_PtrDist  len;
605  
606  
607        /* skip first slash, if any */
608        if ( token->start[0] == '/' )
609          token->start++;
610  
611        len = token->limit - token->start;
612        if ( len == 0 )
613        {
614          error = FT_THROW( Invalid_File_Format );
615          goto Exit;
616        }
617  
618        if ( FT_ALLOC( blend->axis_names[n], (FT_Long)( len + 1 ) ) )
619          goto Exit;
620  
621        name = (FT_Byte*)blend->axis_names[n];
622        FT_MEM_COPY( name, token->start, len );
623        name[len] = '\0';
624      }
625  
626    Exit:
627      loader->parser.root.error = error;
628    }
629  
630  
631    static void
parse_blend_design_positions(T1_Face face,T1_Loader loader)632    parse_blend_design_positions( T1_Face    face,
633                                  T1_Loader  loader )
634    {
635      T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
636      FT_Int       num_designs;
637      FT_Int       num_axis;
638      T1_Parser    parser = &loader->parser;
639  
640      FT_Error     error = FT_Err_Ok;
641      PS_Blend     blend;
642  
643  
644      /* get the array of design tokens -- compute number of designs */
645      T1_ToTokenArray( parser, design_tokens,
646                       T1_MAX_MM_DESIGNS, &num_designs );
647      if ( num_designs < 0 )
648      {
649        error = FT_ERR( Ignore );
650        goto Exit;
651      }
652      if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
653      {
654        FT_ERROR(( "parse_blend_design_positions:"
655                   " incorrect number of designs: %d\n",
656                   num_designs ));
657        error = FT_THROW( Invalid_File_Format );
658        goto Exit;
659      }
660  
661      {
662        FT_Byte*  old_cursor = parser->root.cursor;
663        FT_Byte*  old_limit  = parser->root.limit;
664        FT_Int    n;
665  
666  
667        blend    = face->blend;
668        num_axis = 0;  /* make compiler happy */
669  
670        for ( n = 0; n < num_designs; n++ )
671        {
672          T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
673          T1_Token     token;
674          FT_Int       axis, n_axis;
675  
676  
677          /* read axis/coordinates tokens */
678          token = design_tokens + n;
679          parser->root.cursor = token->start;
680          parser->root.limit  = token->limit;
681          T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
682  
683          if ( n == 0 )
684          {
685            if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
686            {
687              FT_ERROR(( "parse_blend_design_positions:"
688                         " invalid number of axes: %d\n",
689                         n_axis ));
690              error = FT_THROW( Invalid_File_Format );
691              goto Exit;
692            }
693  
694            num_axis = n_axis;
695            error = t1_allocate_blend( face, num_designs, num_axis );
696            if ( error )
697              goto Exit;
698            blend = face->blend;
699          }
700          else if ( n_axis != num_axis )
701          {
702            FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
703            error = FT_THROW( Invalid_File_Format );
704            goto Exit;
705          }
706  
707          /* now read each axis token into the design position */
708          for ( axis = 0; axis < n_axis; axis++ )
709          {
710            T1_Token  token2 = axis_tokens + axis;
711  
712  
713            parser->root.cursor = token2->start;
714            parser->root.limit  = token2->limit;
715            blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
716          }
717        }
718  
719        loader->parser.root.cursor = old_cursor;
720        loader->parser.root.limit  = old_limit;
721      }
722  
723    Exit:
724      loader->parser.root.error = error;
725    }
726  
727  
728    static void
parse_blend_design_map(T1_Face face,T1_Loader loader)729    parse_blend_design_map( T1_Face    face,
730                            T1_Loader  loader )
731    {
732      FT_Error     error  = FT_Err_Ok;
733      T1_Parser    parser = &loader->parser;
734      PS_Blend     blend;
735      T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
736      FT_Int       n, num_axis;
737      FT_Byte*     old_cursor;
738      FT_Byte*     old_limit;
739      FT_Memory    memory = face->root.memory;
740  
741  
742      T1_ToTokenArray( parser, axis_tokens,
743                       T1_MAX_MM_AXIS, &num_axis );
744      if ( num_axis < 0 )
745      {
746        error = FT_ERR( Ignore );
747        goto Exit;
748      }
749      if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
750      {
751        FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
752                   num_axis ));
753        error = FT_THROW( Invalid_File_Format );
754        goto Exit;
755      }
756  
757      old_cursor = parser->root.cursor;
758      old_limit  = parser->root.limit;
759  
760      error = t1_allocate_blend( face, 0, num_axis );
761      if ( error )
762        goto Exit;
763      blend = face->blend;
764  
765      /* now read each axis design map */
766      for ( n = 0; n < num_axis; n++ )
767      {
768        PS_DesignMap  map = blend->design_map + n;
769        T1_Token      axis_token;
770        T1_TokenRec   point_tokens[T1_MAX_MM_MAP_POINTS];
771        FT_Int        p, num_points;
772  
773  
774        axis_token = axis_tokens + n;
775  
776        parser->root.cursor = axis_token->start;
777        parser->root.limit  = axis_token->limit;
778        T1_ToTokenArray( parser, point_tokens,
779                         T1_MAX_MM_MAP_POINTS, &num_points );
780  
781        if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
782        {
783          FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
784          error = FT_THROW( Invalid_File_Format );
785          goto Exit;
786        }
787  
788        /* allocate design map data */
789        if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
790          goto Exit;
791        map->blend_points = map->design_points + num_points;
792        map->num_points   = (FT_Byte)num_points;
793  
794        for ( p = 0; p < num_points; p++ )
795        {
796          T1_Token  point_token;
797  
798  
799          point_token = point_tokens + p;
800  
801          /* don't include delimiting brackets */
802          parser->root.cursor = point_token->start + 1;
803          parser->root.limit  = point_token->limit - 1;
804  
805          map->design_points[p] = T1_ToInt( parser );
806          map->blend_points [p] = T1_ToFixed( parser, 0 );
807        }
808      }
809  
810      parser->root.cursor = old_cursor;
811      parser->root.limit  = old_limit;
812  
813    Exit:
814      parser->root.error = error;
815    }
816  
817  
818    static void
parse_weight_vector(T1_Face face,T1_Loader loader)819    parse_weight_vector( T1_Face    face,
820                         T1_Loader  loader )
821    {
822      T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
823      FT_Int       num_designs;
824      FT_Error     error  = FT_Err_Ok;
825      T1_Parser    parser = &loader->parser;
826      PS_Blend     blend  = face->blend;
827      T1_Token     token;
828      FT_Int       n;
829      FT_Byte*     old_cursor;
830      FT_Byte*     old_limit;
831  
832  
833      T1_ToTokenArray( parser, design_tokens,
834                       T1_MAX_MM_DESIGNS, &num_designs );
835      if ( num_designs < 0 )
836      {
837        error = FT_ERR( Ignore );
838        goto Exit;
839      }
840      if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
841      {
842        FT_ERROR(( "parse_weight_vector:"
843                   " incorrect number of designs: %d\n",
844                   num_designs ));
845        error = FT_THROW( Invalid_File_Format );
846        goto Exit;
847      }
848  
849      if ( !blend || !blend->num_designs )
850      {
851        error = t1_allocate_blend( face, num_designs, 0 );
852        if ( error )
853          goto Exit;
854        blend = face->blend;
855      }
856      else if ( blend->num_designs != (FT_UInt)num_designs )
857      {
858        FT_ERROR(( "parse_weight_vector:"
859                   " /BlendDesignPosition and /WeightVector have\n"
860                   "                    "
861                   " different number of elements\n" ));
862        error = FT_THROW( Invalid_File_Format );
863        goto Exit;
864      }
865  
866      old_cursor = parser->root.cursor;
867      old_limit  = parser->root.limit;
868  
869      for ( n = 0; n < num_designs; n++ )
870      {
871        token = design_tokens + n;
872        parser->root.cursor = token->start;
873        parser->root.limit  = token->limit;
874  
875        blend->default_weight_vector[n] =
876        blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
877      }
878  
879      parser->root.cursor = old_cursor;
880      parser->root.limit  = old_limit;
881  
882    Exit:
883      parser->root.error = error;
884    }
885  
886  
887    /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
888    /* we're only interested in the number of array elements */
889    static void
parse_buildchar(T1_Face face,T1_Loader loader)890    parse_buildchar( T1_Face    face,
891                     T1_Loader  loader )
892    {
893      face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
894  
895      return;
896    }
897  
898  
899  #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
900  
901  
902  
903  
904    /*************************************************************************/
905    /*************************************************************************/
906    /*****                                                               *****/
907    /*****                      TYPE 1 SYMBOL PARSING                    *****/
908    /*****                                                               *****/
909    /*************************************************************************/
910    /*************************************************************************/
911  
912    static FT_Error
t1_load_keyword(T1_Face face,T1_Loader loader,const T1_Field field)913    t1_load_keyword( T1_Face         face,
914                     T1_Loader       loader,
915                     const T1_Field  field )
916    {
917      FT_Error  error;
918      void*     dummy_object;
919      void**    objects;
920      FT_UInt   max_objects;
921      PS_Blend  blend = face->blend;
922  
923  
924      if ( blend && blend->num_designs == 0 )
925        blend = NULL;
926  
927      /* if the keyword has a dedicated callback, call it */
928      if ( field->type == T1_FIELD_TYPE_CALLBACK )
929      {
930        field->reader( (FT_Face)face, loader );
931        error = loader->parser.root.error;
932        goto Exit;
933      }
934  
935      /* now, the keyword is either a simple field, or a table of fields; */
936      /* we are now going to take care of it                              */
937      switch ( field->location )
938      {
939      case T1_FIELD_LOCATION_FONT_INFO:
940        dummy_object = &face->type1.font_info;
941        objects      = &dummy_object;
942        max_objects  = 0;
943  
944        if ( blend )
945        {
946          objects     = (void**)blend->font_infos;
947          max_objects = blend->num_designs;
948        }
949        break;
950  
951      case T1_FIELD_LOCATION_FONT_EXTRA:
952        dummy_object = &face->type1.font_extra;
953        objects      = &dummy_object;
954        max_objects  = 0;
955        break;
956  
957      case T1_FIELD_LOCATION_PRIVATE:
958        dummy_object = &face->type1.private_dict;
959        objects      = &dummy_object;
960        max_objects  = 0;
961  
962        if ( blend )
963        {
964          objects     = (void**)blend->privates;
965          max_objects = blend->num_designs;
966        }
967        break;
968  
969      case T1_FIELD_LOCATION_BBOX:
970        dummy_object = &face->type1.font_bbox;
971        objects      = &dummy_object;
972        max_objects  = 0;
973  
974        if ( blend )
975        {
976          objects     = (void**)blend->bboxes;
977          max_objects = blend->num_designs;
978        }
979        break;
980  
981      case T1_FIELD_LOCATION_LOADER:
982        dummy_object = loader;
983        objects      = &dummy_object;
984        max_objects  = 0;
985        break;
986  
987      case T1_FIELD_LOCATION_FACE:
988        dummy_object = face;
989        objects      = &dummy_object;
990        max_objects  = 0;
991        break;
992  
993  #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
994      case T1_FIELD_LOCATION_BLEND:
995        dummy_object = face->blend;
996        objects      = &dummy_object;
997        max_objects  = 0;
998        break;
999  #endif
1000  
1001      default:
1002        dummy_object = &face->type1;
1003        objects      = &dummy_object;
1004        max_objects  = 0;
1005      }
1006  
1007      if ( *objects )
1008      {
1009        if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1010             field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1011          error = T1_Load_Field_Table( &loader->parser, field,
1012                                       objects, max_objects, 0 );
1013        else
1014          error = T1_Load_Field( &loader->parser, field,
1015                                 objects, max_objects, 0 );
1016      }
1017      else
1018      {
1019        FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'"
1020                    " which is not valid at this point\n"
1021                    "                 (probably due to missing keywords)\n",
1022                   field->ident ));
1023        error = FT_Err_Ok;
1024      }
1025  
1026    Exit:
1027      return error;
1028    }
1029  
1030  
1031    static void
parse_private(T1_Face face,T1_Loader loader)1032    parse_private( T1_Face    face,
1033                   T1_Loader  loader )
1034    {
1035      FT_UNUSED( face );
1036  
1037      loader->keywords_encountered |= T1_PRIVATE;
1038    }
1039  
1040  
1041    static int
read_binary_data(T1_Parser parser,FT_Long * size,FT_Byte ** base,FT_Bool incremental)1042    read_binary_data( T1_Parser  parser,
1043                      FT_Long*   size,
1044                      FT_Byte**  base,
1045                      FT_Bool    incremental )
1046    {
1047      FT_Byte*  cur;
1048      FT_Byte*  limit = parser->root.limit;
1049  
1050  
1051      /* the binary data has one of the following formats */
1052      /*                                                  */
1053      /*   `size' [white*] RD white ....... ND            */
1054      /*   `size' [white*] -| white ....... |-            */
1055      /*                                                  */
1056  
1057      T1_Skip_Spaces( parser );
1058  
1059      cur = parser->root.cursor;
1060  
1061      if ( cur < limit && ft_isdigit( *cur ) )
1062      {
1063        FT_Long  s = T1_ToInt( parser );
1064  
1065  
1066        T1_Skip_PS_Token( parser );   /* `RD' or `-|' or something else */
1067  
1068        /* there is only one whitespace char after the */
1069        /* `RD' or `-|' token                          */
1070        *base = parser->root.cursor + 1;
1071  
1072        if ( s >= 0 && s < limit - *base )
1073        {
1074          parser->root.cursor += s + 1;
1075          *size = s;
1076          return !parser->root.error;
1077        }
1078      }
1079  
1080      if( !incremental )
1081      {
1082        FT_ERROR(( "read_binary_data: invalid size field\n" ));
1083        parser->root.error = FT_THROW( Invalid_File_Format );
1084      }
1085  
1086      return 0;
1087    }
1088  
1089  
1090    /* We now define the routines to handle the `/Encoding', `/Subrs', */
1091    /* and `/CharStrings' dictionaries.                                */
1092  
1093    static void
t1_parse_font_matrix(T1_Face face,T1_Loader loader)1094    t1_parse_font_matrix( T1_Face    face,
1095                          T1_Loader  loader )
1096    {
1097      T1_Parser   parser = &loader->parser;
1098      FT_Matrix*  matrix = &face->type1.font_matrix;
1099      FT_Vector*  offset = &face->type1.font_offset;
1100      FT_Face     root   = (FT_Face)&face->root;
1101      FT_Fixed    temp[6];
1102      FT_Fixed    temp_scale;
1103      FT_Int      result;
1104  
1105  
1106      result = T1_ToFixedArray( parser, 6, temp, 3 );
1107  
1108      if ( result < 6 )
1109      {
1110        parser->root.error = FT_THROW( Invalid_File_Format );
1111        return;
1112      }
1113  
1114      temp_scale = FT_ABS( temp[3] );
1115  
1116      if ( temp_scale == 0 )
1117      {
1118        FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
1119        parser->root.error = FT_THROW( Invalid_File_Format );
1120        return;
1121      }
1122  
1123      /* Set Units per EM based on FontMatrix values.  We set the value to */
1124      /* 1000 / temp_scale, because temp_scale was already multiplied by   */
1125      /* 1000 (in t1_tofixed, from psobjs.c).                              */
1126  
1127      root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
1128  
1129      /* we need to scale the values by 1.0/temp_scale */
1130      if ( temp_scale != 0x10000L )
1131      {
1132        temp[0] = FT_DivFix( temp[0], temp_scale );
1133        temp[1] = FT_DivFix( temp[1], temp_scale );
1134        temp[2] = FT_DivFix( temp[2], temp_scale );
1135        temp[4] = FT_DivFix( temp[4], temp_scale );
1136        temp[5] = FT_DivFix( temp[5], temp_scale );
1137        temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
1138      }
1139  
1140      matrix->xx = temp[0];
1141      matrix->yx = temp[1];
1142      matrix->xy = temp[2];
1143      matrix->yy = temp[3];
1144  
1145      /* note that the offsets must be expressed in integer font units */
1146      offset->x = temp[4] >> 16;
1147      offset->y = temp[5] >> 16;
1148    }
1149  
1150  
1151    static void
parse_encoding(T1_Face face,T1_Loader loader)1152    parse_encoding( T1_Face    face,
1153                    T1_Loader  loader )
1154    {
1155      T1_Parser  parser = &loader->parser;
1156      FT_Byte*   cur;
1157      FT_Byte*   limit  = parser->root.limit;
1158  
1159      PSAux_Service  psaux = (PSAux_Service)face->psaux;
1160  
1161  
1162      T1_Skip_Spaces( parser );
1163      cur = parser->root.cursor;
1164      if ( cur >= limit )
1165      {
1166        FT_ERROR(( "parse_encoding: out of bounds\n" ));
1167        parser->root.error = FT_THROW( Invalid_File_Format );
1168        return;
1169      }
1170  
1171      /* if we have a number or `[', the encoding is an array, */
1172      /* and we must load it now                               */
1173      if ( ft_isdigit( *cur ) || *cur == '[' )
1174      {
1175        T1_Encoding  encode          = &face->type1.encoding;
1176        FT_Int       count, n;
1177        PS_Table     char_table      = &loader->encoding_table;
1178        FT_Memory    memory          = parser->root.memory;
1179        FT_Error     error;
1180        FT_Bool      only_immediates = 0;
1181  
1182  
1183        /* read the number of entries in the encoding; should be 256 */
1184        if ( *cur == '[' )
1185        {
1186          count           = 256;
1187          only_immediates = 1;
1188          parser->root.cursor++;
1189        }
1190        else
1191          count = (FT_Int)T1_ToInt( parser );
1192  
1193        T1_Skip_Spaces( parser );
1194        if ( parser->root.cursor >= limit )
1195          return;
1196  
1197        /* we use a T1_Table to store our charnames */
1198        loader->num_chars = encode->num_chars = count;
1199        if ( FT_NEW_ARRAY( encode->char_index, count )     ||
1200             FT_NEW_ARRAY( encode->char_name,  count )     ||
1201             FT_SET_ERROR( psaux->ps_table_funcs->init(
1202                             char_table, count, memory ) ) )
1203        {
1204          parser->root.error = error;
1205          return;
1206        }
1207  
1208        /* We need to `zero' out encoding_table.elements */
1209        for ( n = 0; n < count; n++ )
1210        {
1211          char*  notdef = (char *)".notdef";
1212  
1213  
1214          (void)T1_Add_Table( char_table, n, notdef, 8 );
1215        }
1216  
1217        /* Now we need to read records of the form                */
1218        /*                                                        */
1219        /*   ... charcode /charname ...                           */
1220        /*                                                        */
1221        /* for each entry in our table.                           */
1222        /*                                                        */
1223        /* We simply look for a number followed by an immediate   */
1224        /* name.  Note that this ignores correctly the sequence   */
1225        /* that is often seen in type1 fonts:                     */
1226        /*                                                        */
1227        /*   0 1 255 { 1 index exch /.notdef put } for dup        */
1228        /*                                                        */
1229        /* used to clean the encoding array before anything else. */
1230        /*                                                        */
1231        /* Alternatively, if the array is directly given as       */
1232        /*                                                        */
1233        /*   /Encoding [ ... ]                                    */
1234        /*                                                        */
1235        /* we only read immediates.                               */
1236  
1237        n = 0;
1238        T1_Skip_Spaces( parser );
1239  
1240        while ( parser->root.cursor < limit )
1241        {
1242          cur = parser->root.cursor;
1243  
1244          /* we stop when we encounter a `def' or `]' */
1245          if ( *cur == 'd' && cur + 3 < limit )
1246          {
1247            if ( cur[1] == 'e'         &&
1248                 cur[2] == 'f'         &&
1249                 IS_PS_DELIM( cur[3] ) )
1250            {
1251              FT_TRACE6(( "encoding end\n" ));
1252              cur += 3;
1253              break;
1254            }
1255          }
1256          if ( *cur == ']' )
1257          {
1258            FT_TRACE6(( "encoding end\n" ));
1259            cur++;
1260            break;
1261          }
1262  
1263          /* check whether we've found an entry */
1264          if ( ft_isdigit( *cur ) || only_immediates )
1265          {
1266            FT_Int  charcode;
1267  
1268  
1269            if ( only_immediates )
1270              charcode = n;
1271            else
1272            {
1273              charcode = (FT_Int)T1_ToInt( parser );
1274              T1_Skip_Spaces( parser );
1275  
1276              /* protect against invalid charcode */
1277              if ( cur == parser->root.cursor )
1278              {
1279                parser->root.error = FT_THROW( Unknown_File_Format );
1280                return;
1281              }
1282            }
1283  
1284            cur = parser->root.cursor;
1285  
1286            if ( cur + 2 < limit && *cur == '/' && n < count )
1287            {
1288              FT_PtrDist  len;
1289  
1290  
1291              cur++;
1292  
1293              parser->root.cursor = cur;
1294              T1_Skip_PS_Token( parser );
1295              if ( parser->root.cursor >= limit )
1296                return;
1297              if ( parser->root.error )
1298                return;
1299  
1300              len = parser->root.cursor - cur;
1301  
1302              parser->root.error = T1_Add_Table( char_table, charcode,
1303                                                 cur, len + 1 );
1304              if ( parser->root.error )
1305                return;
1306              char_table->elements[charcode][len] = '\0';
1307  
1308              n++;
1309            }
1310            else if ( only_immediates )
1311            {
1312              /* Since the current position is not updated for           */
1313              /* immediates-only mode we would get an infinite loop if   */
1314              /* we don't do anything here.                              */
1315              /*                                                         */
1316              /* This encoding array is not valid according to the type1 */
1317              /* specification (it might be an encoding for a CID type1  */
1318              /* font, however), so we conclude that this font is NOT a  */
1319              /* type1 font.                                             */
1320              parser->root.error = FT_THROW( Unknown_File_Format );
1321              return;
1322            }
1323          }
1324          else
1325          {
1326            T1_Skip_PS_Token( parser );
1327            if ( parser->root.error )
1328              return;
1329          }
1330  
1331          T1_Skip_Spaces( parser );
1332        }
1333  
1334        face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
1335        parser->root.cursor       = cur;
1336      }
1337  
1338      /* Otherwise, we should have either `StandardEncoding', */
1339      /* `ExpertEncoding', or `ISOLatin1Encoding'             */
1340      else
1341      {
1342        if ( cur + 17 < limit                                            &&
1343             ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
1344          face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
1345  
1346        else if ( cur + 15 < limit                                          &&
1347                  ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
1348          face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
1349  
1350        else if ( cur + 18 < limit                                             &&
1351                  ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
1352          face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
1353  
1354        else
1355          parser->root.error = FT_ERR( Ignore );
1356      }
1357    }
1358  
1359  
1360    static void
parse_subrs(T1_Face face,T1_Loader loader)1361    parse_subrs( T1_Face    face,
1362                 T1_Loader  loader )
1363    {
1364      T1_Parser  parser = &loader->parser;
1365      PS_Table   table  = &loader->subrs;
1366      FT_Memory  memory = parser->root.memory;
1367      FT_Error   error;
1368      FT_Int     num_subrs;
1369  
1370      PSAux_Service  psaux = (PSAux_Service)face->psaux;
1371  
1372  
1373      T1_Skip_Spaces( parser );
1374  
1375      /* test for empty array */
1376      if ( parser->root.cursor < parser->root.limit &&
1377           *parser->root.cursor == '['              )
1378      {
1379        T1_Skip_PS_Token( parser );
1380        T1_Skip_Spaces  ( parser );
1381        if ( parser->root.cursor >= parser->root.limit ||
1382             *parser->root.cursor != ']'               )
1383          parser->root.error = FT_THROW( Invalid_File_Format );
1384        return;
1385      }
1386  
1387      num_subrs = (FT_Int)T1_ToInt( parser );
1388  
1389      /* position the parser right before the `dup' of the first subr */
1390      T1_Skip_PS_Token( parser );         /* `array' */
1391      if ( parser->root.error )
1392        return;
1393      T1_Skip_Spaces( parser );
1394  
1395      /* initialize subrs array -- with synthetic fonts it is possible */
1396      /* we get here twice                                             */
1397      if ( !loader->num_subrs )
1398      {
1399        error = psaux->ps_table_funcs->init( table, num_subrs, memory );
1400        if ( error )
1401          goto Fail;
1402      }
1403  
1404      /* the format is simple:   */
1405      /*                         */
1406      /*   `index' + binary data */
1407      /*                         */
1408      for (;;)
1409      {
1410        FT_Long   idx, size;
1411        FT_Byte*  base;
1412  
1413  
1414        /* If we are out of data, or if the next token isn't `dup', */
1415        /* we are done.                                             */
1416        if ( parser->root.cursor + 4 >= parser->root.limit          ||
1417            ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
1418          break;
1419  
1420        T1_Skip_PS_Token( parser );       /* `dup' */
1421  
1422        idx = T1_ToInt( parser );
1423  
1424        if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
1425          return;
1426  
1427        /* The binary string is followed by one token, e.g. `NP' */
1428        /* (bound to `noaccess put') or by two separate tokens:  */
1429        /* `noaccess' & `put'.  We position the parser right     */
1430        /* before the next `dup', if any.                        */
1431        T1_Skip_PS_Token( parser );   /* `NP' or `|' or `noaccess' */
1432        if ( parser->root.error )
1433          return;
1434        T1_Skip_Spaces  ( parser );
1435  
1436        if ( parser->root.cursor + 4 < parser->root.limit            &&
1437             ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
1438        {
1439          T1_Skip_PS_Token( parser ); /* skip `put' */
1440          T1_Skip_Spaces  ( parser );
1441        }
1442  
1443        /* with synthetic fonts it is possible we get here twice */
1444        if ( loader->num_subrs )
1445          continue;
1446  
1447        /* some fonts use a value of -1 for lenIV to indicate that */
1448        /* the charstrings are unencoded                           */
1449        /*                                                         */
1450        /* thanks to Tom Kacvinsky for pointing this out           */
1451        /*                                                         */
1452        if ( face->type1.private_dict.lenIV >= 0 )
1453        {
1454          FT_Byte*  temp;
1455  
1456  
1457          /* some fonts define empty subr records -- this is not totally */
1458          /* compliant to the specification (which says they should at   */
1459          /* least contain a `return'), but we support them anyway       */
1460          if ( size < face->type1.private_dict.lenIV )
1461          {
1462            error = FT_THROW( Invalid_File_Format );
1463            goto Fail;
1464          }
1465  
1466          /* t1_decrypt() shouldn't write to base -- make temporary copy */
1467          if ( FT_ALLOC( temp, size ) )
1468            goto Fail;
1469          FT_MEM_COPY( temp, base, size );
1470          psaux->t1_decrypt( temp, size, 4330 );
1471          size -= face->type1.private_dict.lenIV;
1472          error = T1_Add_Table( table, (FT_Int)idx,
1473                                temp + face->type1.private_dict.lenIV, size );
1474          FT_FREE( temp );
1475        }
1476        else
1477          error = T1_Add_Table( table, (FT_Int)idx, base, size );
1478        if ( error )
1479          goto Fail;
1480      }
1481  
1482      if ( !loader->num_subrs )
1483        loader->num_subrs = num_subrs;
1484  
1485      return;
1486  
1487    Fail:
1488      parser->root.error = error;
1489    }
1490  
1491  
1492  #define TABLE_EXTEND  5
1493  
1494  
1495    static void
parse_charstrings(T1_Face face,T1_Loader loader)1496    parse_charstrings( T1_Face    face,
1497                       T1_Loader  loader )
1498    {
1499      T1_Parser      parser       = &loader->parser;
1500      PS_Table       code_table   = &loader->charstrings;
1501      PS_Table       name_table   = &loader->glyph_names;
1502      PS_Table       swap_table   = &loader->swap_table;
1503      FT_Memory      memory       = parser->root.memory;
1504      FT_Error       error;
1505  
1506      PSAux_Service  psaux        = (PSAux_Service)face->psaux;
1507  
1508      FT_Byte*       cur;
1509      FT_Byte*       limit        = parser->root.limit;
1510      FT_Int         n, num_glyphs;
1511      FT_UInt        notdef_index = 0;
1512      FT_Byte        notdef_found = 0;
1513  
1514  
1515      num_glyphs = (FT_Int)T1_ToInt( parser );
1516      if ( num_glyphs < 0 )
1517      {
1518        error = FT_THROW( Invalid_File_Format );
1519        goto Fail;
1520      }
1521  
1522      /* some fonts like Optima-Oblique not only define the /CharStrings */
1523      /* array but access it also                                        */
1524      if ( num_glyphs == 0 || parser->root.error )
1525        return;
1526  
1527      /* initialize tables, leaving space for addition of .notdef, */
1528      /* if necessary, and a few other glyphs to handle buggy      */
1529      /* fonts which have more glyphs than specified.              */
1530  
1531      /* for some non-standard fonts like `Optima' which provides  */
1532      /* different outlines depending on the resolution it is      */
1533      /* possible to get here twice                                */
1534      if ( !loader->num_glyphs )
1535      {
1536        error = psaux->ps_table_funcs->init(
1537                  code_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1538        if ( error )
1539          goto Fail;
1540  
1541        error = psaux->ps_table_funcs->init(
1542                  name_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1543        if ( error )
1544          goto Fail;
1545  
1546        /* Initialize table for swapping index notdef_index and */
1547        /* index 0 names and codes (if necessary).              */
1548  
1549        error = psaux->ps_table_funcs->init( swap_table, 4, memory );
1550        if ( error )
1551          goto Fail;
1552      }
1553  
1554      n = 0;
1555  
1556      for (;;)
1557      {
1558        FT_Long   size;
1559        FT_Byte*  base;
1560  
1561  
1562        /* the format is simple:        */
1563        /*   `/glyphname' + binary data */
1564  
1565        T1_Skip_Spaces( parser );
1566  
1567        cur = parser->root.cursor;
1568        if ( cur >= limit )
1569          break;
1570  
1571        /* we stop when we find a `def' or `end' keyword */
1572        if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) )
1573        {
1574          if ( cur[0] == 'd' &&
1575               cur[1] == 'e' &&
1576               cur[2] == 'f' )
1577          {
1578            /* There are fonts which have this: */
1579            /*                                  */
1580            /*   /CharStrings 118 dict def      */
1581            /*   Private begin                  */
1582            /*   CharStrings begin              */
1583            /*   ...                            */
1584            /*                                  */
1585            /* To catch this we ignore `def' if */
1586            /* no charstring has actually been  */
1587            /* seen.                            */
1588            if ( n )
1589              break;
1590          }
1591  
1592          if ( cur[0] == 'e' &&
1593               cur[1] == 'n' &&
1594               cur[2] == 'd' )
1595            break;
1596        }
1597  
1598        T1_Skip_PS_Token( parser );
1599        if ( parser->root.cursor >= limit )
1600        {
1601          error = FT_THROW( Invalid_File_Format );
1602          goto Fail;
1603        }
1604        if ( parser->root.error )
1605          return;
1606  
1607        if ( *cur == '/' )
1608        {
1609          FT_PtrDist  len;
1610  
1611  
1612          if ( cur + 2 >= limit )
1613          {
1614            error = FT_THROW( Invalid_File_Format );
1615            goto Fail;
1616          }
1617  
1618          cur++;                              /* skip `/' */
1619          len = parser->root.cursor - cur;
1620  
1621          if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
1622            return;
1623  
1624          /* for some non-standard fonts like `Optima' which provides */
1625          /* different outlines depending on the resolution it is     */
1626          /* possible to get here twice                               */
1627          if ( loader->num_glyphs )
1628            continue;
1629  
1630          error = T1_Add_Table( name_table, n, cur, len + 1 );
1631          if ( error )
1632            goto Fail;
1633  
1634          /* add a trailing zero to the name table */
1635          name_table->elements[n][len] = '\0';
1636  
1637          /* record index of /.notdef */
1638          if ( *cur == '.'                                              &&
1639               ft_strcmp( ".notdef",
1640                          (const char*)(name_table->elements[n]) ) == 0 )
1641          {
1642            notdef_index = n;
1643            notdef_found = 1;
1644          }
1645  
1646          if ( face->type1.private_dict.lenIV >= 0 &&
1647               n < num_glyphs + TABLE_EXTEND       )
1648          {
1649            FT_Byte*  temp;
1650  
1651  
1652            if ( size <= face->type1.private_dict.lenIV )
1653            {
1654              error = FT_THROW( Invalid_File_Format );
1655              goto Fail;
1656            }
1657  
1658            /* t1_decrypt() shouldn't write to base -- make temporary copy */
1659            if ( FT_ALLOC( temp, size ) )
1660              goto Fail;
1661            FT_MEM_COPY( temp, base, size );
1662            psaux->t1_decrypt( temp, size, 4330 );
1663            size -= face->type1.private_dict.lenIV;
1664            error = T1_Add_Table( code_table, n,
1665                                  temp + face->type1.private_dict.lenIV, size );
1666            FT_FREE( temp );
1667          }
1668          else
1669            error = T1_Add_Table( code_table, n, base, size );
1670          if ( error )
1671            goto Fail;
1672  
1673          n++;
1674        }
1675      }
1676  
1677      loader->num_glyphs = n;
1678  
1679      /* if /.notdef is found but does not occupy index 0, do our magic. */
1680      if ( notdef_found                                                 &&
1681           ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
1682      {
1683        /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
1684        /* name and code entries to swap_table.  Then place notdef_index   */
1685        /* name and code entries into swap_table.  Then swap name and code */
1686        /* entries at indices notdef_index and 0 using values stored in    */
1687        /* swap_table.                                                     */
1688  
1689        /* Index 0 name */
1690        error = T1_Add_Table( swap_table, 0,
1691                              name_table->elements[0],
1692                              name_table->lengths [0] );
1693        if ( error )
1694          goto Fail;
1695  
1696        /* Index 0 code */
1697        error = T1_Add_Table( swap_table, 1,
1698                              code_table->elements[0],
1699                              code_table->lengths [0] );
1700        if ( error )
1701          goto Fail;
1702  
1703        /* Index notdef_index name */
1704        error = T1_Add_Table( swap_table, 2,
1705                              name_table->elements[notdef_index],
1706                              name_table->lengths [notdef_index] );
1707        if ( error )
1708          goto Fail;
1709  
1710        /* Index notdef_index code */
1711        error = T1_Add_Table( swap_table, 3,
1712                              code_table->elements[notdef_index],
1713                              code_table->lengths [notdef_index] );
1714        if ( error )
1715          goto Fail;
1716  
1717        error = T1_Add_Table( name_table, notdef_index,
1718                              swap_table->elements[0],
1719                              swap_table->lengths [0] );
1720        if ( error )
1721          goto Fail;
1722  
1723        error = T1_Add_Table( code_table, notdef_index,
1724                              swap_table->elements[1],
1725                              swap_table->lengths [1] );
1726        if ( error )
1727          goto Fail;
1728  
1729        error = T1_Add_Table( name_table, 0,
1730                              swap_table->elements[2],
1731                              swap_table->lengths [2] );
1732        if ( error )
1733          goto Fail;
1734  
1735        error = T1_Add_Table( code_table, 0,
1736                              swap_table->elements[3],
1737                              swap_table->lengths [3] );
1738        if ( error )
1739          goto Fail;
1740  
1741      }
1742      else if ( !notdef_found )
1743      {
1744        /* notdef_index is already 0, or /.notdef is undefined in   */
1745        /* charstrings dictionary.  Worry about /.notdef undefined. */
1746        /* We take index 0 and add it to the end of the table(s)    */
1747        /* and add our own /.notdef glyph to index 0.               */
1748  
1749        /* 0 333 hsbw endchar */
1750        FT_Byte  notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E };
1751        char*    notdef_name    = (char *)".notdef";
1752  
1753  
1754        error = T1_Add_Table( swap_table, 0,
1755                              name_table->elements[0],
1756                              name_table->lengths [0] );
1757        if ( error )
1758          goto Fail;
1759  
1760        error = T1_Add_Table( swap_table, 1,
1761                              code_table->elements[0],
1762                              code_table->lengths [0] );
1763        if ( error )
1764          goto Fail;
1765  
1766        error = T1_Add_Table( name_table, 0, notdef_name, 8 );
1767        if ( error )
1768          goto Fail;
1769  
1770        error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
1771  
1772        if ( error )
1773          goto Fail;
1774  
1775        error = T1_Add_Table( name_table, n,
1776                              swap_table->elements[0],
1777                              swap_table->lengths [0] );
1778        if ( error )
1779          goto Fail;
1780  
1781        error = T1_Add_Table( code_table, n,
1782                              swap_table->elements[1],
1783                              swap_table->lengths [1] );
1784        if ( error )
1785          goto Fail;
1786  
1787        /* we added a glyph. */
1788        loader->num_glyphs += 1;
1789      }
1790  
1791      return;
1792  
1793    Fail:
1794      parser->root.error = error;
1795    }
1796  
1797  
1798    /*************************************************************************/
1799    /*                                                                       */
1800    /* Define the token field static variables.  This is a set of            */
1801    /* T1_FieldRec variables.                                                */
1802    /*                                                                       */
1803    /*************************************************************************/
1804  
1805  
1806    static
1807    const T1_FieldRec  t1_keywords[] =
1808    {
1809  
1810  #include "t1tokens.h"
1811  
1812      /* now add the special functions... */
1813      T1_FIELD_CALLBACK( "FontMatrix",           t1_parse_font_matrix,
1814                         T1_FIELD_DICT_FONTDICT )
1815      T1_FIELD_CALLBACK( "Encoding",             parse_encoding,
1816                         T1_FIELD_DICT_FONTDICT )
1817      T1_FIELD_CALLBACK( "Subrs",                parse_subrs,
1818                         T1_FIELD_DICT_PRIVATE )
1819      T1_FIELD_CALLBACK( "CharStrings",          parse_charstrings,
1820                         T1_FIELD_DICT_PRIVATE )
1821      T1_FIELD_CALLBACK( "Private",              parse_private,
1822                         T1_FIELD_DICT_FONTDICT )
1823  
1824  #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
1825      T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions,
1826                         T1_FIELD_DICT_FONTDICT )
1827      T1_FIELD_CALLBACK( "BlendDesignMap",       parse_blend_design_map,
1828                         T1_FIELD_DICT_FONTDICT )
1829      T1_FIELD_CALLBACK( "BlendAxisTypes",       parse_blend_axis_types,
1830                         T1_FIELD_DICT_FONTDICT )
1831      T1_FIELD_CALLBACK( "WeightVector",         parse_weight_vector,
1832                         T1_FIELD_DICT_FONTDICT )
1833      T1_FIELD_CALLBACK( "BuildCharArray",       parse_buildchar,
1834                         T1_FIELD_DICT_PRIVATE )
1835  #endif
1836  
1837      { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
1838    };
1839  
1840  
1841  #define T1_FIELD_COUNT                                           \
1842            ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) )
1843  
1844  
1845    static FT_Error
parse_dict(T1_Face face,T1_Loader loader,FT_Byte * base,FT_Long size)1846    parse_dict( T1_Face    face,
1847                T1_Loader  loader,
1848                FT_Byte*   base,
1849                FT_Long    size )
1850    {
1851      T1_Parser  parser = &loader->parser;
1852      FT_Byte   *limit, *start_binary = NULL;
1853      FT_Bool    have_integer = 0;
1854  
1855  
1856      parser->root.cursor = base;
1857      parser->root.limit  = base + size;
1858      parser->root.error  = FT_Err_Ok;
1859  
1860      limit = parser->root.limit;
1861  
1862      T1_Skip_Spaces( parser );
1863  
1864      while ( parser->root.cursor < limit )
1865      {
1866        FT_Byte*  cur;
1867  
1868  
1869        cur = parser->root.cursor;
1870  
1871        /* look for `eexec' */
1872        if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
1873          break;
1874  
1875        /* look for `closefile' which ends the eexec section */
1876        else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
1877          break;
1878  
1879        /* in a synthetic font the base font starts after a           */
1880        /* `FontDictionary' token that is placed after a Private dict */
1881        else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
1882        {
1883          if ( loader->keywords_encountered & T1_PRIVATE )
1884            loader->keywords_encountered |=
1885              T1_FONTDIR_AFTER_PRIVATE;
1886          parser->root.cursor += 13;
1887        }
1888  
1889        /* check whether we have an integer */
1890        else if ( ft_isdigit( *cur ) )
1891        {
1892          start_binary = cur;
1893          T1_Skip_PS_Token( parser );
1894          if ( parser->root.error )
1895            goto Exit;
1896          have_integer = 1;
1897        }
1898  
1899        /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
1900        /* since those tokens are handled by parse_subrs and        */
1901        /* parse_charstrings                                        */
1902        else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' &&
1903                  have_integer )
1904        {
1905          FT_Long   s;
1906          FT_Byte*  b;
1907  
1908  
1909          parser->root.cursor = start_binary;
1910          if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
1911            return FT_THROW( Invalid_File_Format );
1912          have_integer = 0;
1913        }
1914  
1915        else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' &&
1916                  have_integer )
1917        {
1918          FT_Long   s;
1919          FT_Byte*  b;
1920  
1921  
1922          parser->root.cursor = start_binary;
1923          if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
1924            return FT_THROW( Invalid_File_Format );
1925          have_integer = 0;
1926        }
1927  
1928        /* look for immediates */
1929        else if ( *cur == '/' && cur + 2 < limit )
1930        {
1931          FT_PtrDist  len;
1932  
1933  
1934          cur++;
1935  
1936          parser->root.cursor = cur;
1937          T1_Skip_PS_Token( parser );
1938          if ( parser->root.error )
1939            goto Exit;
1940  
1941          len = parser->root.cursor - cur;
1942  
1943          if ( len > 0 && len < 22 && parser->root.cursor < limit )
1944          {
1945            /* now compare the immediate name to the keyword table */
1946            T1_Field  keyword = (T1_Field)t1_keywords;
1947  
1948  
1949            for (;;)
1950            {
1951              FT_Byte*  name;
1952  
1953  
1954              name = (FT_Byte*)keyword->ident;
1955              if ( !name )
1956                break;
1957  
1958              if ( cur[0] == name[0]                                  &&
1959                   len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
1960                   ft_memcmp( cur, name, len ) == 0                   )
1961              {
1962                /* We found it -- run the parsing callback!     */
1963                /* We record every instance of every field      */
1964                /* (until we reach the base font of a           */
1965                /* synthetic font) to deal adequately with      */
1966                /* multiple master fonts; this is also          */
1967                /* necessary because later PostScript           */
1968                /* definitions override earlier ones.           */
1969  
1970                /* Once we encounter `FontDirectory' after      */
1971                /* `/Private', we know that this is a synthetic */
1972                /* font; except for `/CharStrings' we are not   */
1973                /* interested in anything that follows this     */
1974                /* `FontDirectory'.                             */
1975  
1976                /* MM fonts have more than one /Private token at */
1977                /* the top level; let's hope that all the junk   */
1978                /* that follows the first /Private token is not  */
1979                /* interesting to us.                            */
1980  
1981                /* According to Adobe Tech Note #5175 (CID-Keyed */
1982                /* Font Installation for ATM Software) a `begin' */
1983                /* must be followed by exactly one `end', and    */
1984                /* `begin' -- `end' pairs must be accurately     */
1985                /* paired.  We could use this to distinguish     */
1986                /* between the global Private and the Private    */
1987                /* dict that is a member of the Blend dict.      */
1988  
1989                const FT_UInt dict =
1990                  ( loader->keywords_encountered & T1_PRIVATE )
1991                      ? T1_FIELD_DICT_PRIVATE
1992                      : T1_FIELD_DICT_FONTDICT;
1993  
1994                if ( !( dict & keyword->dict ) )
1995                {
1996                  FT_TRACE1(( "parse_dict: found `%s' but ignoring it"
1997                              " since it is in the wrong dictionary\n",
1998                              keyword->ident ));
1999                  break;
2000                }
2001  
2002                if ( !( loader->keywords_encountered &
2003                        T1_FONTDIR_AFTER_PRIVATE     )                  ||
2004                     ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
2005                {
2006                  parser->root.error = t1_load_keyword( face,
2007                                                        loader,
2008                                                        keyword );
2009                  if ( parser->root.error != FT_Err_Ok )
2010                  {
2011                    if ( FT_ERR_EQ( parser->root.error, Ignore ) )
2012                      parser->root.error = FT_Err_Ok;
2013                    else
2014                      return parser->root.error;
2015                  }
2016                }
2017                break;
2018              }
2019  
2020              keyword++;
2021            }
2022          }
2023  
2024          have_integer = 0;
2025        }
2026        else
2027        {
2028          T1_Skip_PS_Token( parser );
2029          if ( parser->root.error )
2030            goto Exit;
2031          have_integer = 0;
2032        }
2033  
2034        T1_Skip_Spaces( parser );
2035      }
2036  
2037    Exit:
2038      return parser->root.error;
2039    }
2040  
2041  
2042    static void
t1_init_loader(T1_Loader loader,T1_Face face)2043    t1_init_loader( T1_Loader  loader,
2044                    T1_Face    face )
2045    {
2046      FT_UNUSED( face );
2047  
2048      FT_MEM_ZERO( loader, sizeof ( *loader ) );
2049      loader->num_glyphs = 0;
2050      loader->num_chars  = 0;
2051  
2052      /* initialize the tables -- simply set their `init' field to 0 */
2053      loader->encoding_table.init  = 0;
2054      loader->charstrings.init     = 0;
2055      loader->glyph_names.init     = 0;
2056      loader->subrs.init           = 0;
2057      loader->swap_table.init      = 0;
2058      loader->fontdata             = 0;
2059      loader->keywords_encountered = 0;
2060    }
2061  
2062  
2063    static void
t1_done_loader(T1_Loader loader)2064    t1_done_loader( T1_Loader  loader )
2065    {
2066      T1_Parser  parser = &loader->parser;
2067  
2068  
2069      /* finalize tables */
2070      T1_Release_Table( &loader->encoding_table );
2071      T1_Release_Table( &loader->charstrings );
2072      T1_Release_Table( &loader->glyph_names );
2073      T1_Release_Table( &loader->swap_table );
2074      T1_Release_Table( &loader->subrs );
2075  
2076      /* finalize parser */
2077      T1_Finalize_Parser( parser );
2078    }
2079  
2080  
2081    FT_LOCAL_DEF( FT_Error )
T1_Open_Face(T1_Face face)2082    T1_Open_Face( T1_Face  face )
2083    {
2084      T1_LoaderRec   loader;
2085      T1_Parser      parser;
2086      T1_Font        type1 = &face->type1;
2087      PS_Private     priv  = &type1->private_dict;
2088      FT_Error       error;
2089  
2090      PSAux_Service  psaux = (PSAux_Service)face->psaux;
2091  
2092  
2093      t1_init_loader( &loader, face );
2094  
2095      /* default values */
2096      face->ndv_idx          = -1;
2097      face->cdv_idx          = -1;
2098      face->len_buildchar    = 0;
2099  
2100      priv->blue_shift       = 7;
2101      priv->blue_fuzz        = 1;
2102      priv->lenIV            = 4;
2103      priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
2104      priv->blue_scale       = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
2105  
2106      parser = &loader.parser;
2107      error  = T1_New_Parser( parser,
2108                              face->root.stream,
2109                              face->root.memory,
2110                              psaux );
2111      if ( error )
2112        goto Exit;
2113  
2114      error = parse_dict( face, &loader,
2115                          parser->base_dict, parser->base_len );
2116      if ( error )
2117        goto Exit;
2118  
2119      error = T1_Get_Private_Dict( parser, psaux );
2120      if ( error )
2121        goto Exit;
2122  
2123      error = parse_dict( face, &loader,
2124                          parser->private_dict, parser->private_len );
2125      if ( error )
2126        goto Exit;
2127  
2128      /* ensure even-ness of `num_blue_values' */
2129      priv->num_blue_values &= ~1;
2130  
2131  #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
2132  
2133      if ( face->blend                                                     &&
2134           face->blend->num_default_design_vector != 0                     &&
2135           face->blend->num_default_design_vector != face->blend->num_axis )
2136      {
2137        /* we don't use it currently so just warn, reset, and ignore */
2138        FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
2139                   "while there are %u axes.\n",
2140                   face->blend->num_default_design_vector,
2141                   face->blend->num_axis ));
2142  
2143        face->blend->num_default_design_vector = 0;
2144      }
2145  
2146      /* the following can happen for MM instances; we then treat the */
2147      /* font as a normal PS font                                     */
2148      if ( face->blend                                             &&
2149           ( !face->blend->num_designs || !face->blend->num_axis ) )
2150        T1_Done_Blend( face );
2151  
2152      /* another safety check */
2153      if ( face->blend )
2154      {
2155        FT_UInt  i;
2156  
2157  
2158        for ( i = 0; i < face->blend->num_axis; i++ )
2159          if ( !face->blend->design_map[i].num_points )
2160          {
2161            T1_Done_Blend( face );
2162            break;
2163          }
2164      }
2165  
2166      if ( face->blend )
2167      {
2168        if ( face->len_buildchar > 0 )
2169        {
2170          FT_Memory  memory = face->root.memory;
2171  
2172  
2173          if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) )
2174          {
2175            FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" ));
2176            face->len_buildchar = 0;
2177            goto Exit;
2178          }
2179        }
2180      }
2181      else
2182        face->len_buildchar = 0;
2183  
2184  #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
2185  
2186      /* now, propagate the subrs, charstrings, and glyphnames tables */
2187      /* to the Type1 data                                            */
2188      type1->num_glyphs = loader.num_glyphs;
2189  
2190      if ( loader.subrs.init )
2191      {
2192        loader.subrs.init  = 0;
2193        type1->num_subrs   = loader.num_subrs;
2194        type1->subrs_block = loader.subrs.block;
2195        type1->subrs       = loader.subrs.elements;
2196        type1->subrs_len   = loader.subrs.lengths;
2197      }
2198  
2199      if ( !IS_INCREMENTAL )
2200        if ( !loader.charstrings.init )
2201        {
2202          FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
2203          error = FT_THROW( Invalid_File_Format );
2204        }
2205  
2206      loader.charstrings.init  = 0;
2207      type1->charstrings_block = loader.charstrings.block;
2208      type1->charstrings       = loader.charstrings.elements;
2209      type1->charstrings_len   = loader.charstrings.lengths;
2210  
2211      /* we copy the glyph names `block' and `elements' fields; */
2212      /* the `lengths' field must be released later             */
2213      type1->glyph_names_block    = loader.glyph_names.block;
2214      type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
2215      loader.glyph_names.block    = 0;
2216      loader.glyph_names.elements = 0;
2217  
2218      /* we must now build type1.encoding when we have a custom array */
2219      if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
2220      {
2221        FT_Int    charcode, idx, min_char, max_char;
2222        FT_Byte*  glyph_name;
2223  
2224  
2225        /* OK, we do the following: for each element in the encoding  */
2226        /* table, look up the index of the glyph having the same name */
2227        /* the index is then stored in type1.encoding.char_index, and */
2228        /* the name to type1.encoding.char_name                       */
2229  
2230        min_char = 0;
2231        max_char = 0;
2232  
2233        charcode = 0;
2234        for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
2235        {
2236          FT_Byte*  char_name;
2237  
2238  
2239          type1->encoding.char_index[charcode] = 0;
2240          type1->encoding.char_name [charcode] = (char *)".notdef";
2241  
2242          char_name = loader.encoding_table.elements[charcode];
2243          if ( char_name )
2244            for ( idx = 0; idx < type1->num_glyphs; idx++ )
2245            {
2246              glyph_name = (FT_Byte*)type1->glyph_names[idx];
2247              if ( ft_strcmp( (const char*)char_name,
2248                              (const char*)glyph_name ) == 0 )
2249              {
2250                type1->encoding.char_index[charcode] = (FT_UShort)idx;
2251                type1->encoding.char_name [charcode] = (char*)glyph_name;
2252  
2253                /* Change min/max encoded char only if glyph name is */
2254                /* not /.notdef                                      */
2255                if ( ft_strcmp( (const char*)".notdef",
2256                                (const char*)glyph_name ) != 0 )
2257                {
2258                  if ( charcode < min_char )
2259                    min_char = charcode;
2260                  if ( charcode >= max_char )
2261                    max_char = charcode + 1;
2262                }
2263                break;
2264              }
2265            }
2266        }
2267  
2268        type1->encoding.code_first = min_char;
2269        type1->encoding.code_last  = max_char;
2270        type1->encoding.num_chars  = loader.num_chars;
2271      }
2272  
2273    Exit:
2274      t1_done_loader( &loader );
2275      return error;
2276    }
2277  
2278  
2279  /* END */
2280