ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

t1load.c
Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  t1load.c                                                               */
00004 /*                                                                         */
00005 /*    Type 1 font loader (body).                                           */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
00008 /*            2010 by                                                      */
00009 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00010 /*                                                                         */
00011 /*  This file is part of the FreeType project, and may only be used,       */
00012 /*  modified, and distributed under the terms of the FreeType project      */
00013 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00014 /*  this file you indicate that you have read the license and              */
00015 /*  understand and accept it fully.                                        */
00016 /*                                                                         */
00017 /***************************************************************************/
00018 
00019 
00020   /*************************************************************************/
00021   /*                                                                       */
00022   /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
00023   /* old loader has several problems: it is slow, complex, difficult to    */
00024   /* maintain, and contains incredible hacks to make it accept some        */
00025   /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
00026   /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
00027   /*                                                                       */
00028   /* This version is much simpler, much faster and also easier to read and */
00029   /* maintain by a great order of magnitude.  The idea behind it is to     */
00030   /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
00031   /* a Postscript-like interpreter) but rather to perform simple pattern   */
00032   /* matching.                                                             */
00033   /*                                                                       */
00034   /* Indeed, nearly all data definitions follow a simple pattern like      */
00035   /*                                                                       */
00036   /*  ... /Field <data> ...                                                */
00037   /*                                                                       */
00038   /* where <data> can be a number, a boolean, a string, or an array of     */
00039   /* numbers.  There are a few exceptions, namely the encoding, font name, */
00040   /* charstrings, and subrs; they are handled with a special pattern       */
00041   /* matching routine.                                                     */
00042   /*                                                                       */
00043   /* All other common cases are handled very simply.  The matching rules   */
00044   /* are defined in the file `t1tokens.h' through the use of several       */
00045   /* macros calls PARSE_XXX.  This file is included twice here; the first  */
00046   /* time to generate parsing callback functions, the second time to       */
00047   /* generate a table of keywords (with pointers to the associated         */
00048   /* callback functions).                                                  */
00049   /*                                                                       */
00050   /* The function `parse_dict' simply scans *linearly* a given dictionary  */
00051   /* (either the top-level or private one) and calls the appropriate       */
00052   /* callback when it encounters an immediate keyword.                     */
00053   /*                                                                       */
00054   /* This is by far the fastest way one can find to parse and read all     */
00055   /* data.                                                                 */
00056   /*                                                                       */
00057   /* This led to tremendous code size reduction.  Note that later, the     */
00058   /* glyph loader will also be _greatly_ simplified, and the automatic     */
00059   /* hinter will replace the clumsy `t1hinter'.                            */
00060   /*                                                                       */
00061   /*************************************************************************/
00062 
00063 
00064 #include <ft2build.h>
00065 #include FT_INTERNAL_DEBUG_H
00066 #include FT_CONFIG_CONFIG_H
00067 #include FT_MULTIPLE_MASTERS_H
00068 #include FT_INTERNAL_TYPE1_TYPES_H
00069 #include FT_INTERNAL_CALC_H
00070 
00071 #include "t1load.h"
00072 #include "t1errors.h"
00073 
00074 
00075   /*************************************************************************/
00076   /*                                                                       */
00077   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00078   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00079   /* messages during execution.                                            */
00080   /*                                                                       */
00081 #undef  FT_COMPONENT
00082 #define FT_COMPONENT  trace_t1load
00083 
00084 
00085 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
00086 
00087 
00088   /*************************************************************************/
00089   /*************************************************************************/
00090   /*****                                                               *****/
00091   /*****                    MULTIPLE MASTERS SUPPORT                   *****/
00092   /*****                                                               *****/
00093   /*************************************************************************/
00094   /*************************************************************************/
00095 
00096   static FT_Error
00097   t1_allocate_blend( T1_Face  face,
00098                      FT_UInt  num_designs,
00099                      FT_UInt  num_axis )
00100   {
00101     PS_Blend   blend;
00102     FT_Memory  memory = face->root.memory;
00103     FT_Error   error  = T1_Err_Ok;
00104 
00105 
00106     blend = face->blend;
00107     if ( !blend )
00108     {
00109       if ( FT_NEW( blend ) )
00110         goto Exit;
00111 
00112       blend->num_default_design_vector = 0;
00113 
00114       face->blend = blend;
00115     }
00116 
00117     /* allocate design data if needed */
00118     if ( num_designs > 0 )
00119     {
00120       if ( blend->num_designs == 0 )
00121       {
00122         FT_UInt  nn;
00123 
00124 
00125         /* allocate the blend `private' and `font_info' dictionaries */
00126         if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs     ) ||
00127              FT_NEW_ARRAY( blend->privates[1], num_designs       ) ||
00128              FT_NEW_ARRAY( blend->bboxes[1], num_designs         ) ||
00129              FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
00130           goto Exit;
00131 
00132         blend->default_weight_vector = blend->weight_vector + num_designs;
00133 
00134         blend->font_infos[0] = &face->type1.font_info;
00135         blend->privates  [0] = &face->type1.private_dict;
00136         blend->bboxes    [0] = &face->type1.font_bbox;
00137 
00138         for ( nn = 2; nn <= num_designs; nn++ )
00139         {
00140           blend->privates[nn]   = blend->privates  [nn - 1] + 1;
00141           blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
00142           blend->bboxes[nn]     = blend->bboxes    [nn - 1] + 1;
00143         }
00144 
00145         blend->num_designs   = num_designs;
00146       }
00147       else if ( blend->num_designs != num_designs )
00148         goto Fail;
00149     }
00150 
00151     /* allocate axis data if needed */
00152     if ( num_axis > 0 )
00153     {
00154       if ( blend->num_axis != 0 && blend->num_axis != num_axis )
00155         goto Fail;
00156 
00157       blend->num_axis = num_axis;
00158     }
00159 
00160     /* allocate the blend design pos table if needed */
00161     num_designs = blend->num_designs;
00162     num_axis    = blend->num_axis;
00163     if ( num_designs && num_axis && blend->design_pos[0] == 0 )
00164     {
00165       FT_UInt  n;
00166 
00167 
00168       if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
00169         goto Exit;
00170 
00171       for ( n = 1; n < num_designs; n++ )
00172         blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
00173     }
00174 
00175   Exit:
00176     return error;
00177 
00178   Fail:
00179     error = T1_Err_Invalid_File_Format;
00180     goto Exit;
00181   }
00182 
00183 
00184   FT_LOCAL_DEF( FT_Error )
00185   T1_Get_Multi_Master( T1_Face           face,
00186                        FT_Multi_Master*  master )
00187   {
00188     PS_Blend  blend = face->blend;
00189     FT_UInt   n;
00190     FT_Error  error;
00191 
00192 
00193     error = T1_Err_Invalid_Argument;
00194 
00195     if ( blend )
00196     {
00197       master->num_axis    = blend->num_axis;
00198       master->num_designs = blend->num_designs;
00199 
00200       for ( n = 0; n < blend->num_axis; n++ )
00201       {
00202         FT_MM_Axis*   axis = master->axis + n;
00203         PS_DesignMap  map = blend->design_map + n;
00204 
00205 
00206         axis->name    = blend->axis_names[n];
00207         axis->minimum = map->design_points[0];
00208         axis->maximum = map->design_points[map->num_points - 1];
00209       }
00210 
00211       error = T1_Err_Ok;
00212     }
00213 
00214     return error;
00215   }
00216 
00217 
00218   /*************************************************************************/
00219   /*                                                                       */
00220   /* Given a normalized (blend) coordinate, figure out the design          */
00221   /* coordinate appropriate for that value.                                */
00222   /*                                                                       */
00223   FT_LOCAL_DEF( FT_Fixed )
00224   mm_axis_unmap( PS_DesignMap  axismap,
00225                  FT_Fixed      ncv )
00226   {
00227     int  j;
00228 
00229 
00230     if ( ncv <= axismap->blend_points[0] )
00231       return INT_TO_FIXED( axismap->design_points[0] );
00232 
00233     for ( j = 1; j < axismap->num_points; ++j )
00234     {
00235       if ( ncv <= axismap->blend_points[j] )
00236       {
00237         FT_Fixed  t = FT_MulDiv( ncv - axismap->blend_points[j - 1],
00238                                  0x10000L,
00239                                  axismap->blend_points[j] -
00240                                    axismap->blend_points[j - 1] );
00241 
00242         return INT_TO_FIXED( axismap->design_points[j - 1] ) +
00243                  FT_MulDiv( t,
00244                             axismap->design_points[j] -
00245                               axismap->design_points[j - 1],
00246                             1L );
00247       }
00248     }
00249 
00250     return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
00251   }
00252 
00253 
00254   /*************************************************************************/
00255   /*                                                                       */
00256   /* Given a vector of weights, one for each design, figure out the        */
00257   /* normalized axis coordinates which gave rise to those weights.         */
00258   /*                                                                       */
00259   FT_LOCAL_DEF( void )
00260   mm_weights_unmap( FT_Fixed*  weights,
00261                     FT_Fixed*  axiscoords,
00262                     FT_UInt    axis_count )
00263   {
00264     FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
00265 
00266     if ( axis_count == 1 )
00267       axiscoords[0] = weights[1];
00268 
00269     else if ( axis_count == 2 )
00270     {
00271       axiscoords[0] = weights[3] + weights[1];
00272       axiscoords[1] = weights[3] + weights[2];
00273     }
00274 
00275     else if ( axis_count == 3 )
00276     {
00277       axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
00278       axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
00279       axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
00280     }
00281 
00282     else
00283     {
00284       axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
00285                         weights[7] + weights[5] + weights[3] + weights[1];
00286       axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
00287                         weights[7] + weights[6] + weights[3] + weights[2];
00288       axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
00289                         weights[7] + weights[6] + weights[5] + weights[4];
00290       axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
00291                         weights[11] + weights[10] + weights[9] + weights[8];
00292     }
00293   }
00294 
00295 
00296   /*************************************************************************/
00297   /*                                                                       */
00298   /* Just a wrapper around T1_Get_Multi_Master to support the different    */
00299   /*  arguments needed by the GX var distortable fonts.                    */
00300   /*                                                                       */
00301   FT_LOCAL_DEF( FT_Error )
00302   T1_Get_MM_Var( T1_Face      face,
00303                  FT_MM_Var*  *master )
00304   {
00305     FT_Memory        memory = face->root.memory;
00306     FT_MM_Var       *mmvar;
00307     FT_Multi_Master  mmaster;
00308     FT_Error         error;
00309     FT_UInt          i;
00310     FT_Fixed         axiscoords[T1_MAX_MM_AXIS];
00311     PS_Blend         blend = face->blend;
00312 
00313 
00314     error = T1_Get_Multi_Master( face, &mmaster );
00315     if ( error )
00316       goto Exit;
00317     if ( FT_ALLOC( mmvar,
00318                    sizeof ( FT_MM_Var ) +
00319                      mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
00320       goto Exit;
00321 
00322     mmvar->num_axis        = mmaster.num_axis;
00323     mmvar->num_designs     = mmaster.num_designs;
00324     mmvar->num_namedstyles = (FT_UInt)-1;                /* Does not apply */
00325     mmvar->axis            = (FT_Var_Axis*)&mmvar[1];
00326                                       /* Point to axes after MM_Var struct */
00327     mmvar->namedstyle      = NULL;
00328 
00329     for ( i = 0 ; i < mmaster.num_axis; ++i )
00330     {
00331       mmvar->axis[i].name    = mmaster.axis[i].name;
00332       mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum);
00333       mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum);
00334       mmvar->axis[i].def     = ( mmvar->axis[i].minimum +
00335                                    mmvar->axis[i].maximum ) / 2;
00336                             /* Does not apply.  But this value is in range */
00337       mmvar->axis[i].strid   = (FT_UInt)-1;    /* Does not apply */
00338       mmvar->axis[i].tag     = (FT_ULong)-1;   /* Does not apply */
00339 
00340       if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
00341         mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
00342       else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
00343         mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
00344       else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
00345         mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
00346     }
00347 
00348     if ( blend->num_designs == ( 1U << blend->num_axis ) )
00349     {
00350       mm_weights_unmap( blend->default_weight_vector,
00351                         axiscoords,
00352                         blend->num_axis );
00353 
00354       for ( i = 0; i < mmaster.num_axis; ++i )
00355         mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
00356                                             axiscoords[i] );
00357     }
00358 
00359     *master = mmvar;
00360 
00361   Exit:
00362     return error;
00363   }
00364 
00365 
00366   FT_LOCAL_DEF( FT_Error )
00367   T1_Set_MM_Blend( T1_Face    face,
00368                    FT_UInt    num_coords,
00369                    FT_Fixed*  coords )
00370   {
00371     PS_Blend  blend = face->blend;
00372     FT_Error  error;
00373     FT_UInt   n, m;
00374 
00375 
00376     error = T1_Err_Invalid_Argument;
00377 
00378     if ( blend && blend->num_axis == num_coords )
00379     {
00380       /* recompute the weight vector from the blend coordinates */
00381       error = T1_Err_Ok;
00382 
00383       for ( n = 0; n < blend->num_designs; n++ )
00384       {
00385         FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
00386 
00387 
00388         for ( m = 0; m < blend->num_axis; m++ )
00389         {
00390           FT_Fixed  factor;
00391 
00392 
00393           /* get current blend axis position */
00394           factor = coords[m];
00395           if ( factor < 0 )        factor = 0;
00396           if ( factor > 0x10000L ) factor = 0x10000L;
00397 
00398           if ( ( n & ( 1 << m ) ) == 0 )
00399             factor = 0x10000L - factor;
00400 
00401           result = FT_MulFix( result, factor );
00402         }
00403         blend->weight_vector[n] = result;
00404       }
00405 
00406       error = T1_Err_Ok;
00407     }
00408 
00409     return error;
00410   }
00411 
00412 
00413   FT_LOCAL_DEF( FT_Error )
00414   T1_Set_MM_Design( T1_Face   face,
00415                     FT_UInt   num_coords,
00416                     FT_Long*  coords )
00417   {
00418     PS_Blend  blend = face->blend;
00419     FT_Error  error;
00420     FT_UInt   n, p;
00421 
00422 
00423     error = T1_Err_Invalid_Argument;
00424     if ( blend && blend->num_axis == num_coords )
00425     {
00426       /* compute the blend coordinates through the blend design map */
00427       FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
00428 
00429 
00430       for ( n = 0; n < blend->num_axis; n++ )
00431       {
00432         FT_Long       design  = coords[n];
00433         FT_Fixed      the_blend;
00434         PS_DesignMap  map     = blend->design_map + n;
00435         FT_Long*      designs = map->design_points;
00436         FT_Fixed*     blends  = map->blend_points;
00437         FT_Int        before  = -1, after = -1;
00438 
00439 
00440         for ( p = 0; p < (FT_UInt)map->num_points; p++ )
00441         {
00442           FT_Long  p_design = designs[p];
00443 
00444 
00445           /* exact match? */
00446           if ( design == p_design )
00447           {
00448             the_blend = blends[p];
00449             goto Found;
00450           }
00451 
00452           if ( design < p_design )
00453           {
00454             after = p;
00455             break;
00456           }
00457 
00458           before = p;
00459         }
00460 
00461         /* now interpolate if necessary */
00462         if ( before < 0 )
00463           the_blend = blends[0];
00464 
00465         else if ( after < 0 )
00466           the_blend = blends[map->num_points - 1];
00467 
00468         else
00469           the_blend = FT_MulDiv( design         - designs[before],
00470                                  blends [after] - blends [before],
00471                                  designs[after] - designs[before] );
00472 
00473       Found:
00474         final_blends[n] = the_blend;
00475       }
00476 
00477       error = T1_Set_MM_Blend( face, num_coords, final_blends );
00478     }
00479 
00480     return error;
00481   }
00482 
00483 
00484   /*************************************************************************/
00485   /*                                                                       */
00486   /* Just a wrapper around T1_Set_MM_Design to support the different       */
00487   /* arguments needed by the GX var distortable fonts.                     */
00488   /*                                                                       */
00489   FT_LOCAL_DEF( FT_Error )
00490   T1_Set_Var_Design( T1_Face    face,
00491                      FT_UInt    num_coords,
00492                      FT_Fixed*  coords )
00493   {
00494      FT_Long   lcoords[4];          /* maximum axis count is 4 */
00495      FT_UInt   i;
00496      FT_Error  error;
00497 
00498 
00499      error = T1_Err_Invalid_Argument;
00500      if ( num_coords <= 4 && num_coords > 0 )
00501      {
00502        for ( i = 0; i < num_coords; ++i )
00503          lcoords[i] = FIXED_TO_INT( coords[i] );
00504        error = T1_Set_MM_Design( face, num_coords, lcoords );
00505      }
00506 
00507      return error;
00508   }
00509 
00510 
00511   FT_LOCAL_DEF( void )
00512   T1_Done_Blend( T1_Face  face )
00513   {
00514     FT_Memory  memory = face->root.memory;
00515     PS_Blend   blend  = face->blend;
00516 
00517 
00518     if ( blend )
00519     {
00520       FT_UInt  num_designs = blend->num_designs;
00521       FT_UInt  num_axis    = blend->num_axis;
00522       FT_UInt  n;
00523 
00524 
00525       /* release design pos table */
00526       FT_FREE( blend->design_pos[0] );
00527       for ( n = 1; n < num_designs; n++ )
00528         blend->design_pos[n] = 0;
00529 
00530       /* release blend `private' and `font info' dictionaries */
00531       FT_FREE( blend->privates[1] );
00532       FT_FREE( blend->font_infos[1] );
00533       FT_FREE( blend->bboxes[1] );
00534 
00535       for ( n = 0; n < num_designs; n++ )
00536       {
00537         blend->privates  [n] = 0;
00538         blend->font_infos[n] = 0;
00539         blend->bboxes    [n] = 0;
00540       }
00541 
00542       /* release weight vectors */
00543       FT_FREE( blend->weight_vector );
00544       blend->default_weight_vector = 0;
00545 
00546       /* release axis names */
00547       for ( n = 0; n < num_axis; n++ )
00548         FT_FREE( blend->axis_names[n] );
00549 
00550       /* release design map */
00551       for ( n = 0; n < num_axis; n++ )
00552       {
00553         PS_DesignMap  dmap = blend->design_map + n;
00554 
00555 
00556         FT_FREE( dmap->design_points );
00557         dmap->num_points = 0;
00558       }
00559 
00560       FT_FREE( face->blend );
00561     }
00562   }
00563 
00564 
00565   static void
00566   parse_blend_axis_types( T1_Face    face,
00567                           T1_Loader  loader )
00568   {
00569     T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
00570     FT_Int       n, num_axis;
00571     FT_Error     error = T1_Err_Ok;
00572     PS_Blend     blend;
00573     FT_Memory    memory;
00574 
00575 
00576     /* take an array of objects */
00577     T1_ToTokenArray( &loader->parser, axis_tokens,
00578                      T1_MAX_MM_AXIS, &num_axis );
00579     if ( num_axis < 0 )
00580     {
00581       error = T1_Err_Ignore;
00582       goto Exit;
00583     }
00584     if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
00585     {
00586       FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
00587                  num_axis ));
00588       error = T1_Err_Invalid_File_Format;
00589       goto Exit;
00590     }
00591 
00592     /* allocate blend if necessary */
00593     error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
00594     if ( error )
00595       goto Exit;
00596 
00597     blend  = face->blend;
00598     memory = face->root.memory;
00599 
00600     /* each token is an immediate containing the name of the axis */
00601     for ( n = 0; n < num_axis; n++ )
00602     {
00603       T1_Token    token = axis_tokens + n;
00604       FT_Byte*    name;
00605       FT_PtrDist  len;
00606 
00607 
00608       /* skip first slash, if any */
00609       if ( token->start[0] == '/' )
00610         token->start++;
00611 
00612       len = token->limit - token->start;
00613       if ( len == 0 )
00614       {
00615         error = T1_Err_Invalid_File_Format;
00616         goto Exit;
00617       }
00618 
00619       if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
00620         goto Exit;
00621 
00622       name = (FT_Byte*)blend->axis_names[n];
00623       FT_MEM_COPY( name, token->start, len );
00624       name[len] = 0;
00625     }
00626 
00627   Exit:
00628     loader->parser.root.error = error;
00629   }
00630 
00631 
00632   static void
00633   parse_blend_design_positions( T1_Face    face,
00634                                 T1_Loader  loader )
00635   {
00636     T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
00637     FT_Int       num_designs;
00638     FT_Int       num_axis;
00639     T1_Parser    parser = &loader->parser;
00640 
00641     FT_Error     error = T1_Err_Ok;
00642     PS_Blend     blend;
00643 
00644 
00645     /* get the array of design tokens -- compute number of designs */
00646     T1_ToTokenArray( parser, design_tokens,
00647                      T1_MAX_MM_DESIGNS, &num_designs );
00648     if ( num_designs < 0 )
00649     {
00650       error = T1_Err_Ignore;
00651       goto Exit;
00652     }
00653     if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
00654     {
00655       FT_ERROR(( "parse_blend_design_positions:"
00656                  " incorrect number of designs: %d\n",
00657                  num_designs ));
00658       error = T1_Err_Invalid_File_Format;
00659       goto Exit;
00660     }
00661 
00662     {
00663       FT_Byte*  old_cursor = parser->root.cursor;
00664       FT_Byte*  old_limit  = parser->root.limit;
00665       FT_Int    n;
00666 
00667 
00668       blend    = face->blend;
00669       num_axis = 0;  /* make compiler happy */
00670 
00671       for ( n = 0; n < num_designs; n++ )
00672       {
00673         T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
00674         T1_Token     token;
00675         FT_Int       axis, n_axis;
00676 
00677 
00678         /* read axis/coordinates tokens */
00679         token = design_tokens + n;
00680         parser->root.cursor = token->start;
00681         parser->root.limit  = token->limit;
00682         T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
00683 
00684         if ( n == 0 )
00685         {
00686           if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
00687           {
00688             FT_ERROR(( "parse_blend_design_positions:"
00689                        " invalid number of axes: %d\n",
00690                        n_axis ));
00691             error = T1_Err_Invalid_File_Format;
00692             goto Exit;
00693           }
00694 
00695           num_axis = n_axis;
00696           error = t1_allocate_blend( face, num_designs, num_axis );
00697           if ( error )
00698             goto Exit;
00699           blend = face->blend;
00700         }
00701         else if ( n_axis != num_axis )
00702         {
00703           FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
00704           error = T1_Err_Invalid_File_Format;
00705           goto Exit;
00706         }
00707 
00708         /* now read each axis token into the design position */
00709         for ( axis = 0; axis < n_axis; axis++ )
00710         {
00711           T1_Token  token2 = axis_tokens + axis;
00712 
00713 
00714           parser->root.cursor = token2->start;
00715           parser->root.limit  = token2->limit;
00716           blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
00717         }
00718       }
00719 
00720       loader->parser.root.cursor = old_cursor;
00721       loader->parser.root.limit  = old_limit;
00722     }
00723 
00724   Exit:
00725     loader->parser.root.error = error;
00726   }
00727 
00728 
00729   static void
00730   parse_blend_design_map( T1_Face    face,
00731                           T1_Loader  loader )
00732   {
00733     FT_Error     error  = T1_Err_Ok;
00734     T1_Parser    parser = &loader->parser;
00735     PS_Blend     blend;
00736     T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
00737     FT_Int       n, num_axis;
00738     FT_Byte*     old_cursor;
00739     FT_Byte*     old_limit;
00740     FT_Memory    memory = face->root.memory;
00741 
00742 
00743     T1_ToTokenArray( parser, axis_tokens,
00744                      T1_MAX_MM_AXIS, &num_axis );
00745     if ( num_axis < 0 )
00746     {
00747       error = T1_Err_Ignore;
00748       goto Exit;
00749     }
00750     if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
00751     {
00752       FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
00753                  num_axis ));
00754       error = T1_Err_Invalid_File_Format;
00755       goto Exit;
00756     }
00757 
00758     old_cursor = parser->root.cursor;
00759     old_limit  = parser->root.limit;
00760 
00761     error = t1_allocate_blend( face, 0, num_axis );
00762     if ( error )
00763       goto Exit;
00764     blend = face->blend;
00765 
00766     /* now read each axis design map */
00767     for ( n = 0; n < num_axis; n++ )
00768     {
00769       PS_DesignMap  map = blend->design_map + n;
00770       T1_Token      axis_token;
00771       T1_TokenRec   point_tokens[T1_MAX_MM_MAP_POINTS];
00772       FT_Int        p, num_points;
00773 
00774 
00775       axis_token = axis_tokens + n;
00776 
00777       parser->root.cursor = axis_token->start;
00778       parser->root.limit  = axis_token->limit;
00779       T1_ToTokenArray( parser, point_tokens,
00780                        T1_MAX_MM_MAP_POINTS, &num_points );
00781 
00782       if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
00783       {
00784         FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
00785         error = T1_Err_Invalid_File_Format;
00786         goto Exit;
00787       }
00788 
00789       /* allocate design map data */
00790       if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
00791         goto Exit;
00792       map->blend_points = map->design_points + num_points;
00793       map->num_points   = (FT_Byte)num_points;
00794 
00795       for ( p = 0; p < num_points; p++ )
00796       {
00797         T1_Token  point_token;
00798 
00799 
00800         point_token = point_tokens + p;
00801 
00802         /* don't include delimiting brackets */
00803         parser->root.cursor = point_token->start + 1;
00804         parser->root.limit  = point_token->limit - 1;
00805 
00806         map->design_points[p] = T1_ToInt( parser );
00807         map->blend_points [p] = T1_ToFixed( parser, 0 );
00808       }
00809     }
00810 
00811     parser->root.cursor = old_cursor;
00812     parser->root.limit  = old_limit;
00813 
00814   Exit:
00815     parser->root.error = error;
00816   }
00817 
00818 
00819   static void
00820   parse_weight_vector( T1_Face    face,
00821                        T1_Loader  loader )
00822   {
00823     T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
00824     FT_Int       num_designs;
00825     FT_Error     error  = T1_Err_Ok;
00826     T1_Parser    parser = &loader->parser;
00827     PS_Blend     blend  = face->blend;
00828     T1_Token     token;
00829     FT_Int       n;
00830     FT_Byte*     old_cursor;
00831     FT_Byte*     old_limit;
00832 
00833 
00834     T1_ToTokenArray( parser, design_tokens,
00835                      T1_MAX_MM_DESIGNS, &num_designs );
00836     if ( num_designs < 0 )
00837     {
00838       error = T1_Err_Ignore;
00839       goto Exit;
00840     }
00841     if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
00842     {
00843       FT_ERROR(( "parse_weight_vector:"
00844                  " incorrect number of designs: %d\n",
00845                  num_designs ));
00846       error = T1_Err_Invalid_File_Format;
00847       goto Exit;
00848     }
00849 
00850     if ( !blend || !blend->num_designs )
00851     {
00852       error = t1_allocate_blend( face, num_designs, 0 );
00853       if ( error )
00854         goto Exit;
00855       blend = face->blend;
00856     }
00857     else if ( blend->num_designs != (FT_UInt)num_designs )
00858     {
00859       FT_ERROR(( "parse_weight_vector:"
00860                  " /BlendDesignPosition and /WeightVector have\n"
00861                  "                    "
00862                  " different number of elements\n" ));
00863       error = T1_Err_Invalid_File_Format;
00864       goto Exit;
00865     }
00866 
00867     old_cursor = parser->root.cursor;
00868     old_limit  = parser->root.limit;
00869 
00870     for ( n = 0; n < num_designs; n++ )
00871     {
00872       token = design_tokens + n;
00873       parser->root.cursor = token->start;
00874       parser->root.limit  = token->limit;
00875 
00876       blend->default_weight_vector[n] =
00877       blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
00878     }
00879 
00880     parser->root.cursor = old_cursor;
00881     parser->root.limit  = old_limit;
00882 
00883   Exit:
00884     parser->root.error = error;
00885   }
00886 
00887 
00888   /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
00889   /* we're only interested in the number of array elements */
00890   static void
00891   parse_buildchar( T1_Face    face,
00892                    T1_Loader  loader )
00893   {
00894     face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
00895 
00896     return;
00897   }
00898 
00899 
00900 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
00901 
00902 
00903 
00904 
00905   /*************************************************************************/
00906   /*************************************************************************/
00907   /*****                                                               *****/
00908   /*****                      TYPE 1 SYMBOL PARSING                    *****/
00909   /*****                                                               *****/
00910   /*************************************************************************/
00911   /*************************************************************************/
00912 
00913   static FT_Error
00914   t1_load_keyword( T1_Face         face,
00915                    T1_Loader       loader,
00916                    const T1_Field  field )
00917   {
00918     FT_Error  error;
00919     void*     dummy_object;
00920     void**    objects;
00921     FT_UInt   max_objects;
00922     PS_Blend  blend = face->blend;
00923 
00924 
00925     /* if the keyword has a dedicated callback, call it */
00926     if ( field->type == T1_FIELD_TYPE_CALLBACK )
00927     {
00928       field->reader( (FT_Face)face, loader );
00929       error = loader->parser.root.error;
00930       goto Exit;
00931     }
00932 
00933     /* now, the keyword is either a simple field, or a table of fields; */
00934     /* we are now going to take care of it                              */
00935     switch ( field->location )
00936     {
00937     case T1_FIELD_LOCATION_FONT_INFO:
00938       dummy_object = &face->type1.font_info;
00939       objects      = &dummy_object;
00940       max_objects  = 0;
00941 
00942       if ( blend )
00943       {
00944         objects     = (void**)blend->font_infos;
00945         max_objects = blend->num_designs;
00946       }
00947       break;
00948 
00949     case T1_FIELD_LOCATION_FONT_EXTRA:
00950       dummy_object = &face->type1.font_extra;
00951       objects      = &dummy_object;
00952       max_objects  = 0;
00953       break;
00954 
00955     case T1_FIELD_LOCATION_PRIVATE:
00956       dummy_object = &face->type1.private_dict;
00957       objects      = &dummy_object;
00958       max_objects  = 0;
00959 
00960       if ( blend )
00961       {
00962         objects     = (void**)blend->privates;
00963         max_objects = blend->num_designs;
00964       }
00965       break;
00966 
00967     case T1_FIELD_LOCATION_BBOX:
00968       dummy_object = &face->type1.font_bbox;
00969       objects      = &dummy_object;
00970       max_objects  = 0;
00971 
00972       if ( blend )
00973       {
00974         objects     = (void**)blend->bboxes;
00975         max_objects = blend->num_designs;
00976       }
00977       break;
00978 
00979     case T1_FIELD_LOCATION_LOADER:
00980       dummy_object = loader;
00981       objects      = &dummy_object;
00982       max_objects  = 0;
00983       break;
00984 
00985     case T1_FIELD_LOCATION_FACE:
00986       dummy_object = face;
00987       objects      = &dummy_object;
00988       max_objects  = 0;
00989       break;
00990 
00991 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
00992     case T1_FIELD_LOCATION_BLEND:
00993       dummy_object = face->blend;
00994       objects      = &dummy_object;
00995       max_objects  = 0;
00996       break;
00997 #endif
00998 
00999     default:
01000       dummy_object = &face->type1;
01001       objects      = &dummy_object;
01002       max_objects  = 0;
01003     }
01004 
01005     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
01006          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
01007       error = T1_Load_Field_Table( &loader->parser, field,
01008                                    objects, max_objects, 0 );
01009     else
01010       error = T1_Load_Field( &loader->parser, field,
01011                              objects, max_objects, 0 );
01012 
01013   Exit:
01014     return error;
01015   }
01016 
01017 
01018   static void
01019   parse_private( T1_Face    face,
01020                  T1_Loader  loader )
01021   {
01022     FT_UNUSED( face );
01023 
01024     loader->keywords_encountered |= T1_PRIVATE;
01025   }
01026 
01027 
01028   static int
01029   read_binary_data( T1_Parser  parser,
01030                     FT_Long*   size,
01031                     FT_Byte**  base )
01032   {
01033     FT_Byte*  cur;
01034     FT_Byte*  limit = parser->root.limit;
01035 
01036 
01037     /* the binary data has one of the following formats */
01038     /*                                                  */
01039     /*   `size' [white*] RD white ....... ND            */
01040     /*   `size' [white*] -| white ....... |-            */
01041     /*                                                  */
01042 
01043     T1_Skip_Spaces( parser );
01044 
01045     cur = parser->root.cursor;
01046 
01047     if ( cur < limit && ft_isdigit( *cur ) )
01048     {
01049       FT_Long  s = T1_ToInt( parser );
01050 
01051 
01052       T1_Skip_PS_Token( parser );   /* `RD' or `-|' or something else */
01053 
01054       /* there is only one whitespace char after the */
01055       /* `RD' or `-|' token                          */
01056       *base = parser->root.cursor + 1;
01057 
01058       if ( s >= 0 && s < limit - *base )
01059       {
01060         parser->root.cursor += s + 1;
01061         *size = s;
01062         return !parser->root.error;
01063       }
01064     }
01065 
01066     FT_ERROR(( "read_binary_data: invalid size field\n" ));
01067     parser->root.error = T1_Err_Invalid_File_Format;
01068     return 0;
01069   }
01070 
01071 
01072   /* We now define the routines to handle the `/Encoding', `/Subrs', */
01073   /* and `/CharStrings' dictionaries.                                */
01074 
01075   static void
01076   parse_font_matrix( T1_Face    face,
01077                      T1_Loader  loader )
01078   {
01079     T1_Parser   parser = &loader->parser;
01080     FT_Matrix*  matrix = &face->type1.font_matrix;
01081     FT_Vector*  offset = &face->type1.font_offset;
01082     FT_Face     root   = (FT_Face)&face->root;
01083     FT_Fixed    temp[6];
01084     FT_Fixed    temp_scale;
01085     FT_Int      result;
01086 
01087 
01088     result = T1_ToFixedArray( parser, 6, temp, 3 );
01089 
01090     if ( result < 0 )
01091     {
01092       parser->root.error = T1_Err_Invalid_File_Format;
01093       return;
01094     }
01095 
01096     temp_scale = FT_ABS( temp[3] );
01097 
01098     if ( temp_scale == 0 )
01099     {
01100       FT_ERROR(( "parse_font_matrix: invalid font matrix\n" ));
01101       parser->root.error = T1_Err_Invalid_File_Format;
01102       return;
01103     }
01104 
01105     /* Set Units per EM based on FontMatrix values.  We set the value to */
01106     /* 1000 / temp_scale, because temp_scale was already multiplied by   */
01107     /* 1000 (in t1_tofixed, from psobjs.c).                              */
01108 
01109     root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
01110                                                  temp_scale ) >> 16 );
01111 
01112     /* we need to scale the values by 1.0/temp_scale */
01113     if ( temp_scale != 0x10000L )
01114     {
01115       temp[0] = FT_DivFix( temp[0], temp_scale );
01116       temp[1] = FT_DivFix( temp[1], temp_scale );
01117       temp[2] = FT_DivFix( temp[2], temp_scale );
01118       temp[4] = FT_DivFix( temp[4], temp_scale );
01119       temp[5] = FT_DivFix( temp[5], temp_scale );
01120       temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
01121     }
01122 
01123     matrix->xx = temp[0];
01124     matrix->yx = temp[1];
01125     matrix->xy = temp[2];
01126     matrix->yy = temp[3];
01127 
01128     /* note that the offsets must be expressed in integer font units */
01129     offset->x = temp[4] >> 16;
01130     offset->y = temp[5] >> 16;
01131   }
01132 
01133 
01134   static void
01135   parse_encoding( T1_Face    face,
01136                   T1_Loader  loader )
01137   {
01138     T1_Parser  parser = &loader->parser;
01139     FT_Byte*   cur;
01140     FT_Byte*   limit  = parser->root.limit;
01141 
01142     PSAux_Service  psaux = (PSAux_Service)face->psaux;
01143 
01144 
01145     T1_Skip_Spaces( parser );
01146     cur = parser->root.cursor;
01147     if ( cur >= limit )
01148     {
01149       FT_ERROR(( "parse_encoding: out of bounds\n" ));
01150       parser->root.error = T1_Err_Invalid_File_Format;
01151       return;
01152     }
01153 
01154     /* if we have a number or `[', the encoding is an array, */
01155     /* and we must load it now                               */
01156     if ( ft_isdigit( *cur ) || *cur == '[' )
01157     {
01158       T1_Encoding  encode          = &face->type1.encoding;
01159       FT_Int       count, n;
01160       PS_Table     char_table      = &loader->encoding_table;
01161       FT_Memory    memory          = parser->root.memory;
01162       FT_Error     error;
01163       FT_Bool      only_immediates = 0;
01164 
01165 
01166       /* read the number of entries in the encoding; should be 256 */
01167       if ( *cur == '[' )
01168       {
01169         count           = 256;
01170         only_immediates = 1;
01171         parser->root.cursor++;
01172       }
01173       else
01174         count = (FT_Int)T1_ToInt( parser );
01175 
01176       T1_Skip_Spaces( parser );
01177       if ( parser->root.cursor >= limit )
01178         return;
01179 
01180       /* we use a T1_Table to store our charnames */
01181       loader->num_chars = encode->num_chars = count;
01182       if ( FT_NEW_ARRAY( encode->char_index, count )     ||
01183            FT_NEW_ARRAY( encode->char_name,  count )     ||
01184            FT_SET_ERROR( psaux->ps_table_funcs->init(
01185                            char_table, count, memory ) ) )
01186       {
01187         parser->root.error = error;
01188         return;
01189       }
01190 
01191       /* We need to `zero' out encoding_table.elements */
01192       for ( n = 0; n < count; n++ )
01193       {
01194         char*  notdef = (char *)".notdef";
01195 
01196 
01197         T1_Add_Table( char_table, n, notdef, 8 );
01198       }
01199 
01200       /* Now we need to read records of the form                */
01201       /*                                                        */
01202       /*   ... charcode /charname ...                           */
01203       /*                                                        */
01204       /* for each entry in our table.                           */
01205       /*                                                        */
01206       /* We simply look for a number followed by an immediate   */
01207       /* name.  Note that this ignores correctly the sequence   */
01208       /* that is often seen in type1 fonts:                     */
01209       /*                                                        */
01210       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
01211       /*                                                        */
01212       /* used to clean the encoding array before anything else. */
01213       /*                                                        */
01214       /* Alternatively, if the array is directly given as       */
01215       /*                                                        */
01216       /*   /Encoding [ ... ]                                    */
01217       /*                                                        */
01218       /* we only read immediates.                               */
01219 
01220       n = 0;
01221       T1_Skip_Spaces( parser );
01222 
01223       while ( parser->root.cursor < limit )
01224       {
01225         cur = parser->root.cursor;
01226 
01227         /* we stop when we encounter a `def' or `]' */
01228         if ( *cur == 'd' && cur + 3 < limit )
01229         {
01230           if ( cur[1] == 'e'         &&
01231                cur[2] == 'f'         &&
01232                IS_PS_DELIM( cur[3] ) )
01233           {
01234             FT_TRACE6(( "encoding end\n" ));
01235             cur += 3;
01236             break;
01237           }
01238         }
01239         if ( *cur == ']' )
01240         {
01241           FT_TRACE6(( "encoding end\n" ));
01242           cur++;
01243           break;
01244         }
01245 
01246         /* check whether we've found an entry */
01247         if ( ft_isdigit( *cur ) || only_immediates )
01248         {
01249           FT_Int  charcode;
01250 
01251 
01252           if ( only_immediates )
01253             charcode = n;
01254           else
01255           {
01256             charcode = (FT_Int)T1_ToInt( parser );
01257             T1_Skip_Spaces( parser );
01258           }
01259 
01260           cur = parser->root.cursor;
01261 
01262           if ( *cur == '/' && cur + 2 < limit && n < count )
01263           {
01264             FT_PtrDist  len;
01265 
01266 
01267             cur++;
01268 
01269             parser->root.cursor = cur;
01270             T1_Skip_PS_Token( parser );
01271             if ( parser->root.error )
01272               return;
01273 
01274             len = parser->root.cursor - cur;
01275 
01276             parser->root.error = T1_Add_Table( char_table, charcode,
01277                                                cur, len + 1 );
01278             if ( parser->root.error )
01279               return;
01280             char_table->elements[charcode][len] = '\0';
01281 
01282             n++;
01283           }
01284           else if ( only_immediates )
01285           {
01286             /* Since the current position is not updated for           */
01287             /* immediates-only mode we would get an infinite loop if   */
01288             /* we don't do anything here.                              */
01289             /*                                                         */
01290             /* This encoding array is not valid according to the type1 */
01291             /* specification (it might be an encoding for a CID type1  */
01292             /* font, however), so we conclude that this font is NOT a  */
01293             /* type1 font.                                             */
01294             parser->root.error = FT_Err_Unknown_File_Format;
01295             return;
01296           }
01297         }
01298         else
01299         {
01300           T1_Skip_PS_Token( parser );
01301           if ( parser->root.error )
01302             return;
01303         }
01304 
01305         T1_Skip_Spaces( parser );
01306       }
01307 
01308       face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
01309       parser->root.cursor       = cur;
01310     }
01311 
01312     /* Otherwise, we should have either `StandardEncoding', */
01313     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
01314     else
01315     {
01316       if ( cur + 17 < limit                                            &&
01317            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
01318         face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
01319 
01320       else if ( cur + 15 < limit                                          &&
01321                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
01322         face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
01323 
01324       else if ( cur + 18 < limit                                             &&
01325                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
01326         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
01327 
01328       else
01329         parser->root.error = T1_Err_Ignore;
01330     }
01331   }
01332 
01333 
01334   static void
01335   parse_subrs( T1_Face    face,
01336                T1_Loader  loader )
01337   {
01338     T1_Parser  parser = &loader->parser;
01339     PS_Table   table  = &loader->subrs;
01340     FT_Memory  memory = parser->root.memory;
01341     FT_Error   error;
01342     FT_Int     num_subrs;
01343 
01344     PSAux_Service  psaux = (PSAux_Service)face->psaux;
01345 
01346 
01347     T1_Skip_Spaces( parser );
01348 
01349     /* test for empty array */
01350     if ( parser->root.cursor < parser->root.limit &&
01351          *parser->root.cursor == '['              )
01352     {
01353       T1_Skip_PS_Token( parser );
01354       T1_Skip_Spaces  ( parser );
01355       if ( parser->root.cursor >= parser->root.limit ||
01356            *parser->root.cursor != ']'               )
01357         parser->root.error = T1_Err_Invalid_File_Format;
01358       return;
01359     }
01360 
01361     num_subrs = (FT_Int)T1_ToInt( parser );
01362 
01363     /* position the parser right before the `dup' of the first subr */
01364     T1_Skip_PS_Token( parser );         /* `array' */
01365     if ( parser->root.error )
01366       return;
01367     T1_Skip_Spaces( parser );
01368 
01369     /* initialize subrs array -- with synthetic fonts it is possible */
01370     /* we get here twice                                             */
01371     if ( !loader->num_subrs )
01372     {
01373       error = psaux->ps_table_funcs->init( table, num_subrs, memory );
01374       if ( error )
01375         goto Fail;
01376     }
01377 
01378     /* the format is simple:   */
01379     /*                         */
01380     /*   `index' + binary data */
01381     /*                         */
01382     for (;;)
01383     {
01384       FT_Long   idx, size;
01385       FT_Byte*  base;
01386 
01387 
01388       /* If the next token isn't `dup' we are done. */
01389       if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
01390         break;
01391 
01392       T1_Skip_PS_Token( parser );       /* `dup' */
01393 
01394       idx = T1_ToInt( parser );
01395 
01396       if ( !read_binary_data( parser, &size, &base ) )
01397         return;
01398 
01399       /* The binary string is followed by one token, e.g. `NP' */
01400       /* (bound to `noaccess put') or by two separate tokens:  */
01401       /* `noaccess' & `put'.  We position the parser right     */
01402       /* before the next `dup', if any.                        */
01403       T1_Skip_PS_Token( parser );   /* `NP' or `|' or `noaccess' */
01404       if ( parser->root.error )
01405         return;
01406       T1_Skip_Spaces  ( parser );
01407 
01408       if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
01409       {
01410         T1_Skip_PS_Token( parser ); /* skip `put' */
01411         T1_Skip_Spaces  ( parser );
01412       }
01413 
01414       /* with synthetic fonts it is possible we get here twice */
01415       if ( loader->num_subrs )
01416         continue;
01417 
01418       /* some fonts use a value of -1 for lenIV to indicate that */
01419       /* the charstrings are unencoded                           */
01420       /*                                                         */
01421       /* thanks to Tom Kacvinsky for pointing this out           */
01422       /*                                                         */
01423       if ( face->type1.private_dict.lenIV >= 0 )
01424       {
01425         FT_Byte*  temp;
01426 
01427 
01428         /* some fonts define empty subr records -- this is not totally */
01429         /* compliant to the specification (which says they should at   */
01430         /* least contain a `return'), but we support them anyway       */
01431         if ( size < face->type1.private_dict.lenIV )
01432         {
01433           error = T1_Err_Invalid_File_Format;
01434           goto Fail;
01435         }
01436 
01437         /* t1_decrypt() shouldn't write to base -- make temporary copy */
01438         if ( FT_ALLOC( temp, size ) )
01439           goto Fail;
01440         FT_MEM_COPY( temp, base, size );
01441         psaux->t1_decrypt( temp, size, 4330 );
01442         size -= face->type1.private_dict.lenIV;
01443         error = T1_Add_Table( table, (FT_Int)idx,
01444                               temp + face->type1.private_dict.lenIV, size );
01445         FT_FREE( temp );
01446       }
01447       else
01448         error = T1_Add_Table( table, (FT_Int)idx, base, size );
01449       if ( error )
01450         goto Fail;
01451     }
01452 
01453     if ( !loader->num_subrs )
01454       loader->num_subrs = num_subrs;
01455 
01456     return;
01457 
01458   Fail:
01459     parser->root.error = error;
01460   }
01461 
01462 
01463 #define TABLE_EXTEND  5
01464 
01465 
01466   static void
01467   parse_charstrings( T1_Face    face,
01468                      T1_Loader  loader )
01469   {
01470     T1_Parser      parser       = &loader->parser;
01471     PS_Table       code_table   = &loader->charstrings;
01472     PS_Table       name_table   = &loader->glyph_names;
01473     PS_Table       swap_table   = &loader->swap_table;
01474     FT_Memory      memory       = parser->root.memory;
01475     FT_Error       error;
01476 
01477     PSAux_Service  psaux        = (PSAux_Service)face->psaux;
01478 
01479     FT_Byte*       cur;
01480     FT_Byte*       limit        = parser->root.limit;
01481     FT_Int         n, num_glyphs;
01482     FT_UInt        notdef_index = 0;
01483     FT_Byte        notdef_found = 0;
01484 
01485 
01486     num_glyphs = (FT_Int)T1_ToInt( parser );
01487     /* some fonts like Optima-Oblique not only define the /CharStrings */
01488     /* array but access it also                                        */
01489     if ( num_glyphs == 0 || parser->root.error )
01490       return;
01491 
01492     /* initialize tables, leaving space for addition of .notdef, */
01493     /* if necessary, and a few other glyphs to handle buggy      */
01494     /* fonts which have more glyphs than specified.              */
01495 
01496     /* for some non-standard fonts like `Optima' which provides  */
01497     /* different outlines depending on the resolution it is      */
01498     /* possible to get here twice                                */
01499     if ( !loader->num_glyphs )
01500     {
01501       error = psaux->ps_table_funcs->init(
01502                 code_table, num_glyphs + 1 + TABLE_EXTEND, memory );
01503       if ( error )
01504         goto Fail;
01505 
01506       error = psaux->ps_table_funcs->init(
01507                 name_table, num_glyphs + 1 + TABLE_EXTEND, memory );
01508       if ( error )
01509         goto Fail;
01510 
01511       /* Initialize table for swapping index notdef_index and */
01512       /* index 0 names and codes (if necessary).              */
01513 
01514       error = psaux->ps_table_funcs->init( swap_table, 4, memory );
01515       if ( error )
01516         goto Fail;
01517     }
01518 
01519     n = 0;
01520 
01521     for (;;)
01522     {
01523       FT_Long   size;
01524       FT_Byte*  base;
01525 
01526 
01527       /* the format is simple:        */
01528       /*   `/glyphname' + binary data */
01529 
01530       T1_Skip_Spaces( parser );
01531 
01532       cur = parser->root.cursor;
01533       if ( cur >= limit )
01534         break;
01535 
01536       /* we stop when we find a `def' or `end' keyword */
01537       if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) )
01538       {
01539         if ( cur[0] == 'd' &&
01540              cur[1] == 'e' &&
01541              cur[2] == 'f' )
01542         {
01543           /* There are fonts which have this: */
01544           /*                                  */
01545           /*   /CharStrings 118 dict def      */
01546           /*   Private begin                  */
01547           /*   CharStrings begin              */
01548           /*   ...                            */
01549           /*                                  */
01550           /* To catch this we ignore `def' if */
01551           /* no charstring has actually been  */
01552           /* seen.                            */
01553           if ( n )
01554             break;
01555         }
01556 
01557         if ( cur[0] == 'e' &&
01558              cur[1] == 'n' &&
01559              cur[2] == 'd' )
01560           break;
01561       }
01562 
01563       T1_Skip_PS_Token( parser );
01564       if ( parser->root.error )
01565         return;
01566 
01567       if ( *cur == '/' )
01568       {
01569         FT_PtrDist  len;
01570 
01571 
01572         if ( cur + 1 >= limit )
01573         {
01574           error = T1_Err_Invalid_File_Format;
01575           goto Fail;
01576         }
01577 
01578         cur++;                              /* skip `/' */
01579         len = parser->root.cursor - cur;
01580 
01581         if ( !read_binary_data( parser, &size, &base ) )
01582           return;
01583 
01584         /* for some non-standard fonts like `Optima' which provides */
01585         /* different outlines depending on the resolution it is     */
01586         /* possible to get here twice                               */
01587         if ( loader->num_glyphs )
01588           continue;
01589 
01590         error = T1_Add_Table( name_table, n, cur, len + 1 );
01591         if ( error )
01592           goto Fail;
01593 
01594         /* add a trailing zero to the name table */
01595         name_table->elements[n][len] = '\0';
01596 
01597         /* record index of /.notdef */
01598         if ( *cur == '.'                                              &&
01599              ft_strcmp( ".notdef",
01600                         (const char*)(name_table->elements[n]) ) == 0 )
01601         {
01602           notdef_index = n;
01603           notdef_found = 1;
01604         }
01605 
01606         if ( face->type1.private_dict.lenIV >= 0 &&
01607              n < num_glyphs + TABLE_EXTEND       )
01608         {
01609           FT_Byte*  temp;
01610 
01611 
01612           if ( size <= face->type1.private_dict.lenIV )
01613           {
01614             error = T1_Err_Invalid_File_Format;
01615             goto Fail;
01616           }
01617 
01618           /* t1_decrypt() shouldn't write to base -- make temporary copy */
01619           if ( FT_ALLOC( temp, size ) )
01620             goto Fail;
01621           FT_MEM_COPY( temp, base, size );
01622           psaux->t1_decrypt( temp, size, 4330 );
01623           size -= face->type1.private_dict.lenIV;
01624           error = T1_Add_Table( code_table, n,
01625                                 temp + face->type1.private_dict.lenIV, size );
01626           FT_FREE( temp );
01627         }
01628         else
01629           error = T1_Add_Table( code_table, n, base, size );
01630         if ( error )
01631           goto Fail;
01632 
01633         n++;
01634       }
01635     }
01636 
01637     loader->num_glyphs = n;
01638 
01639     /* if /.notdef is found but does not occupy index 0, do our magic. */
01640     if ( notdef_found                                                 &&
01641          ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
01642     {
01643       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
01644       /* name and code entries to swap_table.  Then place notdef_index   */
01645       /* name and code entries into swap_table.  Then swap name and code */
01646       /* entries at indices notdef_index and 0 using values stored in    */
01647       /* swap_table.                                                     */
01648 
01649       /* Index 0 name */
01650       error = T1_Add_Table( swap_table, 0,
01651                             name_table->elements[0],
01652                             name_table->lengths [0] );
01653       if ( error )
01654         goto Fail;
01655 
01656       /* Index 0 code */
01657       error = T1_Add_Table( swap_table, 1,
01658                             code_table->elements[0],
01659                             code_table->lengths [0] );
01660       if ( error )
01661         goto Fail;
01662 
01663       /* Index notdef_index name */
01664       error = T1_Add_Table( swap_table, 2,
01665                             name_table->elements[notdef_index],
01666                             name_table->lengths [notdef_index] );
01667       if ( error )
01668         goto Fail;
01669 
01670       /* Index notdef_index code */
01671       error = T1_Add_Table( swap_table, 3,
01672                             code_table->elements[notdef_index],
01673                             code_table->lengths [notdef_index] );
01674       if ( error )
01675         goto Fail;
01676 
01677       error = T1_Add_Table( name_table, notdef_index,
01678                             swap_table->elements[0],
01679                             swap_table->lengths [0] );
01680       if ( error )
01681         goto Fail;
01682 
01683       error = T1_Add_Table( code_table, notdef_index,
01684                             swap_table->elements[1],
01685                             swap_table->lengths [1] );
01686       if ( error )
01687         goto Fail;
01688 
01689       error = T1_Add_Table( name_table, 0,
01690                             swap_table->elements[2],
01691                             swap_table->lengths [2] );
01692       if ( error )
01693         goto Fail;
01694 
01695       error = T1_Add_Table( code_table, 0,
01696                             swap_table->elements[3],
01697                             swap_table->lengths [3] );
01698       if ( error )
01699         goto Fail;
01700 
01701     }
01702     else if ( !notdef_found )
01703     {
01704       /* notdef_index is already 0, or /.notdef is undefined in   */
01705       /* charstrings dictionary.  Worry about /.notdef undefined. */
01706       /* We take index 0 and add it to the end of the table(s)    */
01707       /* and add our own /.notdef glyph to index 0.               */
01708 
01709       /* 0 333 hsbw endchar */
01710       FT_Byte  notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E };
01711       char*    notdef_name    = (char *)".notdef";
01712 
01713 
01714       error = T1_Add_Table( swap_table, 0,
01715                             name_table->elements[0],
01716                             name_table->lengths [0] );
01717       if ( error )
01718         goto Fail;
01719 
01720       error = T1_Add_Table( swap_table, 1,
01721                             code_table->elements[0],
01722                             code_table->lengths [0] );
01723       if ( error )
01724         goto Fail;
01725 
01726       error = T1_Add_Table( name_table, 0, notdef_name, 8 );
01727       if ( error )
01728         goto Fail;
01729 
01730       error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
01731 
01732       if ( error )
01733         goto Fail;
01734 
01735       error = T1_Add_Table( name_table, n,
01736                             swap_table->elements[0],
01737                             swap_table->lengths [0] );
01738       if ( error )
01739         goto Fail;
01740 
01741       error = T1_Add_Table( code_table, n,
01742                             swap_table->elements[1],
01743                             swap_table->lengths [1] );
01744       if ( error )
01745         goto Fail;
01746 
01747       /* we added a glyph. */
01748       loader->num_glyphs += 1;
01749     }
01750 
01751     return;
01752 
01753   Fail:
01754     parser->root.error = error;
01755   }
01756 
01757 
01758   /*************************************************************************/
01759   /*                                                                       */
01760   /* Define the token field static variables.  This is a set of            */
01761   /* T1_FieldRec variables.                                                */
01762   /*                                                                       */
01763   /*************************************************************************/
01764 
01765 
01766   static
01767   const T1_FieldRec  t1_keywords[] =
01768   {
01769 
01770 #include "t1tokens.h"
01771 
01772     /* now add the special functions... */
01773     T1_FIELD_CALLBACK( "FontMatrix",           parse_font_matrix,
01774                        T1_FIELD_DICT_FONTDICT )
01775     T1_FIELD_CALLBACK( "Encoding",             parse_encoding,
01776                        T1_FIELD_DICT_FONTDICT )
01777     T1_FIELD_CALLBACK( "Subrs",                parse_subrs,
01778                        T1_FIELD_DICT_PRIVATE )
01779     T1_FIELD_CALLBACK( "CharStrings",          parse_charstrings,
01780                        T1_FIELD_DICT_PRIVATE )
01781     T1_FIELD_CALLBACK( "Private",              parse_private,
01782                        T1_FIELD_DICT_FONTDICT )
01783 
01784 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
01785     T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions,
01786                        T1_FIELD_DICT_FONTDICT )
01787     T1_FIELD_CALLBACK( "BlendDesignMap",       parse_blend_design_map,
01788                        T1_FIELD_DICT_FONTDICT )
01789     T1_FIELD_CALLBACK( "BlendAxisTypes",       parse_blend_axis_types,
01790                        T1_FIELD_DICT_FONTDICT )
01791     T1_FIELD_CALLBACK( "WeightVector",         parse_weight_vector,
01792                        T1_FIELD_DICT_FONTDICT )
01793     T1_FIELD_CALLBACK( "BuildCharArray",       parse_buildchar,
01794                        T1_FIELD_DICT_PRIVATE )
01795 #endif
01796 
01797     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
01798   };
01799 
01800 
01801 #define T1_FIELD_COUNT                                           \
01802           ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) )
01803 
01804 
01805   static FT_Error
01806   parse_dict( T1_Face    face,
01807               T1_Loader  loader,
01808               FT_Byte*   base,
01809               FT_Long    size )
01810   {
01811     T1_Parser  parser = &loader->parser;
01812     FT_Byte   *limit, *start_binary = NULL;
01813     FT_Bool    have_integer = 0;
01814 
01815 
01816     parser->root.cursor = base;
01817     parser->root.limit  = base + size;
01818     parser->root.error  = T1_Err_Ok;
01819 
01820     limit = parser->root.limit;
01821 
01822     T1_Skip_Spaces( parser );
01823 
01824     while ( parser->root.cursor < limit )
01825     {
01826       FT_Byte*  cur;
01827 
01828 
01829       cur = parser->root.cursor;
01830 
01831       /* look for `eexec' */
01832       if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
01833         break;
01834 
01835       /* look for `closefile' which ends the eexec section */
01836       else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
01837         break;
01838 
01839       /* in a synthetic font the base font starts after a           */
01840       /* `FontDictionary' token that is placed after a Private dict */
01841       else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
01842       {
01843         if ( loader->keywords_encountered & T1_PRIVATE )
01844           loader->keywords_encountered |=
01845             T1_FONTDIR_AFTER_PRIVATE;
01846         parser->root.cursor += 13;
01847       }
01848 
01849       /* check whether we have an integer */
01850       else if ( ft_isdigit( *cur ) )
01851       {
01852         start_binary = cur;
01853         T1_Skip_PS_Token( parser );
01854         if ( parser->root.error )
01855           goto Exit;
01856         have_integer = 1;
01857       }
01858 
01859       /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
01860       /* since those tokens are handled by parse_subrs and        */
01861       /* parse_charstrings                                        */
01862       else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' &&
01863                 have_integer )
01864       {
01865         FT_Long   s;
01866         FT_Byte*  b;
01867 
01868 
01869         parser->root.cursor = start_binary;
01870         if ( !read_binary_data( parser, &s, &b ) )
01871           return T1_Err_Invalid_File_Format;
01872         have_integer = 0;
01873       }
01874 
01875       else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' &&
01876                 have_integer )
01877       {
01878         FT_Long   s;
01879         FT_Byte*  b;
01880 
01881 
01882         parser->root.cursor = start_binary;
01883         if ( !read_binary_data( parser, &s, &b ) )
01884           return T1_Err_Invalid_File_Format;
01885         have_integer = 0;
01886       }
01887 
01888       /* look for immediates */
01889       else if ( *cur == '/' && cur + 2 < limit )
01890       {
01891         FT_PtrDist  len;
01892 
01893 
01894         cur++;
01895 
01896         parser->root.cursor = cur;
01897         T1_Skip_PS_Token( parser );
01898         if ( parser->root.error )
01899           goto Exit;
01900 
01901         len = parser->root.cursor - cur;
01902 
01903         if ( len > 0 && len < 22 && parser->root.cursor < limit )
01904         {
01905           /* now compare the immediate name to the keyword table */
01906           T1_Field  keyword = (T1_Field)t1_keywords;
01907 
01908 
01909           for (;;)
01910           {
01911             FT_Byte*  name;
01912 
01913 
01914             name = (FT_Byte*)keyword->ident;
01915             if ( !name )
01916               break;
01917 
01918             if ( cur[0] == name[0]                                  &&
01919                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
01920                  ft_memcmp( cur, name, len ) == 0                   )
01921             {
01922               /* We found it -- run the parsing callback!     */
01923               /* We record every instance of every field      */
01924               /* (until we reach the base font of a           */
01925               /* synthetic font) to deal adequately with      */
01926               /* multiple master fonts; this is also          */
01927               /* necessary because later PostScript           */
01928               /* definitions override earlier ones.           */
01929 
01930               /* Once we encounter `FontDirectory' after      */
01931               /* `/Private', we know that this is a synthetic */
01932               /* font; except for `/CharStrings' we are not   */
01933               /* interested in anything that follows this     */
01934               /* `FontDirectory'.                             */
01935 
01936               /* MM fonts have more than one /Private token at */
01937               /* the top level; let's hope that all the junk   */
01938               /* that follows the first /Private token is not  */
01939               /* interesting to us.                            */
01940 
01941               /* According to Adobe Tech Note #5175 (CID-Keyed */
01942               /* Font Installation for ATM Software) a `begin' */
01943               /* must be followed by exactly one `end', and    */
01944               /* `begin' -- `end' pairs must be accurately     */
01945               /* paired.  We could use this to distinguish     */
01946               /* between the global Private and the Private    */
01947               /* dict that is a member of the Blend dict.      */
01948 
01949               const FT_UInt dict =
01950                 ( loader->keywords_encountered & T1_PRIVATE )
01951                     ? T1_FIELD_DICT_PRIVATE
01952                     : T1_FIELD_DICT_FONTDICT;
01953 
01954               if ( !( dict & keyword->dict ) )
01955               {
01956                 FT_TRACE1(( "parse_dict: found %s but ignoring it "
01957                             "since it is in the wrong dictionary\n",
01958                             keyword->ident ));
01959                 break;
01960               }
01961 
01962               if ( !( loader->keywords_encountered &
01963                       T1_FONTDIR_AFTER_PRIVATE     )                  ||
01964                    ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
01965               {
01966                 parser->root.error = t1_load_keyword( face,
01967                                                       loader,
01968                                                       keyword );
01969                 if ( parser->root.error != T1_Err_Ok )
01970                 {
01971                   if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore )
01972                     parser->root.error = T1_Err_Ok;
01973                   else
01974                     return parser->root.error;
01975                 }
01976               }
01977               break;
01978             }
01979 
01980             keyword++;
01981           }
01982         }
01983 
01984         have_integer = 0;
01985       }
01986       else
01987       {
01988         T1_Skip_PS_Token( parser );
01989         if ( parser->root.error )
01990           goto Exit;
01991         have_integer = 0;
01992       }
01993 
01994       T1_Skip_Spaces( parser );
01995     }
01996 
01997   Exit:
01998     return parser->root.error;
01999   }
02000 
02001 
02002   static void
02003   t1_init_loader( T1_Loader  loader,
02004                   T1_Face    face )
02005   {
02006     FT_UNUSED( face );
02007 
02008     FT_MEM_ZERO( loader, sizeof ( *loader ) );
02009     loader->num_glyphs = 0;
02010     loader->num_chars  = 0;
02011 
02012     /* initialize the tables -- simply set their `init' field to 0 */
02013     loader->encoding_table.init  = 0;
02014     loader->charstrings.init     = 0;
02015     loader->glyph_names.init     = 0;
02016     loader->subrs.init           = 0;
02017     loader->swap_table.init      = 0;
02018     loader->fontdata             = 0;
02019     loader->keywords_encountered = 0;
02020   }
02021 
02022 
02023   static void
02024   t1_done_loader( T1_Loader  loader )
02025   {
02026     T1_Parser  parser = &loader->parser;
02027 
02028 
02029     /* finalize tables */
02030     T1_Release_Table( &loader->encoding_table );
02031     T1_Release_Table( &loader->charstrings );
02032     T1_Release_Table( &loader->glyph_names );
02033     T1_Release_Table( &loader->swap_table );
02034     T1_Release_Table( &loader->subrs );
02035 
02036     /* finalize parser */
02037     T1_Finalize_Parser( parser );
02038   }
02039 
02040 
02041   FT_LOCAL_DEF( FT_Error )
02042   T1_Open_Face( T1_Face  face )
02043   {
02044     T1_LoaderRec   loader;
02045     T1_Parser      parser;
02046     T1_Font        type1 = &face->type1;
02047     PS_Private     priv  = &type1->private_dict;
02048     FT_Error       error;
02049 
02050     PSAux_Service  psaux = (PSAux_Service)face->psaux;
02051 
02052 
02053     t1_init_loader( &loader, face );
02054 
02055     /* default values */
02056     face->ndv_idx          = -1;
02057     face->cdv_idx          = -1;
02058     face->len_buildchar    = 0;
02059 
02060     priv->blue_shift       = 7;
02061     priv->blue_fuzz        = 1;
02062     priv->lenIV            = 4;
02063     priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
02064     priv->blue_scale       = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
02065 
02066     parser = &loader.parser;
02067     error  = T1_New_Parser( parser,
02068                             face->root.stream,
02069                             face->root.memory,
02070                             psaux );
02071     if ( error )
02072       goto Exit;
02073 
02074     error = parse_dict( face, &loader,
02075                         parser->base_dict, parser->base_len );
02076     if ( error )
02077       goto Exit;
02078 
02079     error = T1_Get_Private_Dict( parser, psaux );
02080     if ( error )
02081       goto Exit;
02082 
02083     error = parse_dict( face, &loader,
02084                         parser->private_dict, parser->private_len );
02085     if ( error )
02086       goto Exit;
02087 
02088     /* ensure even-ness of `num_blue_values' */
02089     priv->num_blue_values &= ~1;
02090 
02091 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
02092 
02093     if ( face->blend                                                     &&
02094          face->blend->num_default_design_vector != 0                     &&
02095          face->blend->num_default_design_vector != face->blend->num_axis )
02096     {
02097       /* we don't use it currently so just warn, reset, and ignore */
02098       FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
02099                  "while there are %u axes.\n",
02100                  face->blend->num_default_design_vector,
02101                  face->blend->num_axis ));
02102 
02103       face->blend->num_default_design_vector = 0;
02104     }
02105 
02106     /* the following can happen for MM instances; we then treat the */
02107     /* font as a normal PS font                                     */
02108     if ( face->blend                                             &&
02109          ( !face->blend->num_designs || !face->blend->num_axis ) )
02110       T1_Done_Blend( face );
02111 
02112     /* another safety check */
02113     if ( face->blend )
02114     {
02115       FT_UInt  i;
02116 
02117 
02118       for ( i = 0; i < face->blend->num_axis; i++ )
02119         if ( !face->blend->design_map[i].num_points )
02120         {
02121           T1_Done_Blend( face );
02122           break;
02123         }
02124     }
02125 
02126     if ( face->blend )
02127     {
02128       if ( face->len_buildchar > 0 )
02129       {
02130         FT_Memory  memory = face->root.memory;
02131 
02132 
02133         if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) )
02134         {
02135           FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" ));
02136           face->len_buildchar = 0;
02137           goto Exit;
02138         }
02139       }
02140     }
02141 
02142 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
02143 
02144     /* now, propagate the subrs, charstrings, and glyphnames tables */
02145     /* to the Type1 data                                            */
02146     type1->num_glyphs = loader.num_glyphs;
02147 
02148     if ( loader.subrs.init )
02149     {
02150       loader.subrs.init  = 0;
02151       type1->num_subrs   = loader.num_subrs;
02152       type1->subrs_block = loader.subrs.block;
02153       type1->subrs       = loader.subrs.elements;
02154       type1->subrs_len   = loader.subrs.lengths;
02155     }
02156 
02157 #ifdef FT_CONFIG_OPTION_INCREMENTAL
02158     if ( !face->root.internal->incremental_interface )
02159 #endif
02160       if ( !loader.charstrings.init )
02161       {
02162         FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
02163         error = T1_Err_Invalid_File_Format;
02164       }
02165 
02166     loader.charstrings.init  = 0;
02167     type1->charstrings_block = loader.charstrings.block;
02168     type1->charstrings       = loader.charstrings.elements;
02169     type1->charstrings_len   = loader.charstrings.lengths;
02170 
02171     /* we copy the glyph names `block' and `elements' fields; */
02172     /* the `lengths' field must be released later             */
02173     type1->glyph_names_block    = loader.glyph_names.block;
02174     type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
02175     loader.glyph_names.block    = 0;
02176     loader.glyph_names.elements = 0;
02177 
02178     /* we must now build type1.encoding when we have a custom array */
02179     if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
02180     {
02181       FT_Int    charcode, idx, min_char, max_char;
02182       FT_Byte*  char_name;
02183       FT_Byte*  glyph_name;
02184 
02185 
02186       /* OK, we do the following: for each element in the encoding  */
02187       /* table, look up the index of the glyph having the same name */
02188       /* the index is then stored in type1.encoding.char_index, and */
02189       /* the name to type1.encoding.char_name                       */
02190 
02191       min_char = 0;
02192       max_char = 0;
02193 
02194       charcode = 0;
02195       for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
02196       {
02197         type1->encoding.char_index[charcode] = 0;
02198         type1->encoding.char_name [charcode] = (char *)".notdef";
02199 
02200         char_name = loader.encoding_table.elements[charcode];
02201         if ( char_name )
02202           for ( idx = 0; idx < type1->num_glyphs; idx++ )
02203           {
02204             glyph_name = (FT_Byte*)type1->glyph_names[idx];
02205             if ( ft_strcmp( (const char*)char_name,
02206                             (const char*)glyph_name ) == 0 )
02207             {
02208               type1->encoding.char_index[charcode] = (FT_UShort)idx;
02209               type1->encoding.char_name [charcode] = (char*)glyph_name;
02210 
02211               /* Change min/max encoded char only if glyph name is */
02212               /* not /.notdef                                      */
02213               if ( ft_strcmp( (const char*)".notdef",
02214                               (const char*)glyph_name ) != 0 )
02215               {
02216                 if ( charcode < min_char )
02217                   min_char = charcode;
02218                 if ( charcode >= max_char )
02219                   max_char = charcode + 1;
02220               }
02221               break;
02222             }
02223           }
02224       }
02225 
02226       type1->encoding.code_first = min_char;
02227       type1->encoding.code_last  = max_char;
02228       type1->encoding.num_chars  = loader.num_chars;
02229     }
02230 
02231   Exit:
02232     t1_done_loader( &loader );
02233     return error;
02234   }
02235 
02236 
02237 /* END */

Generated on Sat May 26 2012 04:32:59 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.