source: trunk/poppler/freetype2/src/type1/t1load.c @ 251

Last change on this file since 251 was 251, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.5

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