PageRenderTime 85ms CodeModel.GetById 3ms app.highlight 70ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/type1/t1load.c

https://bitbucket.org/cabalistic/ogredeps/
C | 2243 lines | 1489 code | 446 blank | 308 comment | 327 complexity | 75aa6f88e381913fe040e39a0a1d182e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/***************************************************************************/
   2/*                                                                         */
   3/*  t1load.c                                                               */
   4/*                                                                         */
   5/*    Type 1 font loader (body).                                           */
   6/*                                                                         */
   7/*  Copyright 1996-2012 by                                                 */
   8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
   9/*                                                                         */
  10/*  This file is part of the FreeType project, and may only be used,       */
  11/*  modified, and distributed under the terms of the FreeType project      */
  12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13/*  this file you indicate that you have read the license and              */
  14/*  understand and accept it fully.                                        */
  15/*                                                                         */
  16/***************************************************************************/
  17
  18
  19  /*************************************************************************/
  20  /*                                                                       */
  21  /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
  22  /* old loader has several problems: it is slow, complex, difficult to    */
  23  /* maintain, and contains incredible hacks to make it accept some        */
  24  /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
  25  /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
  26  /*                                                                       */
  27  /* This version is much simpler, much faster and also easier to read and */
  28  /* maintain by a great order of magnitude.  The idea behind it is to     */
  29  /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
  30  /* a Postscript-like interpreter) but rather to perform simple pattern   */
  31  /* matching.                                                             */
  32  /*                                                                       */
  33  /* Indeed, nearly all data definitions follow a simple pattern like      */
  34  /*                                                                       */
  35  /*  ... /Field <data> ...                                                */
  36  /*                                                                       */
  37  /* where <data> can be a number, a boolean, a string, or an array of     */
  38  /* numbers.  There are a few exceptions, namely the encoding, font name, */
  39  /* charstrings, and subrs; they are handled with a special pattern       */
  40  /* matching routine.                                                     */
  41  /*                                                                       */
  42  /* All other common cases are handled very simply.  The matching rules   */
  43  /* are defined in the file `t1tokens.h' through the use of several       */
  44  /* macros calls PARSE_XXX.  This file is included twice here; the first  */
  45  /* time to generate parsing callback functions, the second time to       */
  46  /* generate a table of keywords (with pointers to the associated         */
  47  /* callback functions).                                                  */
  48  /*                                                                       */
  49  /* The function `parse_dict' simply scans *linearly* a given dictionary  */
  50  /* (either the top-level or private one) and calls the appropriate       */
  51  /* callback when it encounters an immediate keyword.                     */
  52  /*                                                                       */
  53  /* This is by far the fastest way one can find to parse and read all     */
  54  /* data.                                                                 */
  55  /*                                                                       */
  56  /* This led to tremendous code size reduction.  Note that later, the     */
  57  /* glyph loader will also be _greatly_ simplified, and the automatic     */
  58  /* hinter will replace the clumsy `t1hinter'.                            */
  59  /*                                                                       */
  60  /*************************************************************************/
  61
  62
  63#include <ft2build.h>
  64#include FT_INTERNAL_DEBUG_H
  65#include FT_CONFIG_CONFIG_H
  66#include FT_MULTIPLE_MASTERS_H
  67#include FT_INTERNAL_TYPE1_TYPES_H
  68#include FT_INTERNAL_CALC_H
  69
  70#include "t1load.h"
  71#include "t1errors.h"
  72
  73
  74  /*************************************************************************/
  75  /*                                                                       */
  76  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  77  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  78  /* messages during execution.                                            */
  79  /*                                                                       */
  80#undef  FT_COMPONENT
  81#define FT_COMPONENT  trace_t1load
  82
  83
  84#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
  85
  86
  87  /*************************************************************************/
  88  /*************************************************************************/
  89  /*****                                                               *****/
  90  /*****                    MULTIPLE MASTERS SUPPORT                   *****/
  91  /*****                                                               *****/
  92  /*************************************************************************/
  93  /*************************************************************************/
  94
  95  static FT_Error
  96  t1_allocate_blend( T1_Face  face,
  97                     FT_UInt  num_designs,
  98                     FT_UInt  num_axis )
  99  {
 100    PS_Blend   blend;
 101    FT_Memory  memory = face->root.memory;
 102    FT_Error   error  = T1_Err_Ok;
 103
 104
 105    blend = face->blend;
 106    if ( !blend )
 107    {
 108      if ( FT_NEW( blend ) )
 109        goto Exit;
 110
 111      blend->num_default_design_vector = 0;
 112
 113      face->blend = blend;
 114    }
 115
 116    /* allocate design data if needed */
 117    if ( num_designs > 0 )
 118    {
 119      if ( blend->num_designs == 0 )
 120      {
 121        FT_UInt  nn;
 122
 123
 124        /* allocate the blend `private' and `font_info' dictionaries */
 125        if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs     ) ||
 126             FT_NEW_ARRAY( blend->privates[1], num_designs       ) ||
 127             FT_NEW_ARRAY( blend->bboxes[1], num_designs         ) ||
 128             FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
 129          goto Exit;
 130
 131        blend->default_weight_vector = blend->weight_vector + num_designs;
 132
 133        blend->font_infos[0] = &face->type1.font_info;
 134        blend->privates  [0] = &face->type1.private_dict;
 135        blend->bboxes    [0] = &face->type1.font_bbox;
 136
 137        for ( nn = 2; nn <= num_designs; nn++ )
 138        {
 139          blend->privates[nn]   = blend->privates  [nn - 1] + 1;
 140          blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
 141          blend->bboxes[nn]     = blend->bboxes    [nn - 1] + 1;
 142        }
 143
 144        blend->num_designs   = num_designs;
 145      }
 146      else if ( blend->num_designs != num_designs )
 147        goto Fail;
 148    }
 149
 150    /* allocate axis data if needed */
 151    if ( num_axis > 0 )
 152    {
 153      if ( blend->num_axis != 0 && blend->num_axis != num_axis )
 154        goto Fail;
 155
 156      blend->num_axis = num_axis;
 157    }
 158
 159    /* allocate the blend design pos table if needed */
 160    num_designs = blend->num_designs;
 161    num_axis    = blend->num_axis;
 162    if ( num_designs && num_axis && blend->design_pos[0] == 0 )
 163    {
 164      FT_UInt  n;
 165
 166
 167      if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
 168        goto Exit;
 169
 170      for ( n = 1; n < num_designs; n++ )
 171        blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
 172    }
 173
 174  Exit:
 175    return error;
 176
 177  Fail:
 178    error = T1_Err_Invalid_File_Format;
 179    goto Exit;
 180  }
 181
 182
 183  FT_LOCAL_DEF( FT_Error )
 184  T1_Get_Multi_Master( T1_Face           face,
 185                       FT_Multi_Master*  master )
 186  {
 187    PS_Blend  blend = face->blend;
 188    FT_UInt   n;
 189    FT_Error  error;
 190
 191
 192    error = T1_Err_Invalid_Argument;
 193
 194    if ( blend )
 195    {
 196      master->num_axis    = blend->num_axis;
 197      master->num_designs = blend->num_designs;
 198
 199      for ( n = 0; n < blend->num_axis; n++ )
 200      {
 201        FT_MM_Axis*   axis = master->axis + n;
 202        PS_DesignMap  map = blend->design_map + n;
 203
 204
 205        axis->name    = blend->axis_names[n];
 206        axis->minimum = map->design_points[0];
 207        axis->maximum = map->design_points[map->num_points - 1];
 208      }
 209
 210      error = T1_Err_Ok;
 211    }
 212
 213    return error;
 214  }
 215
 216
 217  /*************************************************************************/
 218  /*                                                                       */
 219  /* Given a normalized (blend) coordinate, figure out the design          */
 220  /* coordinate appropriate for that value.                                */
 221  /*                                                                       */
 222  FT_LOCAL_DEF( FT_Fixed )
 223  mm_axis_unmap( PS_DesignMap  axismap,
 224                 FT_Fixed      ncv )
 225  {
 226    int  j;
 227
 228
 229    if ( ncv <= axismap->blend_points[0] )
 230      return INT_TO_FIXED( axismap->design_points[0] );
 231
 232    for ( j = 1; j < axismap->num_points; ++j )
 233    {
 234      if ( ncv <= axismap->blend_points[j] )
 235      {
 236        FT_Fixed  t = FT_MulDiv( ncv - axismap->blend_points[j - 1],
 237                                 0x10000L,
 238                                 axismap->blend_points[j] -
 239                                   axismap->blend_points[j - 1] );
 240
 241        return INT_TO_FIXED( axismap->design_points[j - 1] ) +
 242                 FT_MulDiv( t,
 243                            axismap->design_points[j] -
 244                              axismap->design_points[j - 1],
 245                            1L );
 246      }
 247    }
 248
 249    return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
 250  }
 251
 252
 253  /*************************************************************************/
 254  /*                                                                       */
 255  /* Given a vector of weights, one for each design, figure out the        */
 256  /* normalized axis coordinates which gave rise to those weights.         */
 257  /*                                                                       */
 258  FT_LOCAL_DEF( void )
 259  mm_weights_unmap( FT_Fixed*  weights,
 260                    FT_Fixed*  axiscoords,
 261                    FT_UInt    axis_count )
 262  {
 263    FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
 264
 265    if ( axis_count == 1 )
 266      axiscoords[0] = weights[1];
 267
 268    else if ( axis_count == 2 )
 269    {
 270      axiscoords[0] = weights[3] + weights[1];
 271      axiscoords[1] = weights[3] + weights[2];
 272    }
 273
 274    else if ( axis_count == 3 )
 275    {
 276      axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
 277      axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
 278      axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
 279    }
 280
 281    else
 282    {
 283      axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
 284                        weights[7] + weights[5] + weights[3] + weights[1];
 285      axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
 286                        weights[7] + weights[6] + weights[3] + weights[2];
 287      axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
 288                        weights[7] + weights[6] + weights[5] + weights[4];
 289      axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
 290                        weights[11] + weights[10] + weights[9] + weights[8];
 291    }
 292  }
 293
 294
 295  /*************************************************************************/
 296  /*                                                                       */
 297  /* Just a wrapper around T1_Get_Multi_Master to support the different    */
 298  /*  arguments needed by the GX var distortable fonts.                    */
 299  /*                                                                       */
 300  FT_LOCAL_DEF( FT_Error )
 301  T1_Get_MM_Var( T1_Face      face,
 302                 FT_MM_Var*  *master )
 303  {
 304    FT_Memory        memory = face->root.memory;
 305    FT_MM_Var       *mmvar = NULL;
 306    FT_Multi_Master  mmaster;
 307    FT_Error         error;
 308    FT_UInt          i;
 309    FT_Fixed         axiscoords[T1_MAX_MM_AXIS];
 310    PS_Blend         blend = face->blend;
 311
 312
 313    error = T1_Get_Multi_Master( face, &mmaster );
 314    if ( error )
 315      goto Exit;
 316    if ( FT_ALLOC( mmvar,
 317                   sizeof ( FT_MM_Var ) +
 318                     mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
 319      goto Exit;
 320
 321    mmvar->num_axis        = mmaster.num_axis;
 322    mmvar->num_designs     = mmaster.num_designs;
 323    mmvar->num_namedstyles = (FT_UInt)-1;                /* Does not apply */
 324    mmvar->axis            = (FT_Var_Axis*)&mmvar[1];
 325                                      /* Point to axes after MM_Var struct */
 326    mmvar->namedstyle      = NULL;
 327
 328    for ( i = 0 ; i < mmaster.num_axis; ++i )
 329    {
 330      mmvar->axis[i].name    = mmaster.axis[i].name;
 331      mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum);
 332      mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum);
 333      mmvar->axis[i].def     = ( mmvar->axis[i].minimum +
 334                                   mmvar->axis[i].maximum ) / 2;
 335                            /* Does not apply.  But this value is in range */
 336      mmvar->axis[i].strid   = (FT_UInt)-1;    /* Does not apply */
 337      mmvar->axis[i].tag     = (FT_ULong)-1;   /* Does not apply */
 338
 339      if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
 340        mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
 341      else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
 342        mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
 343      else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
 344        mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
 345    }
 346
 347    if ( blend->num_designs == ( 1U << blend->num_axis ) )
 348    {
 349      mm_weights_unmap( blend->default_weight_vector,
 350                        axiscoords,
 351                        blend->num_axis );
 352
 353      for ( i = 0; i < mmaster.num_axis; ++i )
 354        mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
 355                                            axiscoords[i] );
 356    }
 357
 358    *master = mmvar;
 359
 360  Exit:
 361    return error;
 362  }
 363
 364
 365  FT_LOCAL_DEF( FT_Error )
 366  T1_Set_MM_Blend( T1_Face    face,
 367                   FT_UInt    num_coords,
 368                   FT_Fixed*  coords )
 369  {
 370    PS_Blend  blend = face->blend;
 371    FT_Error  error;
 372    FT_UInt   n, m;
 373
 374
 375    error = T1_Err_Invalid_Argument;
 376
 377    if ( blend && blend->num_axis == num_coords )
 378    {
 379      /* recompute the weight vector from the blend coordinates */
 380      error = T1_Err_Ok;
 381
 382      for ( n = 0; n < blend->num_designs; n++ )
 383      {
 384        FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
 385
 386
 387        for ( m = 0; m < blend->num_axis; m++ )
 388        {
 389          FT_Fixed  factor;
 390
 391
 392          /* get current blend axis position */
 393          factor = coords[m];
 394          if ( factor < 0 )        factor = 0;
 395          if ( factor > 0x10000L ) factor = 0x10000L;
 396
 397          if ( ( n & ( 1 << m ) ) == 0 )
 398            factor = 0x10000L - factor;
 399
 400          result = FT_MulFix( result, factor );
 401        }
 402        blend->weight_vector[n] = result;
 403      }
 404
 405      error = T1_Err_Ok;
 406    }
 407
 408    return error;
 409  }
 410
 411
 412  FT_LOCAL_DEF( FT_Error )
 413  T1_Set_MM_Design( T1_Face   face,
 414                    FT_UInt   num_coords,
 415                    FT_Long*  coords )
 416  {
 417    PS_Blend  blend = face->blend;
 418    FT_Error  error;
 419    FT_UInt   n, p;
 420
 421
 422    error = T1_Err_Invalid_Argument;
 423    if ( blend && blend->num_axis == num_coords )
 424    {
 425      /* compute the blend coordinates through the blend design map */
 426      FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
 427
 428
 429      for ( n = 0; n < blend->num_axis; n++ )
 430      {
 431        FT_Long       design  = coords[n];
 432        FT_Fixed      the_blend;
 433        PS_DesignMap  map     = blend->design_map + n;
 434        FT_Long*      designs = map->design_points;
 435        FT_Fixed*     blends  = map->blend_points;
 436        FT_Int        before  = -1, after = -1;
 437
 438
 439        for ( p = 0; p < (FT_UInt)map->num_points; p++ )
 440        {
 441          FT_Long  p_design = designs[p];
 442
 443
 444          /* exact match? */
 445          if ( design == p_design )
 446          {
 447            the_blend = blends[p];
 448            goto Found;
 449          }
 450
 451          if ( design < p_design )
 452          {
 453            after = p;
 454            break;
 455          }
 456
 457          before = p;
 458        }
 459
 460        /* now interpolate if necessary */
 461        if ( before < 0 )
 462          the_blend = blends[0];
 463
 464        else if ( after < 0 )
 465          the_blend = blends[map->num_points - 1];
 466
 467        else
 468          the_blend = FT_MulDiv( design         - designs[before],
 469                                 blends [after] - blends [before],
 470                                 designs[after] - designs[before] );
 471
 472      Found:
 473        final_blends[n] = the_blend;
 474      }
 475
 476      error = T1_Set_MM_Blend( face, num_coords, final_blends );
 477    }
 478
 479    return error;
 480  }
 481
 482
 483  /*************************************************************************/
 484  /*                                                                       */
 485  /* Just a wrapper around T1_Set_MM_Design to support the different       */
 486  /* arguments needed by the GX var distortable fonts.                     */
 487  /*                                                                       */
 488  FT_LOCAL_DEF( FT_Error )
 489  T1_Set_Var_Design( T1_Face    face,
 490                     FT_UInt    num_coords,
 491                     FT_Fixed*  coords )
 492  {
 493     FT_Long   lcoords[4];          /* maximum axis count is 4 */
 494     FT_UInt   i;
 495     FT_Error  error;
 496
 497
 498     error = T1_Err_Invalid_Argument;
 499     if ( num_coords <= 4 && num_coords > 0 )
 500     {
 501       for ( i = 0; i < num_coords; ++i )
 502         lcoords[i] = FIXED_TO_INT( coords[i] );
 503       error = T1_Set_MM_Design( face, num_coords, lcoords );
 504     }
 505
 506     return error;
 507  }
 508
 509
 510  FT_LOCAL_DEF( void )
 511  T1_Done_Blend( T1_Face  face )
 512  {
 513    FT_Memory  memory = face->root.memory;
 514    PS_Blend   blend  = face->blend;
 515
 516
 517    if ( blend )
 518    {
 519      FT_UInt  num_designs = blend->num_designs;
 520      FT_UInt  num_axis    = blend->num_axis;
 521      FT_UInt  n;
 522
 523
 524      /* release design pos table */
 525      FT_FREE( blend->design_pos[0] );
 526      for ( n = 1; n < num_designs; n++ )
 527        blend->design_pos[n] = 0;
 528
 529      /* release blend `private' and `font info' dictionaries */
 530      FT_FREE( blend->privates[1] );
 531      FT_FREE( blend->font_infos[1] );
 532      FT_FREE( blend->bboxes[1] );
 533
 534      for ( n = 0; n < num_designs; n++ )
 535      {
 536        blend->privates  [n] = 0;
 537        blend->font_infos[n] = 0;
 538        blend->bboxes    [n] = 0;
 539      }
 540
 541      /* release weight vectors */
 542      FT_FREE( blend->weight_vector );
 543      blend->default_weight_vector = 0;
 544
 545      /* release axis names */
 546      for ( n = 0; n < num_axis; n++ )
 547        FT_FREE( blend->axis_names[n] );
 548
 549      /* release design map */
 550      for ( n = 0; n < num_axis; n++ )
 551      {
 552        PS_DesignMap  dmap = blend->design_map + n;
 553
 554
 555        FT_FREE( dmap->design_points );
 556        dmap->num_points = 0;
 557      }
 558
 559      FT_FREE( face->blend );
 560    }
 561  }
 562
 563
 564  static void
 565  parse_blend_axis_types( T1_Face    face,
 566                          T1_Loader  loader )
 567  {
 568    T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
 569    FT_Int       n, num_axis;
 570    FT_Error     error = T1_Err_Ok;
 571    PS_Blend     blend;
 572    FT_Memory    memory;
 573
 574
 575    /* take an array of objects */
 576    T1_ToTokenArray( &loader->parser, axis_tokens,
 577                     T1_MAX_MM_AXIS, &num_axis );
 578    if ( num_axis < 0 )
 579    {
 580      error = T1_Err_Ignore;
 581      goto Exit;
 582    }
 583    if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
 584    {
 585      FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
 586                 num_axis ));
 587      error = T1_Err_Invalid_File_Format;
 588      goto Exit;
 589    }
 590
 591    /* allocate blend if necessary */
 592    error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
 593    if ( error )
 594      goto Exit;
 595
 596    blend  = face->blend;
 597    memory = face->root.memory;
 598
 599    /* each token is an immediate containing the name of the axis */
 600    for ( n = 0; n < num_axis; n++ )
 601    {
 602      T1_Token    token = axis_tokens + n;
 603      FT_Byte*    name;
 604      FT_PtrDist  len;
 605
 606
 607      /* skip first slash, if any */
 608      if ( token->start[0] == '/' )
 609        token->start++;
 610
 611      len = token->limit - token->start;
 612      if ( len == 0 )
 613      {
 614        error = T1_Err_Invalid_File_Format;
 615        goto Exit;
 616      }
 617
 618      if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
 619        goto Exit;
 620
 621      name = (FT_Byte*)blend->axis_names[n];
 622      FT_MEM_COPY( name, token->start, len );
 623      name[len] = 0;
 624    }
 625
 626  Exit:
 627    loader->parser.root.error = error;
 628  }
 629
 630
 631  static void
 632  parse_blend_design_positions( T1_Face    face,
 633                                T1_Loader  loader )
 634  {
 635    T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
 636    FT_Int       num_designs;
 637    FT_Int       num_axis;
 638    T1_Parser    parser = &loader->parser;
 639
 640    FT_Error     error = T1_Err_Ok;
 641    PS_Blend     blend;
 642
 643
 644    /* get the array of design tokens -- compute number of designs */
 645    T1_ToTokenArray( parser, design_tokens,
 646                     T1_MAX_MM_DESIGNS, &num_designs );
 647    if ( num_designs < 0 )
 648    {
 649      error = T1_Err_Ignore;
 650      goto Exit;
 651    }
 652    if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
 653    {
 654      FT_ERROR(( "parse_blend_design_positions:"
 655                 " incorrect number of designs: %d\n",
 656                 num_designs ));
 657      error = T1_Err_Invalid_File_Format;
 658      goto Exit;
 659    }
 660
 661    {
 662      FT_Byte*  old_cursor = parser->root.cursor;
 663      FT_Byte*  old_limit  = parser->root.limit;
 664      FT_Int    n;
 665
 666
 667      blend    = face->blend;
 668      num_axis = 0;  /* make compiler happy */
 669
 670      for ( n = 0; n < num_designs; n++ )
 671      {
 672        T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
 673        T1_Token     token;
 674        FT_Int       axis, n_axis;
 675
 676
 677        /* read axis/coordinates tokens */
 678        token = design_tokens + n;
 679        parser->root.cursor = token->start;
 680        parser->root.limit  = token->limit;
 681        T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
 682
 683        if ( n == 0 )
 684        {
 685          if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
 686          {
 687            FT_ERROR(( "parse_blend_design_positions:"
 688                       " invalid number of axes: %d\n",
 689                       n_axis ));
 690            error = T1_Err_Invalid_File_Format;
 691            goto Exit;
 692          }
 693
 694          num_axis = n_axis;
 695          error = t1_allocate_blend( face, num_designs, num_axis );
 696          if ( error )
 697            goto Exit;
 698          blend = face->blend;
 699        }
 700        else if ( n_axis != num_axis )
 701        {
 702          FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
 703          error = T1_Err_Invalid_File_Format;
 704          goto Exit;
 705        }
 706
 707        /* now read each axis token into the design position */
 708        for ( axis = 0; axis < n_axis; axis++ )
 709        {
 710          T1_Token  token2 = axis_tokens + axis;
 711
 712
 713          parser->root.cursor = token2->start;
 714          parser->root.limit  = token2->limit;
 715          blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
 716        }
 717      }
 718
 719      loader->parser.root.cursor = old_cursor;
 720      loader->parser.root.limit  = old_limit;
 721    }
 722
 723  Exit:
 724    loader->parser.root.error = error;
 725  }
 726
 727
 728  static void
 729  parse_blend_design_map( T1_Face    face,
 730                          T1_Loader  loader )
 731  {
 732    FT_Error     error  = T1_Err_Ok;
 733    T1_Parser    parser = &loader->parser;
 734    PS_Blend     blend;
 735    T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
 736    FT_Int       n, num_axis;
 737    FT_Byte*     old_cursor;
 738    FT_Byte*     old_limit;
 739    FT_Memory    memory = face->root.memory;
 740
 741
 742    T1_ToTokenArray( parser, axis_tokens,
 743                     T1_MAX_MM_AXIS, &num_axis );
 744    if ( num_axis < 0 )
 745    {
 746      error = T1_Err_Ignore;
 747      goto Exit;
 748    }
 749    if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
 750    {
 751      FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
 752                 num_axis ));
 753      error = T1_Err_Invalid_File_Format;
 754      goto Exit;
 755    }
 756
 757    old_cursor = parser->root.cursor;
 758    old_limit  = parser->root.limit;
 759
 760    error = t1_allocate_blend( face, 0, num_axis );
 761    if ( error )
 762      goto Exit;
 763    blend = face->blend;
 764
 765    /* now read each axis design map */
 766    for ( n = 0; n < num_axis; n++ )
 767    {
 768      PS_DesignMap  map = blend->design_map + n;
 769      T1_Token      axis_token;
 770      T1_TokenRec   point_tokens[T1_MAX_MM_MAP_POINTS];
 771      FT_Int        p, num_points;
 772
 773
 774      axis_token = axis_tokens + n;
 775
 776      parser->root.cursor = axis_token->start;
 777      parser->root.limit  = axis_token->limit;
 778      T1_ToTokenArray( parser, point_tokens,
 779                       T1_MAX_MM_MAP_POINTS, &num_points );
 780
 781      if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
 782      {
 783        FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
 784        error = T1_Err_Invalid_File_Format;
 785        goto Exit;
 786      }
 787
 788      /* allocate design map data */
 789      if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
 790        goto Exit;
 791      map->blend_points = map->design_points + num_points;
 792      map->num_points   = (FT_Byte)num_points;
 793
 794      for ( p = 0; p < num_points; p++ )
 795      {
 796        T1_Token  point_token;
 797
 798
 799        point_token = point_tokens + p;
 800
 801        /* don't include delimiting brackets */
 802        parser->root.cursor = point_token->start + 1;
 803        parser->root.limit  = point_token->limit - 1;
 804
 805        map->design_points[p] = T1_ToInt( parser );
 806        map->blend_points [p] = T1_ToFixed( parser, 0 );
 807      }
 808    }
 809
 810    parser->root.cursor = old_cursor;
 811    parser->root.limit  = old_limit;
 812
 813  Exit:
 814    parser->root.error = error;
 815  }
 816
 817
 818  static void
 819  parse_weight_vector( T1_Face    face,
 820                       T1_Loader  loader )
 821  {
 822    T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
 823    FT_Int       num_designs;
 824    FT_Error     error  = T1_Err_Ok;
 825    T1_Parser    parser = &loader->parser;
 826    PS_Blend     blend  = face->blend;
 827    T1_Token     token;
 828    FT_Int       n;
 829    FT_Byte*     old_cursor;
 830    FT_Byte*     old_limit;
 831
 832
 833    T1_ToTokenArray( parser, design_tokens,
 834                     T1_MAX_MM_DESIGNS, &num_designs );
 835    if ( num_designs < 0 )
 836    {
 837      error = T1_Err_Ignore;
 838      goto Exit;
 839    }
 840    if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
 841    {
 842      FT_ERROR(( "parse_weight_vector:"
 843                 " incorrect number of designs: %d\n",
 844                 num_designs ));
 845      error = T1_Err_Invalid_File_Format;
 846      goto Exit;
 847    }
 848
 849    if ( !blend || !blend->num_designs )
 850    {
 851      error = t1_allocate_blend( face, num_designs, 0 );
 852      if ( error )
 853        goto Exit;
 854      blend = face->blend;
 855    }
 856    else if ( blend->num_designs != (FT_UInt)num_designs )
 857    {
 858      FT_ERROR(( "parse_weight_vector:"
 859                 " /BlendDesignPosition and /WeightVector have\n"
 860                 "                    "
 861                 " different number of elements\n" ));
 862      error = T1_Err_Invalid_File_Format;
 863      goto Exit;
 864    }
 865
 866    old_cursor = parser->root.cursor;
 867    old_limit  = parser->root.limit;
 868
 869    for ( n = 0; n < num_designs; n++ )
 870    {
 871      token = design_tokens + n;
 872      parser->root.cursor = token->start;
 873      parser->root.limit  = token->limit;
 874
 875      blend->default_weight_vector[n] =
 876      blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
 877    }
 878
 879    parser->root.cursor = old_cursor;
 880    parser->root.limit  = old_limit;
 881
 882  Exit:
 883    parser->root.error = error;
 884  }
 885
 886
 887  /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
 888  /* we're only interested in the number of array elements */
 889  static void
 890  parse_buildchar( T1_Face    face,
 891                   T1_Loader  loader )
 892  {
 893    face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
 894
 895    return;
 896  }
 897
 898
 899#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
 900
 901
 902
 903
 904  /*************************************************************************/
 905  /*************************************************************************/
 906  /*****                                                               *****/
 907  /*****                      TYPE 1 SYMBOL PARSING                    *****/
 908  /*****                                                               *****/
 909  /*************************************************************************/
 910  /*************************************************************************/
 911
 912  static FT_Error
 913  t1_load_keyword( T1_Face         face,
 914                   T1_Loader       loader,
 915                   const T1_Field  field )
 916  {
 917    FT_Error  error;
 918    void*     dummy_object;
 919    void**    objects;
 920    FT_UInt   max_objects;
 921    PS_Blend  blend = face->blend;
 922
 923
 924    if ( blend && blend->num_designs == 0 )
 925      blend = NULL;
 926
 927    /* if the keyword has a dedicated callback, call it */
 928    if ( field->type == T1_FIELD_TYPE_CALLBACK )
 929    {
 930      field->reader( (FT_Face)face, loader );
 931      error = loader->parser.root.error;
 932      goto Exit;
 933    }
 934
 935    /* now, the keyword is either a simple field, or a table of fields; */
 936    /* we are now going to take care of it                              */
 937    switch ( field->location )
 938    {
 939    case T1_FIELD_LOCATION_FONT_INFO:
 940      dummy_object = &face->type1.font_info;
 941      objects      = &dummy_object;
 942      max_objects  = 0;
 943
 944      if ( blend )
 945      {
 946        objects     = (void**)blend->font_infos;
 947        max_objects = blend->num_designs;
 948      }
 949      break;
 950
 951    case T1_FIELD_LOCATION_FONT_EXTRA:
 952      dummy_object = &face->type1.font_extra;
 953      objects      = &dummy_object;
 954      max_objects  = 0;
 955      break;
 956
 957    case T1_FIELD_LOCATION_PRIVATE:
 958      dummy_object = &face->type1.private_dict;
 959      objects      = &dummy_object;
 960      max_objects  = 0;
 961
 962      if ( blend )
 963      {
 964        objects     = (void**)blend->privates;
 965        max_objects = blend->num_designs;
 966      }
 967      break;
 968
 969    case T1_FIELD_LOCATION_BBOX:
 970      dummy_object = &face->type1.font_bbox;
 971      objects      = &dummy_object;
 972      max_objects  = 0;
 973
 974      if ( blend )
 975      {
 976        objects     = (void**)blend->bboxes;
 977        max_objects = blend->num_designs;
 978      }
 979      break;
 980
 981    case T1_FIELD_LOCATION_LOADER:
 982      dummy_object = loader;
 983      objects      = &dummy_object;
 984      max_objects  = 0;
 985      break;
 986
 987    case T1_FIELD_LOCATION_FACE:
 988      dummy_object = face;
 989      objects      = &dummy_object;
 990      max_objects  = 0;
 991      break;
 992
 993#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
 994    case T1_FIELD_LOCATION_BLEND:
 995      dummy_object = face->blend;
 996      objects      = &dummy_object;
 997      max_objects  = 0;
 998      break;
 999#endif
1000
1001    default:
1002      dummy_object = &face->type1;
1003      objects      = &dummy_object;
1004      max_objects  = 0;
1005    }
1006
1007    if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1008         field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1009      error = T1_Load_Field_Table( &loader->parser, field,
1010                                   objects, max_objects, 0 );
1011    else
1012      error = T1_Load_Field( &loader->parser, field,
1013                             objects, max_objects, 0 );
1014
1015  Exit:
1016    return error;
1017  }
1018
1019
1020  static void
1021  parse_private( T1_Face    face,
1022                 T1_Loader  loader )
1023  {
1024    FT_UNUSED( face );
1025
1026    loader->keywords_encountered |= T1_PRIVATE;
1027  }
1028
1029
1030  static int
1031  read_binary_data( T1_Parser  parser,
1032                    FT_Long*   size,
1033                    FT_Byte**  base )
1034  {
1035    FT_Byte*  cur;
1036    FT_Byte*  limit = parser->root.limit;
1037
1038
1039    /* the binary data has one of the following formats */
1040    /*                                                  */
1041    /*   `size' [white*] RD white ....... ND            */
1042    /*   `size' [white*] -| white ....... |-            */
1043    /*                                                  */
1044
1045    T1_Skip_Spaces( parser );
1046
1047    cur = parser->root.cursor;
1048
1049    if ( cur < limit && ft_isdigit( *cur ) )
1050    {
1051      FT_Long  s = T1_ToInt( parser );
1052
1053
1054      T1_Skip_PS_Token( parser );   /* `RD' or `-|' or something else */
1055
1056      /* there is only one whitespace char after the */
1057      /* `RD' or `-|' token                          */
1058      *base = parser->root.cursor + 1;
1059
1060      if ( s >= 0 && s < limit - *base )
1061      {
1062        parser->root.cursor += s + 1;
1063        *size = s;
1064        return !parser->root.error;
1065      }
1066    }
1067
1068    FT_ERROR(( "read_binary_data: invalid size field\n" ));
1069    parser->root.error = T1_Err_Invalid_File_Format;
1070    return 0;
1071  }
1072
1073
1074  /* We now define the routines to handle the `/Encoding', `/Subrs', */
1075  /* and `/CharStrings' dictionaries.                                */
1076
1077  static void
1078  t1_parse_font_matrix( T1_Face    face,
1079                        T1_Loader  loader )
1080  {
1081    T1_Parser   parser = &loader->parser;
1082    FT_Matrix*  matrix = &face->type1.font_matrix;
1083    FT_Vector*  offset = &face->type1.font_offset;
1084    FT_Face     root   = (FT_Face)&face->root;
1085    FT_Fixed    temp[6];
1086    FT_Fixed    temp_scale;
1087    FT_Int      result;
1088
1089
1090    result = T1_ToFixedArray( parser, 6, temp, 3 );
1091
1092    if ( result < 0 )
1093    {
1094      parser->root.error = T1_Err_Invalid_File_Format;
1095      return;
1096    }
1097
1098    temp_scale = FT_ABS( temp[3] );
1099
1100    if ( temp_scale == 0 )
1101    {
1102      FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
1103      parser->root.error = T1_Err_Invalid_File_Format;
1104      return;
1105    }
1106
1107    /* Set Units per EM based on FontMatrix values.  We set the value to */
1108    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
1109    /* 1000 (in t1_tofixed, from psobjs.c).                              */
1110
1111    root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
1112                                                 temp_scale ) >> 16 );
1113
1114    /* we need to scale the values by 1.0/temp_scale */
1115    if ( temp_scale != 0x10000L )
1116    {
1117      temp[0] = FT_DivFix( temp[0], temp_scale );
1118      temp[1] = FT_DivFix( temp[1], temp_scale );
1119      temp[2] = FT_DivFix( temp[2], temp_scale );
1120      temp[4] = FT_DivFix( temp[4], temp_scale );
1121      temp[5] = FT_DivFix( temp[5], temp_scale );
1122      temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
1123    }
1124
1125    matrix->xx = temp[0];
1126    matrix->yx = temp[1];
1127    matrix->xy = temp[2];
1128    matrix->yy = temp[3];
1129
1130    /* note that the offsets must be expressed in integer font units */
1131    offset->x = temp[4] >> 16;
1132    offset->y = temp[5] >> 16;
1133  }
1134
1135
1136  static void
1137  parse_encoding( T1_Face    face,
1138                  T1_Loader  loader )
1139  {
1140    T1_Parser  parser = &loader->parser;
1141    FT_Byte*   cur;
1142    FT_Byte*   limit  = parser->root.limit;
1143
1144    PSAux_Service  psaux = (PSAux_Service)face->psaux;
1145
1146
1147    T1_Skip_Spaces( parser );
1148    cur = parser->root.cursor;
1149    if ( cur >= limit )
1150    {
1151      FT_ERROR(( "parse_encoding: out of bounds\n" ));
1152      parser->root.error = T1_Err_Invalid_File_Format;
1153      return;
1154    }
1155
1156    /* if we have a number or `[', the encoding is an array, */
1157    /* and we must load it now                               */
1158    if ( ft_isdigit( *cur ) || *cur == '[' )
1159    {
1160      T1_Encoding  encode          = &face->type1.encoding;
1161      FT_Int       count, n;
1162      PS_Table     char_table      = &loader->encoding_table;
1163      FT_Memory    memory          = parser->root.memory;
1164      FT_Error     error;
1165      FT_Bool      only_immediates = 0;
1166
1167
1168      /* read the number of entries in the encoding; should be 256 */
1169      if ( *cur == '[' )
1170      {
1171        count           = 256;
1172        only_immediates = 1;
1173        parser->root.cursor++;
1174      }
1175      else
1176        count = (FT_Int)T1_ToInt( parser );
1177
1178      T1_Skip_Spaces( parser );
1179      if ( parser->root.cursor >= limit )
1180        return;
1181
1182      /* we use a T1_Table to store our charnames */
1183      loader->num_chars = encode->num_chars = count;
1184      if ( FT_NEW_ARRAY( encode->char_index, count )     ||
1185           FT_NEW_ARRAY( encode->char_name,  count )     ||
1186           FT_SET_ERROR( psaux->ps_table_funcs->init(
1187                           char_table, count, memory ) ) )
1188      {
1189        parser->root.error = error;
1190        return;
1191      }
1192
1193      /* We need to `zero' out encoding_table.elements */
1194      for ( n = 0; n < count; n++ )
1195      {
1196        char*  notdef = (char *)".notdef";
1197
1198
1199        T1_Add_Table( char_table, n, notdef, 8 );
1200      }
1201
1202      /* Now we need to read records of the form                */
1203      /*                                                        */
1204      /*   ... charcode /charname ...                           */
1205      /*                                                        */
1206      /* for each entry in our table.                           */
1207      /*                                                        */
1208      /* We simply look for a number followed by an immediate   */
1209      /* name.  Note that this ignores correctly the sequence   */
1210      /* that is often seen in type1 fonts:                     */
1211      /*                                                        */
1212      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
1213      /*                                                        */
1214      /* used to clean the encoding array before anything else. */
1215      /*                                                        */
1216      /* Alternatively, if the array is directly given as       */
1217      /*                                                        */
1218      /*   /Encoding [ ... ]                                    */
1219      /*                                                        */
1220      /* we only read immediates.                               */
1221
1222      n = 0;
1223      T1_Skip_Spaces( parser );
1224
1225      while ( parser->root.cursor < limit )
1226      {
1227        cur = parser->root.cursor;
1228
1229        /* we stop when we encounter a `def' or `]' */
1230        if ( *cur == 'd' && cur + 3 < limit )
1231        {
1232          if ( cur[1] == 'e'         &&
1233               cur[2] == 'f'         &&
1234               IS_PS_DELIM( cur[3] ) )
1235          {
1236            FT_TRACE6(( "encoding end\n" ));
1237            cur += 3;
1238            break;
1239          }
1240        }
1241        if ( *cur == ']' )
1242        {
1243          FT_TRACE6(( "encoding end\n" ));
1244          cur++;
1245          break;
1246        }
1247
1248        /* check whether we've found an entry */
1249        if ( ft_isdigit( *cur ) || only_immediates )
1250        {
1251          FT_Int  charcode;
1252
1253
1254          if ( only_immediates )
1255            charcode = n;
1256          else
1257          {
1258            charcode = (FT_Int)T1_ToInt( parser );
1259            T1_Skip_Spaces( parser );
1260          }
1261
1262          cur = parser->root.cursor;
1263
1264          if ( *cur == '/' && cur + 2 < limit && n < count )
1265          {
1266            FT_PtrDist  len;
1267
1268
1269            cur++;
1270
1271            parser->root.cursor = cur;
1272            T1_Skip_PS_Token( parser );
1273            if ( parser->root.error )
1274              return;
1275
1276            len = parser->root.cursor - cur;
1277
1278            parser->root.error = T1_Add_Table( char_table, charcode,
1279                                               cur, len + 1 );
1280            if ( parser->root.error )
1281              return;
1282            char_table->elements[charcode][len] = '\0';
1283
1284            n++;
1285          }
1286          else if ( only_immediates )
1287          {
1288            /* Since the current position is not updated for           */
1289            /* immediates-only mode we would get an infinite loop if   */
1290            /* we don't do anything here.                              */
1291            /*                                                         */
1292            /* This encoding array is not valid according to the type1 */
1293            /* specification (it might be an encoding for a CID type1  */
1294            /* font, however), so we conclude that this font is NOT a  */
1295            /* type1 font.                                             */
1296            parser->root.error = FT_Err_Unknown_File_Format;
1297            return;
1298          }
1299        }
1300        else
1301        {
1302          T1_Skip_PS_Token( parser );
1303          if ( parser->root.error )
1304            return;
1305        }
1306
1307        T1_Skip_Spaces( parser );
1308      }
1309
1310      face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
1311      parser->root.cursor       = cur;
1312    }
1313
1314    /* Otherwise, we should have either `StandardEncoding', */
1315    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
1316    else
1317    {
1318      if ( cur + 17 < limit                                            &&
1319           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
1320        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
1321
1322      else if ( cur + 15 < limit                                          &&
1323                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
1324        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
1325
1326      else if ( cur + 18 < limit                                             &&
1327                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
1328        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
1329
1330      else
1331        parser->root.error = T1_Err_Ignore;
1332    }
1333  }
1334
1335
1336  static void
1337  parse_subrs( T1_Face    face,
1338               T1_Loader  loader )
1339  {
1340    T1_Parser  parser = &loader->parser;
1341    PS_Table   table  = &loader->subrs;
1342    FT_Memory  memory = parser->root.memory;
1343    FT_Error   error;
1344    FT_Int     num_subrs;
1345
1346    PSAux_Service  psaux = (PSAux_Service)face->psaux;
1347
1348
1349    T1_Skip_Spaces( parser );
1350
1351    /* test for empty array */
1352    if ( parser->root.cursor < parser->root.limit &&
1353         *parser->root.cursor == '['              )
1354    {
1355      T1_Skip_PS_Token( parser );
1356      T1_Skip_Spaces  ( parser );
1357      if ( parser->root.cursor >= parser->root.limit ||
1358           *parser->root.cursor != ']'               )
1359        parser->root.error = T1_Err_Invalid_File_Format;
1360      return;
1361    }
1362
1363    num_subrs = (FT_Int)T1_ToInt( parser );
1364
1365    /* position the parser right before the `dup' of the first subr */
1366    T1_Skip_PS_Token( parser );         /* `array' */
1367    if ( parser->root.error )
1368      return;
1369    T1_Skip_Spaces( parser );
1370
1371    /* initialize subrs array -- with synthetic fonts it is possible */
1372    /* we get here twice                                             */
1373    if ( !loader->num_subrs )
1374    {
1375      error = psaux->ps_table_funcs->init( table, num_subrs, memory );
1376      if ( error )
1377        goto Fail;
1378    }
1379
1380    /* the format is simple:   */
1381    /*                         */
1382    /*   `index' + binary data */
1383    /*                         */
1384    for (;;)
1385    {
1386      FT_Long   idx, size;
1387      FT_Byte*  base;
1388
1389
1390      /* If the next token isn't `dup' we are done. */
1391      if ( parser->root.cursor + 4 < parser->root.limit            &&
1392           ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
1393        break;
1394
1395      T1_Skip_PS_Token( parser );       /* `dup' */
1396
1397      idx = T1_ToInt( parser );
1398
1399      if ( !read_binary_data( parser, &size, &base ) )
1400        return;
1401
1402      /* The binary string is followed by one token, e.g. `NP' */
1403      /* (bound to `noaccess put') or by two separate tokens:  */
1404      /* `noaccess' & `put'.  We position the parser right     */
1405      /* before the next `dup', if any.                        */
1406      T1_Skip_PS_Token( parser );   /* `NP' or `|' or `noaccess' */
1407      if ( parser->root.error )
1408        return;
1409      T1_Skip_Spaces  ( parser );
1410
1411      if ( parser->root.cursor + 4 < parser->root.limit            &&
1412           ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
1413      {
1414        T1_Skip_PS_Token( parser ); /* skip `put' */
1415        T1_Skip_Spaces  ( parser );
1416      }
1417
1418      /* with synthetic fonts it is possible we get here twice */
1419      if ( loader->num_subrs )
1420        continue;
1421
1422      /* some fonts use a value of -1 for lenIV to indicate that */
1423      /* the charstrings are unencoded                           */
1424      /*                                                         */
1425      /* thanks to Tom Kacvinsky for pointing this out           */
1426      /*                                                         */
1427      if ( face->type1.private_dict.lenIV >= 0 )
1428      {
1429        FT_Byte*  temp;
1430
1431
1432        /* some fonts define empty subr records -- this is not totally */
1433        /* compliant to the specification (which says they should at   */
1434        /* least contain a `return'), but we support them anyway       */
1435        if ( size < face->type1.private_dict.lenIV )
1436        {
1437          error = T1_Err_Invalid_File_Format;
1438          goto Fail;
1439        }
1440
1441        /* t1_decrypt() shouldn't write to base -- make temporary copy */
1442        if ( FT_ALLOC( temp, size ) )
1443          goto Fail;
1444        FT_MEM_COPY( temp, base, size );
1445        psaux->t1_decrypt( temp, size, 4330 );
1446        size -= face->type1.private_dict.lenIV;
1447        error = T1_Add_Table( table, (FT_Int)idx,
1448                              temp + face->type1.private_dict.lenIV, size );
1449        FT_FREE( temp );
1450      }
1451      else
1452        error = T1_Add_Table( table, (FT_Int)idx, base, size );
1453      if ( error )
1454        goto Fail;
1455    }
1456
1457    if ( !loader->num_subrs )
1458      loader->num_subrs = num_subrs;
1459
1460    return;
1461
1462  Fail:
1463    parser->root.error = error;
1464  }
1465
1466
1467#define TABLE_EXTEND  5
1468
1469
1470  static void
1471  parse_charstrings( T1_Face    face,
1472                     T1_Loader  loader )
1473  {
1474    T1_Parser      parser       = &loader->parser;
1475    PS_Table       code_table   = &loader->charstrings;
1476    PS_Table       name_table   = &loader->glyph_names;
1477    PS_Table       swap_table   = &loader->swap_table;
1478    FT_Memory      memory       = parser->root.memory;
1479    FT_Error       error;
1480
1481    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
1482
1483    FT_Byte*       cur;
1484    FT_Byte*       limit        = parser->root.limit;
1485    FT_Int         n, num_glyphs;
1486    FT_UInt        notdef_index = 0;
1487    FT_Byte        notdef_found = 0;
1488
1489
1490    num_glyphs = (FT_Int)T1_ToInt( parser );
1491    /* some fonts like Optima-Oblique not only define the /CharStrings */
1492    /* array but access it also                                        */
1493    if ( num_glyphs == 0 || parser->root.error )
1494      return;
1495
1496    /* initialize tables, leaving space for addition of .notdef, */
1497    /* if necessary, and a few other glyphs to handle buggy      */
1498    /* fonts which have more glyphs than specified.              */
1499
1500    /* for some non-standard fonts like `Optima' which provides  */
1501    /* different outlines depending on the resolution it is      */
1502    /* possible to get here twice                                */
1503    if ( !loader->num_glyphs )
1504    {
1505      error = psaux->ps_table_funcs->init(
1506                code_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1507      if ( error )
1508        goto Fail;
1509
1510      error = psaux->ps_table_funcs->init(
1511                name_table, num_glyphs + 1 + TABLE_EXTEND, memory );
1512      if ( error )
1513        goto Fail;
1514
1515      /* Initialize table for swapping index notdef_index and */
1516      /* index 0 names and codes (if necessary).              */
1517
1518      error = psaux->ps_table_funcs->init( swap_table, 4, memory );
1519      if ( error )
1520        goto Fail;
1521    }
1522
1523    n = 0;
1524
1525    for (;;)
1526    {
1527      FT_Long   size;
1528      FT_Byte*  base;
1529
1530
1531      /* the format is simple:        */
1532      /*   `/glyphname' + binary data */
1533
1534      T1_Skip_Spaces( parser );
1535
1536      cur = parser->root.cursor;
1537      if ( cur >= limit )
1538        break;
1539
1540      /* we stop when we find a `def' or `end' keyword */
1541      if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) )
1542      {
1543        if ( cur[0] == 'd' &&
1544             cur[1] == 'e' &&
1545             cur[2] == 'f' )
1546        {
1547          /* There are fonts which have this: */
1548          /*                                  */
1549          /*   /CharStrings 118 dict def      */
1550          /*   Private begin                  */
1551          /*   CharStrings begin              */
1552          /*   ...                            */
1553          /*                                  */
1554          /* To catch this we ignore `def' if */
1555          /* no charstring has actually been  */
1556          /* seen.                            */
1557          if ( n )
1558            break;
1559        }
1560
1561        if ( cur[0] == 'e' &&
1562             cur[1] == 'n' &&
1563             cur[2] == 'd' )
1564          break;
1565      }
1566
1567      T1_Skip_PS_Token( parser );
1568      if ( parser->root.error )
1569        return;
1570
1571      if ( *cur == '/' )
1572      {
1573        FT_PtrDist  len;
1574
1575
1576        if ( cur + 1 >= limit )
1577        {
1578          error = T1_Err_Invalid_File_Format;
1579          goto Fail;
1580        }
1581
1582        cur++;                              /* skip `/' */
1583        len = parser->root.cursor - cur;
1584
1585        if ( !read_binary_data( parser, &size, &base ) )
1586          return;
1587
1588        /* for some non-standard fonts like `Optima' which provides */
1589        /* different outlines depending on the resolution it is     */
1590        /* possible to get here twice                               */
1591        if ( loader->num_glyphs )
1592          continue;
1593
1594        error = T1_Add_Table( name_table, n, cur, len + 1 );
1595        if ( error )
1596          goto Fail;
1597
1598        /* add a trailing zero to the name table */
1599        name_table->elements[n][len] = '\0';
1600
1601        /* record index of /.notdef */
1602        if ( *cur == '.'                                              &&
1603             ft_strcmp( ".notdef",
1604                        (const char*)(name_table->elements[n]) ) == 0 )
1605        {
1606          notdef_index = n;
1607          notdef_found = 1;
1608        }
1609

Large files files are truncated, but you can click here to view the full file