tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

t1load.c (81827B)


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