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