Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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