Home | History | Annotate | Download | only in psaux
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  t1decode.c                                                             */
      4 /*                                                                         */
      5 /*    PostScript Type 1 decoding routines (body).                          */
      6 /*                                                                         */
      7 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009    */
      8 /*            2010 by                                                      */
      9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
     10 /*                                                                         */
     11 /*  This file is part of the FreeType project, and may only be used,       */
     12 /*  modified, and distributed under the terms of the FreeType project      */
     13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     14 /*  this file you indicate that you have read the license and              */
     15 /*  understand and accept it fully.                                        */
     16 /*                                                                         */
     17 /***************************************************************************/
     18 
     19 
     20 #include <ft2build.h>
     21 #include FT_INTERNAL_CALC_H
     22 #include FT_INTERNAL_DEBUG_H
     23 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
     24 #include FT_OUTLINE_H
     25 
     26 #include "t1decode.h"
     27 #include "psobjs.h"
     28 
     29 #include "psauxerr.h"
     30 
     31 
     32   /*************************************************************************/
     33   /*                                                                       */
     34   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     35   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     36   /* messages during execution.                                            */
     37   /*                                                                       */
     38 #undef  FT_COMPONENT
     39 #define FT_COMPONENT  trace_t1decode
     40 
     41 
     42   typedef enum  T1_Operator_
     43   {
     44     op_none = 0,
     45     op_endchar,
     46     op_hsbw,
     47     op_seac,
     48     op_sbw,
     49     op_closepath,
     50     op_hlineto,
     51     op_hmoveto,
     52     op_hvcurveto,
     53     op_rlineto,
     54     op_rmoveto,
     55     op_rrcurveto,
     56     op_vhcurveto,
     57     op_vlineto,
     58     op_vmoveto,
     59     op_dotsection,
     60     op_hstem,
     61     op_hstem3,
     62     op_vstem,
     63     op_vstem3,
     64     op_div,
     65     op_callothersubr,
     66     op_callsubr,
     67     op_pop,
     68     op_return,
     69     op_setcurrentpoint,
     70     op_unknown15,
     71 
     72     op_max    /* never remove this one */
     73 
     74   } T1_Operator;
     75 
     76 
     77   static
     78   const FT_Int  t1_args_count[op_max] =
     79   {
     80     0, /* none */
     81     0, /* endchar */
     82     2, /* hsbw */
     83     5, /* seac */
     84     4, /* sbw */
     85     0, /* closepath */
     86     1, /* hlineto */
     87     1, /* hmoveto */
     88     4, /* hvcurveto */
     89     2, /* rlineto */
     90     2, /* rmoveto */
     91     6, /* rrcurveto */
     92     4, /* vhcurveto */
     93     1, /* vlineto */
     94     1, /* vmoveto */
     95     0, /* dotsection */
     96     2, /* hstem */
     97     6, /* hstem3 */
     98     2, /* vstem */
     99     6, /* vstem3 */
    100     2, /* div */
    101    -1, /* callothersubr */
    102     1, /* callsubr */
    103     0, /* pop */
    104     0, /* return */
    105     2, /* setcurrentpoint */
    106     2  /* opcode 15 (undocumented and obsolete) */
    107   };
    108 
    109 
    110   /*************************************************************************/
    111   /*                                                                       */
    112   /* <Function>                                                            */
    113   /*    t1_lookup_glyph_by_stdcharcode                                     */
    114   /*                                                                       */
    115   /* <Description>                                                         */
    116   /*    Looks up a given glyph by its StandardEncoding charcode.  Used to  */
    117   /*    implement the SEAC Type 1 operator.                                */
    118   /*                                                                       */
    119   /* <Input>                                                               */
    120   /*    face     :: The current face object.                               */
    121   /*                                                                       */
    122   /*    charcode :: The character code to look for.                        */
    123   /*                                                                       */
    124   /* <Return>                                                              */
    125   /*    A glyph index in the font face.  Returns -1 if the corresponding   */
    126   /*    glyph wasn't found.                                                */
    127   /*                                                                       */
    128   static FT_Int
    129   t1_lookup_glyph_by_stdcharcode( T1_Decoder  decoder,
    130                                   FT_Int      charcode )
    131   {
    132     FT_UInt             n;
    133     const FT_String*    glyph_name;
    134     FT_Service_PsCMaps  psnames = decoder->psnames;
    135 
    136 
    137     /* check range of standard char code */
    138     if ( charcode < 0 || charcode > 255 )
    139       return -1;
    140 
    141     glyph_name = psnames->adobe_std_strings(
    142                    psnames->adobe_std_encoding[charcode]);
    143 
    144     for ( n = 0; n < decoder->num_glyphs; n++ )
    145     {
    146       FT_String*  name = (FT_String*)decoder->glyph_names[n];
    147 
    148 
    149       if ( name                               &&
    150            name[0] == glyph_name[0]           &&
    151            ft_strcmp( name, glyph_name ) == 0 )
    152         return n;
    153     }
    154 
    155     return -1;
    156   }
    157 
    158 
    159   /*************************************************************************/
    160   /*                                                                       */
    161   /* <Function>                                                            */
    162   /*    t1operator_seac                                                    */
    163   /*                                                                       */
    164   /* <Description>                                                         */
    165   /*    Implements the `seac' Type 1 operator for a Type 1 decoder.        */
    166   /*                                                                       */
    167   /* <Input>                                                               */
    168   /*    decoder :: The current CID decoder.                                */
    169   /*                                                                       */
    170   /*    asb     :: The accent's side bearing.                              */
    171   /*                                                                       */
    172   /*    adx     :: The horizontal offset of the accent.                    */
    173   /*                                                                       */
    174   /*    ady     :: The vertical offset of the accent.                      */
    175   /*                                                                       */
    176   /*    bchar   :: The base character's StandardEncoding charcode.         */
    177   /*                                                                       */
    178   /*    achar   :: The accent character's StandardEncoding charcode.       */
    179   /*                                                                       */
    180   /* <Return>                                                              */
    181   /*    FreeType error code.  0 means success.                             */
    182   /*                                                                       */
    183   static FT_Error
    184   t1operator_seac( T1_Decoder  decoder,
    185                    FT_Pos      asb,
    186                    FT_Pos      adx,
    187                    FT_Pos      ady,
    188                    FT_Int      bchar,
    189                    FT_Int      achar )
    190   {
    191     FT_Error     error;
    192     FT_Int       bchar_index, achar_index;
    193 #if 0
    194     FT_Int       n_base_points;
    195     FT_Outline*  base = decoder->builder.base;
    196 #endif
    197     FT_Vector    left_bearing, advance;
    198 
    199 #ifdef FT_CONFIG_OPTION_INCREMENTAL
    200     T1_Face      face  = (T1_Face)decoder->builder.face;
    201 #endif
    202 
    203 
    204     if ( decoder->seac )
    205     {
    206       FT_ERROR(( "t1operator_seac: invalid nested seac\n" ));
    207       return PSaux_Err_Syntax_Error;
    208     }
    209 
    210     /* seac weirdness */
    211     adx += decoder->builder.left_bearing.x;
    212 
    213     /* `glyph_names' is set to 0 for CID fonts which do not */
    214     /* include an encoding.  How can we deal with these?    */
    215 #ifdef FT_CONFIG_OPTION_INCREMENTAL
    216     if ( decoder->glyph_names == 0                   &&
    217          !face->root.internal->incremental_interface )
    218 #else
    219     if ( decoder->glyph_names == 0 )
    220 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
    221     {
    222       FT_ERROR(( "t1operator_seac:"
    223                  " glyph names table not available in this font\n" ));
    224       return PSaux_Err_Syntax_Error;
    225     }
    226 
    227 #ifdef FT_CONFIG_OPTION_INCREMENTAL
    228     if ( face->root.internal->incremental_interface )
    229     {
    230       /* the caller must handle the font encoding also */
    231       bchar_index = bchar;
    232       achar_index = achar;
    233     }
    234     else
    235 #endif
    236     {
    237       bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar );
    238       achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar );
    239     }
    240 
    241     if ( bchar_index < 0 || achar_index < 0 )
    242     {
    243       FT_ERROR(( "t1operator_seac:"
    244                  " invalid seac character code arguments\n" ));
    245       return PSaux_Err_Syntax_Error;
    246     }
    247 
    248     /* if we are trying to load a composite glyph, do not load the */
    249     /* accent character and return the array of subglyphs.         */
    250     if ( decoder->builder.no_recurse )
    251     {
    252       FT_GlyphSlot    glyph  = (FT_GlyphSlot)decoder->builder.glyph;
    253       FT_GlyphLoader  loader = glyph->internal->loader;
    254       FT_SubGlyph     subg;
    255 
    256 
    257       /* reallocate subglyph array if necessary */
    258       error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
    259       if ( error )
    260         goto Exit;
    261 
    262       subg = loader->current.subglyphs;
    263 
    264       /* subglyph 0 = base character */
    265       subg->index = bchar_index;
    266       subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
    267                     FT_SUBGLYPH_FLAG_USE_MY_METRICS;
    268       subg->arg1  = 0;
    269       subg->arg2  = 0;
    270       subg++;
    271 
    272       /* subglyph 1 = accent character */
    273       subg->index = achar_index;
    274       subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
    275       subg->arg1  = (FT_Int)FIXED_TO_INT( adx - asb );
    276       subg->arg2  = (FT_Int)FIXED_TO_INT( ady );
    277 
    278       /* set up remaining glyph fields */
    279       glyph->num_subglyphs = 2;
    280       glyph->subglyphs     = loader->base.subglyphs;
    281       glyph->format        = FT_GLYPH_FORMAT_COMPOSITE;
    282 
    283       loader->current.num_subglyphs = 2;
    284       goto Exit;
    285     }
    286 
    287     /* First load `bchar' in builder */
    288     /* now load the unscaled outline */
    289 
    290     FT_GlyphLoader_Prepare( decoder->builder.loader );  /* prepare loader */
    291 
    292     /* the seac operator must not be nested */
    293     decoder->seac = TRUE;
    294     error = t1_decoder_parse_glyph( decoder, bchar_index );
    295     decoder->seac = FALSE;
    296     if ( error )
    297       goto Exit;
    298 
    299     /* save the left bearing and width of the base character */
    300     /* as they will be erased by the next load.              */
    301 
    302     left_bearing = decoder->builder.left_bearing;
    303     advance      = decoder->builder.advance;
    304 
    305     decoder->builder.left_bearing.x = 0;
    306     decoder->builder.left_bearing.y = 0;
    307 
    308     decoder->builder.pos_x = adx - asb;
    309     decoder->builder.pos_y = ady;
    310 
    311     /* Now load `achar' on top of */
    312     /* the base outline           */
    313 
    314     /* the seac operator must not be nested */
    315     decoder->seac = TRUE;
    316     error = t1_decoder_parse_glyph( decoder, achar_index );
    317     decoder->seac = FALSE;
    318     if ( error )
    319       goto Exit;
    320 
    321     /* restore the left side bearing and   */
    322     /* advance width of the base character */
    323 
    324     decoder->builder.left_bearing = left_bearing;
    325     decoder->builder.advance      = advance;
    326 
    327     decoder->builder.pos_x = 0;
    328     decoder->builder.pos_y = 0;
    329 
    330   Exit:
    331     return error;
    332   }
    333 
    334 
    335   /*************************************************************************/
    336   /*                                                                       */
    337   /* <Function>                                                            */
    338   /*    t1_decoder_parse_charstrings                                       */
    339   /*                                                                       */
    340   /* <Description>                                                         */
    341   /*    Parses a given Type 1 charstrings program.                         */
    342   /*                                                                       */
    343   /* <Input>                                                               */
    344   /*    decoder         :: The current Type 1 decoder.                     */
    345   /*                                                                       */
    346   /*    charstring_base :: The base address of the charstring stream.      */
    347   /*                                                                       */
    348   /*    charstring_len  :: The length in bytes of the charstring stream.   */
    349   /*                                                                       */
    350   /* <Return>                                                              */
    351   /*    FreeType error code.  0 means success.                             */
    352   /*                                                                       */
    353   FT_LOCAL_DEF( FT_Error )
    354   t1_decoder_parse_charstrings( T1_Decoder  decoder,
    355                                 FT_Byte*    charstring_base,
    356                                 FT_UInt     charstring_len )
    357   {
    358     FT_Error         error;
    359     T1_Decoder_Zone  zone;
    360     FT_Byte*         ip;
    361     FT_Byte*         limit;
    362     T1_Builder       builder = &decoder->builder;
    363     FT_Pos           x, y, orig_x, orig_y;
    364     FT_Int           known_othersubr_result_cnt   = 0;
    365     FT_Int           unknown_othersubr_result_cnt = 0;
    366     FT_Bool          large_int;
    367     FT_Fixed         seed;
    368 
    369     T1_Hints_Funcs   hinter;
    370 
    371 #ifdef FT_DEBUG_LEVEL_TRACE
    372     FT_Bool          bol = TRUE;
    373 #endif
    374 
    375 
    376     /* we don't want to touch the source code -- use macro trick */
    377 #define start_point    t1_builder_start_point
    378 #define check_points   t1_builder_check_points
    379 #define add_point      t1_builder_add_point
    380 #define add_point1     t1_builder_add_point1
    381 #define add_contour    t1_builder_add_contour
    382 #define close_contour  t1_builder_close_contour
    383 
    384 
    385     /* compute random seed from stack address of parameter */
    386     seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed              ^
    387                          (FT_PtrDist)(char*)&decoder           ^
    388                          (FT_PtrDist)(char*)&charstring_base ) &
    389                          FT_ULONG_MAX ) ;
    390     seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
    391     if ( seed == 0 )
    392       seed = 0x7384;
    393 
    394     /* First of all, initialize the decoder */
    395     decoder->top  = decoder->stack;
    396     decoder->zone = decoder->zones;
    397     zone          = decoder->zones;
    398 
    399     builder->parse_state = T1_Parse_Start;
    400 
    401     hinter = (T1_Hints_Funcs)builder->hints_funcs;
    402 
    403     /* a font that reads BuildCharArray without setting */
    404     /* its values first is buggy, but ...               */
    405     FT_ASSERT( ( decoder->len_buildchar == 0 ) ==
    406                ( decoder->buildchar == NULL )  );
    407 
    408     if ( decoder->len_buildchar > 0 )
    409       ft_memset( &decoder->buildchar[0],
    410                  0,
    411                  sizeof( decoder->buildchar[0] ) * decoder->len_buildchar );
    412 
    413     FT_TRACE4(( "\n"
    414                 "Start charstring\n" ));
    415 
    416     zone->base           = charstring_base;
    417     limit = zone->limit  = charstring_base + charstring_len;
    418     ip    = zone->cursor = zone->base;
    419 
    420     error = PSaux_Err_Ok;
    421 
    422     x = orig_x = builder->pos_x;
    423     y = orig_y = builder->pos_y;
    424 
    425     /* begin hints recording session, if any */
    426     if ( hinter )
    427       hinter->open( hinter->hints );
    428 
    429     large_int = FALSE;
    430 
    431     /* now, execute loop */
    432     while ( ip < limit )
    433     {
    434       FT_Long*     top   = decoder->top;
    435       T1_Operator  op    = op_none;
    436       FT_Int32     value = 0;
    437 
    438 
    439       FT_ASSERT( known_othersubr_result_cnt == 0   ||
    440                  unknown_othersubr_result_cnt == 0 );
    441 
    442 #ifdef FT_DEBUG_LEVEL_TRACE
    443       if ( bol )
    444       {
    445         FT_TRACE5(( " (%d)", decoder->top - decoder->stack ));
    446         bol = FALSE;
    447       }
    448 #endif
    449 
    450       /*********************************************************************/
    451       /*                                                                   */
    452       /* Decode operator or operand                                        */
    453       /*                                                                   */
    454       /*                                                                   */
    455 
    456       /* first of all, decompress operator or value */
    457       switch ( *ip++ )
    458       {
    459       case 1:
    460         op = op_hstem;
    461         break;
    462 
    463       case 3:
    464         op = op_vstem;
    465         break;
    466       case 4:
    467         op = op_vmoveto;
    468         break;
    469       case 5:
    470         op = op_rlineto;
    471         break;
    472       case 6:
    473         op = op_hlineto;
    474         break;
    475       case 7:
    476         op = op_vlineto;
    477         break;
    478       case 8:
    479         op = op_rrcurveto;
    480         break;
    481       case 9:
    482         op = op_closepath;
    483         break;
    484       case 10:
    485         op = op_callsubr;
    486         break;
    487       case 11:
    488         op = op_return;
    489         break;
    490 
    491       case 13:
    492         op = op_hsbw;
    493         break;
    494       case 14:
    495         op = op_endchar;
    496         break;
    497 
    498       case 15:          /* undocumented, obsolete operator */
    499         op = op_unknown15;
    500         break;
    501 
    502       case 21:
    503         op = op_rmoveto;
    504         break;
    505       case 22:
    506         op = op_hmoveto;
    507         break;
    508 
    509       case 30:
    510         op = op_vhcurveto;
    511         break;
    512       case 31:
    513         op = op_hvcurveto;
    514         break;
    515 
    516       case 12:
    517         if ( ip > limit )
    518         {
    519           FT_ERROR(( "t1_decoder_parse_charstrings:"
    520                      " invalid escape (12+EOF)\n" ));
    521           goto Syntax_Error;
    522         }
    523 
    524         switch ( *ip++ )
    525         {
    526         case 0:
    527           op = op_dotsection;
    528           break;
    529         case 1:
    530           op = op_vstem3;
    531           break;
    532         case 2:
    533           op = op_hstem3;
    534           break;
    535         case 6:
    536           op = op_seac;
    537           break;
    538         case 7:
    539           op = op_sbw;
    540           break;
    541         case 12:
    542           op = op_div;
    543           break;
    544         case 16:
    545           op = op_callothersubr;
    546           break;
    547         case 17:
    548           op = op_pop;
    549           break;
    550         case 33:
    551           op = op_setcurrentpoint;
    552           break;
    553 
    554         default:
    555           FT_ERROR(( "t1_decoder_parse_charstrings:"
    556                      " invalid escape (12+%d)\n",
    557                      ip[-1] ));
    558           goto Syntax_Error;
    559         }
    560         break;
    561 
    562       case 255:    /* four bytes integer */
    563         if ( ip + 4 > limit )
    564         {
    565           FT_ERROR(( "t1_decoder_parse_charstrings:"
    566                      " unexpected EOF in integer\n" ));
    567           goto Syntax_Error;
    568         }
    569 
    570         value = (FT_Int32)( ( (FT_Long)ip[0] << 24 ) |
    571                             ( (FT_Long)ip[1] << 16 ) |
    572                             ( (FT_Long)ip[2] << 8  ) |
    573                                        ip[3]         );
    574         ip += 4;
    575 
    576         /* According to the specification, values > 32000 or < -32000 must */
    577         /* be followed by a `div' operator to make the result be in the    */
    578         /* range [-32000;32000].  We expect that the second argument of    */
    579         /* `div' is not a large number.  Additionally, we don't handle     */
    580         /* stuff like `<large1> <large2> <num> div <num> div' or           */
    581         /* <large1> <large2> <num> div div'.  This is probably not allowed */
    582         /* anyway.                                                         */
    583         if ( value > 32000 || value < -32000 )
    584         {
    585           if ( large_int )
    586           {
    587             FT_ERROR(( "t1_decoder_parse_charstrings:"
    588                        " no `div' after large integer\n" ));
    589           }
    590           else
    591             large_int = TRUE;
    592         }
    593         else
    594         {
    595           if ( !large_int )
    596             value <<= 16;
    597         }
    598 
    599         break;
    600 
    601       default:
    602         if ( ip[-1] >= 32 )
    603         {
    604           if ( ip[-1] < 247 )
    605             value = (FT_Int32)ip[-1] - 139;
    606           else
    607           {
    608             if ( ++ip > limit )
    609             {
    610               FT_ERROR(( "t1_decoder_parse_charstrings:"
    611                          " unexpected EOF in integer\n" ));
    612               goto Syntax_Error;
    613             }
    614 
    615             if ( ip[-2] < 251 )
    616               value =  ( ( (FT_Int32)ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
    617             else
    618               value = -( ( ( (FT_Int32)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
    619           }
    620 
    621           if ( !large_int )
    622             value <<= 16;
    623         }
    624         else
    625         {
    626           FT_ERROR(( "t1_decoder_parse_charstrings:"
    627                      " invalid byte (%d)\n", ip[-1] ));
    628           goto Syntax_Error;
    629         }
    630       }
    631 
    632       if ( unknown_othersubr_result_cnt > 0 )
    633       {
    634         switch ( op )
    635         {
    636         case op_callsubr:
    637         case op_return:
    638         case op_none:
    639         case op_pop:
    640           break;
    641 
    642         default:
    643           /* all operands have been transferred by previous pops */
    644           unknown_othersubr_result_cnt = 0;
    645           break;
    646         }
    647       }
    648 
    649       if ( large_int && !( op == op_none || op == op_div ) )
    650       {
    651         FT_ERROR(( "t1_decoder_parse_charstrings:"
    652                    " no `div' after large integer\n" ));
    653 
    654         large_int = FALSE;
    655       }
    656 
    657       /*********************************************************************/
    658       /*                                                                   */
    659       /*  Push value on stack, or process operator                         */
    660       /*                                                                   */
    661       /*                                                                   */
    662       if ( op == op_none )
    663       {
    664         if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
    665         {
    666           FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow\n" ));
    667           goto Syntax_Error;
    668         }
    669 
    670 #ifdef FT_DEBUG_LEVEL_TRACE
    671         if ( large_int )
    672           FT_TRACE4(( " %ld", value ));
    673         else
    674           FT_TRACE4(( " %ld", (FT_Int32)( value >> 16 ) ));
    675 #endif
    676 
    677         *top++       = value;
    678         decoder->top = top;
    679       }
    680       else if ( op == op_callothersubr )  /* callothersubr */
    681       {
    682         FT_Int  subr_no;
    683         FT_Int  arg_cnt;
    684 
    685 
    686 #ifdef FT_DEBUG_LEVEL_TRACE
    687         FT_TRACE4(( " callothersubr\n" ));
    688         bol = TRUE;
    689 #endif
    690 
    691         if ( top - decoder->stack < 2 )
    692           goto Stack_Underflow;
    693 
    694         top -= 2;
    695 
    696         subr_no = (FT_Int)( top[1] >> 16 );
    697         arg_cnt = (FT_Int)( top[0] >> 16 );
    698 
    699         /***********************************************************/
    700         /*                                                         */
    701         /* remove all operands to callothersubr from the stack     */
    702         /*                                                         */
    703         /* for handled othersubrs, where we know the number of     */
    704         /* arguments, we increase the stack by the value of        */
    705         /* known_othersubr_result_cnt                              */
    706         /*                                                         */
    707         /* for unhandled othersubrs the following pops adjust the  */
    708         /* stack pointer as necessary                              */
    709 
    710         if ( arg_cnt > top - decoder->stack )
    711           goto Stack_Underflow;
    712 
    713         top -= arg_cnt;
    714 
    715         known_othersubr_result_cnt   = 0;
    716         unknown_othersubr_result_cnt = 0;
    717 
    718         /* XXX TODO: The checks to `arg_count == <whatever>'       */
    719         /* might not be correct; an othersubr expects a certain    */
    720         /* number of operands on the PostScript stack (as opposed  */
    721         /* to the T1 stack) but it doesn't have to put them there  */
    722         /* by itself; previous othersubrs might have left the      */
    723         /* operands there if they were not followed by an          */
    724         /* appropriate number of pops                              */
    725         /*                                                         */
    726         /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
    727         /* accept a font that contains charstrings like            */
    728         /*                                                         */
    729         /*     100 200 2 20 callothersubr                          */
    730         /*     300 1 20 callothersubr pop                          */
    731         /*                                                         */
    732         /* Perhaps this is the reason why BuildCharArray exists.   */
    733 
    734         switch ( subr_no )
    735         {
    736         case 1:                     /* start flex feature */
    737           if ( arg_cnt != 0 )
    738             goto Unexpected_OtherSubr;
    739 
    740           decoder->flex_state        = 1;
    741           decoder->num_flex_vectors  = 0;
    742           if ( start_point( builder, x, y ) ||
    743                check_points( builder, 6 )   )
    744             goto Fail;
    745           break;
    746 
    747         case 2:                     /* add flex vectors */
    748           {
    749             FT_Int  idx;
    750 
    751 
    752             if ( arg_cnt != 0 )
    753               goto Unexpected_OtherSubr;
    754 
    755             /* note that we should not add a point for index 0; */
    756             /* this will move our current position to the flex  */
    757             /* point without adding any point to the outline    */
    758             idx = decoder->num_flex_vectors++;
    759             if ( idx > 0 && idx < 7 )
    760               add_point( builder,
    761                          x,
    762                          y,
    763                          (FT_Byte)( idx == 3 || idx == 6 ) );
    764           }
    765           break;
    766 
    767         case 0:                     /* end flex feature */
    768           if ( arg_cnt != 3 )
    769             goto Unexpected_OtherSubr;
    770 
    771           if ( decoder->flex_state       == 0 ||
    772                decoder->num_flex_vectors != 7 )
    773           {
    774             FT_ERROR(( "t1_decoder_parse_charstrings:"
    775                        " unexpected flex end\n" ));
    776             goto Syntax_Error;
    777           }
    778 
    779           /* the two `results' are popped by the following setcurrentpoint */
    780           top[0] = x;
    781           top[1] = y;
    782           known_othersubr_result_cnt = 2;
    783           break;
    784 
    785         case 3:                     /* change hints */
    786           if ( arg_cnt != 1 )
    787             goto Unexpected_OtherSubr;
    788 
    789           known_othersubr_result_cnt = 1;
    790 
    791           if ( hinter )
    792             hinter->reset( hinter->hints, builder->current->n_points );
    793           break;
    794 
    795         case 12:
    796         case 13:
    797           /* counter control hints, clear stack */
    798           top = decoder->stack;
    799           break;
    800 
    801         case 14:
    802         case 15:
    803         case 16:
    804         case 17:
    805         case 18:                    /* multiple masters */
    806           {
    807             PS_Blend  blend = decoder->blend;
    808             FT_UInt   num_points, nn, mm;
    809             FT_Long*  delta;
    810             FT_Long*  values;
    811 
    812 
    813             if ( !blend )
    814             {
    815               FT_ERROR(( "t1_decoder_parse_charstrings:"
    816                          " unexpected multiple masters operator\n" ));
    817               goto Syntax_Error;
    818             }
    819 
    820             num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 );
    821             if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) )
    822             {
    823               FT_ERROR(( "t1_decoder_parse_charstrings:"
    824                          " incorrect number of multiple masters arguments\n" ));
    825               goto Syntax_Error;
    826             }
    827 
    828             /* we want to compute:                                   */
    829             /*                                                       */
    830             /*  a0*w0 + a1*w1 + ... + ak*wk                          */
    831             /*                                                       */
    832             /* but we only have the a0, a1-a0, a2-a0, .. ak-a0       */
    833             /* however, given that w0 + w1 + ... + wk == 1, we can   */
    834             /* rewrite it easily as:                                 */
    835             /*                                                       */
    836             /*  a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk       */
    837             /*                                                       */
    838             /* where k == num_designs-1                              */
    839             /*                                                       */
    840             /* I guess that's why it's written in this `compact'     */
    841             /* form.                                                 */
    842             /*                                                       */
    843             delta  = top + num_points;
    844             values = top;
    845             for ( nn = 0; nn < num_points; nn++ )
    846             {
    847               FT_Long  tmp = values[0];
    848 
    849 
    850               for ( mm = 1; mm < blend->num_designs; mm++ )
    851                 tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
    852 
    853               *values++ = tmp;
    854             }
    855 
    856             known_othersubr_result_cnt = num_points;
    857             break;
    858           }
    859 
    860         case 19:
    861           /* <idx> 1 19 callothersubr                             */
    862           /* => replace elements starting from index cvi( <idx> ) */
    863           /*    of BuildCharArray with WeightVector               */
    864           {
    865             FT_Int    idx;
    866             PS_Blend  blend = decoder->blend;
    867 
    868 
    869             if ( arg_cnt != 1 || blend == NULL )
    870               goto Unexpected_OtherSubr;
    871 
    872             idx = (FT_Int)( top[0] >> 16 );
    873 
    874             if ( idx < 0                                           ||
    875                  idx + blend->num_designs > decoder->len_buildchar )
    876               goto Unexpected_OtherSubr;
    877 
    878             ft_memcpy( &decoder->buildchar[idx],
    879                        blend->weight_vector,
    880                        blend->num_designs *
    881                          sizeof( blend->weight_vector[0] ) );
    882           }
    883           break;
    884 
    885         case 20:
    886           /* <arg1> <arg2> 2 20 callothersubr pop   */
    887           /* ==> push <arg1> + <arg2> onto T1 stack */
    888           if ( arg_cnt != 2 )
    889             goto Unexpected_OtherSubr;
    890 
    891           top[0] += top[1]; /* XXX (over|under)flow */
    892 
    893           known_othersubr_result_cnt = 1;
    894           break;
    895 
    896         case 21:
    897           /* <arg1> <arg2> 2 21 callothersubr pop   */
    898           /* ==> push <arg1> - <arg2> onto T1 stack */
    899           if ( arg_cnt != 2 )
    900             goto Unexpected_OtherSubr;
    901 
    902           top[0] -= top[1]; /* XXX (over|under)flow */
    903 
    904           known_othersubr_result_cnt = 1;
    905           break;
    906 
    907         case 22:
    908           /* <arg1> <arg2> 2 22 callothersubr pop   */
    909           /* ==> push <arg1> * <arg2> onto T1 stack */
    910           if ( arg_cnt != 2 )
    911             goto Unexpected_OtherSubr;
    912 
    913           top[0] = FT_MulFix( top[0], top[1] );
    914 
    915           known_othersubr_result_cnt = 1;
    916           break;
    917 
    918         case 23:
    919           /* <arg1> <arg2> 2 23 callothersubr pop   */
    920           /* ==> push <arg1> / <arg2> onto T1 stack */
    921           if ( arg_cnt != 2 || top[1] == 0 )
    922             goto Unexpected_OtherSubr;
    923 
    924           top[0] = FT_DivFix( top[0], top[1] );
    925 
    926           known_othersubr_result_cnt = 1;
    927           break;
    928 
    929         case 24:
    930           /* <val> <idx> 2 24 callothersubr               */
    931           /* ==> set BuildCharArray[cvi( <idx> )] = <val> */
    932           {
    933             FT_Int    idx;
    934             PS_Blend  blend = decoder->blend;
    935 
    936 
    937             if ( arg_cnt != 2 || blend == NULL )
    938               goto Unexpected_OtherSubr;
    939 
    940             idx = (FT_Int)( top[1] >> 16 );
    941 
    942             if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
    943               goto Unexpected_OtherSubr;
    944 
    945             decoder->buildchar[idx] = top[0];
    946           }
    947           break;
    948 
    949         case 25:
    950           /* <idx> 1 25 callothersubr pop        */
    951           /* ==> push BuildCharArray[cvi( idx )] */
    952           /*     onto T1 stack                   */
    953           {
    954             FT_Int    idx;
    955             PS_Blend  blend = decoder->blend;
    956 
    957 
    958             if ( arg_cnt != 1 || blend == NULL )
    959               goto Unexpected_OtherSubr;
    960 
    961             idx = (FT_Int)( top[0] >> 16 );
    962 
    963             if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
    964               goto Unexpected_OtherSubr;
    965 
    966             top[0] = decoder->buildchar[idx];
    967           }
    968 
    969           known_othersubr_result_cnt = 1;
    970           break;
    971 
    972 #if 0
    973         case 26:
    974           /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
    975           /*                      leave mark on T1 stack                    */
    976           /* <val> <idx>      ==> set BuildCharArray[cvi( <idx> )] = <val>  */
    977           XXX which routine has left its mark on the (PostScript) stack?;
    978           break;
    979 #endif
    980 
    981         case 27:
    982           /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
    983           /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
    984           /*     otherwise push <res2>                          */
    985           if ( arg_cnt != 4 )
    986             goto Unexpected_OtherSubr;
    987 
    988           if ( top[2] > top[3] )
    989             top[0] = top[1];
    990 
    991           known_othersubr_result_cnt = 1;
    992           break;
    993 
    994         case 28:
    995           /* 0 28 callothersubr pop                               */
    996           /* => push random value from interval [0, 1) onto stack */
    997           if ( arg_cnt != 0 )
    998             goto Unexpected_OtherSubr;
    999 
   1000           {
   1001             FT_Fixed  Rand;
   1002 
   1003 
   1004             Rand = seed;
   1005             if ( Rand >= 0x8000L )
   1006               Rand++;
   1007 
   1008             top[0] = Rand;
   1009 
   1010             seed = FT_MulFix( seed, 0x10000L - seed );
   1011             if ( seed == 0 )
   1012               seed += 0x2873;
   1013           }
   1014 
   1015           known_othersubr_result_cnt = 1;
   1016           break;
   1017 
   1018         default:
   1019           FT_ERROR(( "t1_decoder_parse_charstrings:"
   1020                      " unknown othersubr [%d %d], wish me luck\n",
   1021                      arg_cnt, subr_no ));
   1022           unknown_othersubr_result_cnt = arg_cnt;
   1023           break;
   1024 
   1025         Unexpected_OtherSubr:
   1026           FT_ERROR(( "t1_decoder_parse_charstrings:"
   1027                      " invalid othersubr [%d %d]\n", arg_cnt, subr_no ));
   1028           goto Syntax_Error;
   1029         }
   1030 
   1031         top += known_othersubr_result_cnt;
   1032 
   1033         decoder->top = top;
   1034       }
   1035       else  /* general operator */
   1036       {
   1037         FT_Int  num_args = t1_args_count[op];
   1038 
   1039 
   1040         FT_ASSERT( num_args >= 0 );
   1041 
   1042         if ( top - decoder->stack < num_args )
   1043           goto Stack_Underflow;
   1044 
   1045         /* XXX Operators usually take their operands from the        */
   1046         /*     bottom of the stack, i.e., the operands are           */
   1047         /*     decoder->stack[0], ..., decoder->stack[num_args - 1]; */
   1048         /*     only div, callsubr, and callothersubr are different.  */
   1049         /*     In practice it doesn't matter (?).                    */
   1050 
   1051 #ifdef FT_DEBUG_LEVEL_TRACE
   1052 
   1053         switch ( op )
   1054         {
   1055         case op_callsubr:
   1056         case op_div:
   1057         case op_callothersubr:
   1058         case op_pop:
   1059         case op_return:
   1060           break;
   1061 
   1062         default:
   1063           if ( top - decoder->stack != num_args )
   1064             FT_TRACE0(( "t1_decoder_parse_charstrings:"
   1065                         " too much operands on the stack"
   1066                         " (seen %d, expected %d)\n",
   1067                         top - decoder->stack, num_args ));
   1068             break;
   1069         }
   1070 
   1071 #endif /* FT_DEBUG_LEVEL_TRACE */
   1072 
   1073         top -= num_args;
   1074 
   1075         switch ( op )
   1076         {
   1077         case op_endchar:
   1078           FT_TRACE4(( " endchar\n" ));
   1079 
   1080           close_contour( builder );
   1081 
   1082           /* close hints recording session */
   1083           if ( hinter )
   1084           {
   1085             if ( hinter->close( hinter->hints, builder->current->n_points ) )
   1086               goto Syntax_Error;
   1087 
   1088             /* apply hints to the loaded glyph outline now */
   1089             hinter->apply( hinter->hints,
   1090                            builder->current,
   1091                            (PSH_Globals)builder->hints_globals,
   1092                            decoder->hint_mode );
   1093           }
   1094 
   1095           /* add current outline to the glyph slot */
   1096           FT_GlyphLoader_Add( builder->loader );
   1097 
   1098           /* the compiler should optimize away this empty loop but ... */
   1099 
   1100 #ifdef FT_DEBUG_LEVEL_TRACE
   1101 
   1102           if ( decoder->len_buildchar > 0 )
   1103           {
   1104             FT_UInt  i;
   1105 
   1106 
   1107             FT_TRACE4(( "BuildCharArray = [ " ));
   1108 
   1109             for ( i = 0; i < decoder->len_buildchar; ++i )
   1110               FT_TRACE4(( "%d ", decoder->buildchar[ i ] ));
   1111 
   1112             FT_TRACE4(( "]\n" ));
   1113           }
   1114 
   1115 #endif /* FT_DEBUG_LEVEL_TRACE */
   1116 
   1117           FT_TRACE4(( "\n" ));
   1118 
   1119           /* return now! */
   1120           return PSaux_Err_Ok;
   1121 
   1122         case op_hsbw:
   1123           FT_TRACE4(( " hsbw" ));
   1124 
   1125           builder->parse_state = T1_Parse_Have_Width;
   1126 
   1127           builder->left_bearing.x += top[0];
   1128           builder->advance.x       = top[1];
   1129           builder->advance.y       = 0;
   1130 
   1131           orig_x = x = builder->pos_x + top[0];
   1132           orig_y = y = builder->pos_y;
   1133 
   1134           FT_UNUSED( orig_y );
   1135 
   1136           /* the `metrics_only' indicates that we only want to compute */
   1137           /* the glyph's metrics (lsb + advance width), not load the   */
   1138           /* rest of it; so exit immediately                           */
   1139           if ( builder->metrics_only )
   1140             return PSaux_Err_Ok;
   1141 
   1142           break;
   1143 
   1144         case op_seac:
   1145           return t1operator_seac( decoder,
   1146                                   top[0],
   1147                                   top[1],
   1148                                   top[2],
   1149                                   (FT_Int)( top[3] >> 16 ),
   1150                                   (FT_Int)( top[4] >> 16 ) );
   1151 
   1152         case op_sbw:
   1153           FT_TRACE4(( " sbw" ));
   1154 
   1155           builder->parse_state = T1_Parse_Have_Width;
   1156 
   1157           builder->left_bearing.x += top[0];
   1158           builder->left_bearing.y += top[1];
   1159           builder->advance.x       = top[2];
   1160           builder->advance.y       = top[3];
   1161 
   1162           x = builder->pos_x + top[0];
   1163           y = builder->pos_y + top[1];
   1164 
   1165           /* the `metrics_only' indicates that we only want to compute */
   1166           /* the glyph's metrics (lsb + advance width), not load the   */
   1167           /* rest of it; so exit immediately                           */
   1168           if ( builder->metrics_only )
   1169             return PSaux_Err_Ok;
   1170 
   1171           break;
   1172 
   1173         case op_closepath:
   1174           FT_TRACE4(( " closepath" ));
   1175 
   1176           /* if there is no path, `closepath' is a no-op */
   1177           if ( builder->parse_state == T1_Parse_Have_Path   ||
   1178                builder->parse_state == T1_Parse_Have_Moveto )
   1179             close_contour( builder );
   1180 
   1181           builder->parse_state = T1_Parse_Have_Width;
   1182           break;
   1183 
   1184         case op_hlineto:
   1185           FT_TRACE4(( " hlineto" ));
   1186 
   1187           if ( start_point( builder, x, y ) )
   1188             goto Fail;
   1189 
   1190           x += top[0];
   1191           goto Add_Line;
   1192 
   1193         case op_hmoveto:
   1194           FT_TRACE4(( " hmoveto" ));
   1195 
   1196           x += top[0];
   1197           if ( !decoder->flex_state )
   1198           {
   1199             if ( builder->parse_state == T1_Parse_Start )
   1200               goto Syntax_Error;
   1201             builder->parse_state = T1_Parse_Have_Moveto;
   1202           }
   1203           break;
   1204 
   1205         case op_hvcurveto:
   1206           FT_TRACE4(( " hvcurveto" ));
   1207 
   1208           if ( start_point( builder, x, y ) ||
   1209                check_points( builder, 3 )   )
   1210             goto Fail;
   1211 
   1212           x += top[0];
   1213           add_point( builder, x, y, 0 );
   1214           x += top[1];
   1215           y += top[2];
   1216           add_point( builder, x, y, 0 );
   1217           y += top[3];
   1218           add_point( builder, x, y, 1 );
   1219           break;
   1220 
   1221         case op_rlineto:
   1222           FT_TRACE4(( " rlineto" ));
   1223 
   1224           if ( start_point( builder, x, y ) )
   1225             goto Fail;
   1226 
   1227           x += top[0];
   1228           y += top[1];
   1229 
   1230         Add_Line:
   1231           if ( add_point1( builder, x, y ) )
   1232             goto Fail;
   1233           break;
   1234 
   1235         case op_rmoveto:
   1236           FT_TRACE4(( " rmoveto" ));
   1237 
   1238           x += top[0];
   1239           y += top[1];
   1240           if ( !decoder->flex_state )
   1241           {
   1242             if ( builder->parse_state == T1_Parse_Start )
   1243               goto Syntax_Error;
   1244             builder->parse_state = T1_Parse_Have_Moveto;
   1245           }
   1246           break;
   1247 
   1248         case op_rrcurveto:
   1249           FT_TRACE4(( " rrcurveto" ));
   1250 
   1251           if ( start_point( builder, x, y ) ||
   1252                check_points( builder, 3 )   )
   1253             goto Fail;
   1254 
   1255           x += top[0];
   1256           y += top[1];
   1257           add_point( builder, x, y, 0 );
   1258 
   1259           x += top[2];
   1260           y += top[3];
   1261           add_point( builder, x, y, 0 );
   1262 
   1263           x += top[4];
   1264           y += top[5];
   1265           add_point( builder, x, y, 1 );
   1266           break;
   1267 
   1268         case op_vhcurveto:
   1269           FT_TRACE4(( " vhcurveto" ));
   1270 
   1271           if ( start_point( builder, x, y ) ||
   1272                check_points( builder, 3 )   )
   1273             goto Fail;
   1274 
   1275           y += top[0];
   1276           add_point( builder, x, y, 0 );
   1277           x += top[1];
   1278           y += top[2];
   1279           add_point( builder, x, y, 0 );
   1280           x += top[3];
   1281           add_point( builder, x, y, 1 );
   1282           break;
   1283 
   1284         case op_vlineto:
   1285           FT_TRACE4(( " vlineto" ));
   1286 
   1287           if ( start_point( builder, x, y ) )
   1288             goto Fail;
   1289 
   1290           y += top[0];
   1291           goto Add_Line;
   1292 
   1293         case op_vmoveto:
   1294           FT_TRACE4(( " vmoveto" ));
   1295 
   1296           y += top[0];
   1297           if ( !decoder->flex_state )
   1298           {
   1299             if ( builder->parse_state == T1_Parse_Start )
   1300               goto Syntax_Error;
   1301             builder->parse_state = T1_Parse_Have_Moveto;
   1302           }
   1303           break;
   1304 
   1305         case op_div:
   1306           FT_TRACE4(( " div" ));
   1307 
   1308           /* if `large_int' is set, we divide unscaled numbers; */
   1309           /* otherwise, we divide numbers in 16.16 format --    */
   1310           /* in both cases, it is the same operation            */
   1311           *top = FT_DivFix( top[0], top[1] );
   1312           ++top;
   1313 
   1314           large_int = FALSE;
   1315           break;
   1316 
   1317         case op_callsubr:
   1318           {
   1319             FT_Int  idx;
   1320 
   1321 
   1322             FT_TRACE4(( " callsubr" ));
   1323 
   1324             idx = (FT_Int)( top[0] >> 16 );
   1325             if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs )
   1326             {
   1327               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1328                          " invalid subrs index\n" ));
   1329               goto Syntax_Error;
   1330             }
   1331 
   1332             if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
   1333             {
   1334               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1335                          " too many nested subrs\n" ));
   1336               goto Syntax_Error;
   1337             }
   1338 
   1339             zone->cursor = ip;  /* save current instruction pointer */
   1340 
   1341             zone++;
   1342 
   1343             /* The Type 1 driver stores subroutines without the seed bytes. */
   1344             /* The CID driver stores subroutines with seed bytes.  This     */
   1345             /* case is taken care of when decoder->subrs_len == 0.          */
   1346             zone->base = decoder->subrs[idx];
   1347 
   1348             if ( decoder->subrs_len )
   1349               zone->limit = zone->base + decoder->subrs_len[idx];
   1350             else
   1351             {
   1352               /* We are using subroutines from a CID font.  We must adjust */
   1353               /* for the seed bytes.                                       */
   1354               zone->base  += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
   1355               zone->limit  = decoder->subrs[idx + 1];
   1356             }
   1357 
   1358             zone->cursor = zone->base;
   1359 
   1360             if ( !zone->base )
   1361             {
   1362               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1363                          " invoking empty subrs\n" ));
   1364               goto Syntax_Error;
   1365             }
   1366 
   1367             decoder->zone = zone;
   1368             ip            = zone->base;
   1369             limit         = zone->limit;
   1370             break;
   1371           }
   1372 
   1373         case op_pop:
   1374           FT_TRACE4(( " pop" ));
   1375 
   1376           if ( known_othersubr_result_cnt > 0 )
   1377           {
   1378             known_othersubr_result_cnt--;
   1379             /* ignore, we pushed the operands ourselves */
   1380             break;
   1381           }
   1382 
   1383           if ( unknown_othersubr_result_cnt == 0 )
   1384           {
   1385             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1386                        " no more operands for othersubr\n" ));
   1387             goto Syntax_Error;
   1388           }
   1389 
   1390           unknown_othersubr_result_cnt--;
   1391           top++;   /* `push' the operand to callothersubr onto the stack */
   1392           break;
   1393 
   1394         case op_return:
   1395           FT_TRACE4(( " return" ));
   1396 
   1397           if ( zone <= decoder->zones )
   1398           {
   1399             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1400                        " unexpected return\n" ));
   1401             goto Syntax_Error;
   1402           }
   1403 
   1404           zone--;
   1405           ip            = zone->cursor;
   1406           limit         = zone->limit;
   1407           decoder->zone = zone;
   1408           break;
   1409 
   1410         case op_dotsection:
   1411           FT_TRACE4(( " dotsection" ));
   1412 
   1413           break;
   1414 
   1415         case op_hstem:
   1416           FT_TRACE4(( " hstem" ));
   1417 
   1418           /* record horizontal hint */
   1419           if ( hinter )
   1420           {
   1421             /* top[0] += builder->left_bearing.y; */
   1422             hinter->stem( hinter->hints, 1, top );
   1423           }
   1424           break;
   1425 
   1426         case op_hstem3:
   1427           FT_TRACE4(( " hstem3" ));
   1428 
   1429           /* record horizontal counter-controlled hints */
   1430           if ( hinter )
   1431             hinter->stem3( hinter->hints, 1, top );
   1432           break;
   1433 
   1434         case op_vstem:
   1435           FT_TRACE4(( " vstem" ));
   1436 
   1437           /* record vertical hint */
   1438           if ( hinter )
   1439           {
   1440             top[0] += orig_x;
   1441             hinter->stem( hinter->hints, 0, top );
   1442           }
   1443           break;
   1444 
   1445         case op_vstem3:
   1446           FT_TRACE4(( " vstem3" ));
   1447 
   1448           /* record vertical counter-controlled hints */
   1449           if ( hinter )
   1450           {
   1451             FT_Pos  dx = orig_x;
   1452 
   1453 
   1454             top[0] += dx;
   1455             top[2] += dx;
   1456             top[4] += dx;
   1457             hinter->stem3( hinter->hints, 0, top );
   1458           }
   1459           break;
   1460 
   1461         case op_setcurrentpoint:
   1462           FT_TRACE4(( " setcurrentpoint" ));
   1463 
   1464           /* From the T1 specification, section 6.4:                */
   1465           /*                                                        */
   1466           /*   The setcurrentpoint command is used only in          */
   1467           /*   conjunction with results from OtherSubrs procedures. */
   1468 
   1469           /* known_othersubr_result_cnt != 0 is already handled     */
   1470           /* above.                                                 */
   1471 
   1472           /* Note, however, that both Ghostscript and Adobe         */
   1473           /* Distiller handle this situation by silently ignoring   */
   1474           /* the inappropriate `setcurrentpoint' instruction.  So   */
   1475           /* we do the same.                                        */
   1476 #if 0
   1477 
   1478           if ( decoder->flex_state != 1 )
   1479           {
   1480             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1481                        " unexpected `setcurrentpoint'\n" ));
   1482             goto Syntax_Error;
   1483           }
   1484           else
   1485             ...
   1486 #endif
   1487 
   1488           x = top[0];
   1489           y = top[1];
   1490           decoder->flex_state = 0;
   1491           break;
   1492 
   1493         case op_unknown15:
   1494           FT_TRACE4(( " opcode_15" ));
   1495           /* nothing to do except to pop the two arguments */
   1496           break;
   1497 
   1498         default:
   1499           FT_ERROR(( "t1_decoder_parse_charstrings:"
   1500                      " unhandled opcode %d\n", op ));
   1501           goto Syntax_Error;
   1502         }
   1503 
   1504         /* XXX Operators usually clear the operand stack;  */
   1505         /*     only div, callsubr, callothersubr, pop, and */
   1506         /*     return are different.                       */
   1507         /*     In practice it doesn't matter (?).          */
   1508 
   1509         decoder->top = top;
   1510 
   1511 #ifdef FT_DEBUG_LEVEL_TRACE
   1512         FT_TRACE4(( "\n" ));
   1513         bol = TRUE;
   1514 #endif
   1515 
   1516       } /* general operator processing */
   1517 
   1518     } /* while ip < limit */
   1519 
   1520     FT_TRACE4(( "..end..\n\n" ));
   1521 
   1522   Fail:
   1523     return error;
   1524 
   1525   Syntax_Error:
   1526     return PSaux_Err_Syntax_Error;
   1527 
   1528   Stack_Underflow:
   1529     return PSaux_Err_Stack_Underflow;
   1530   }
   1531 
   1532 
   1533   /* parse a single Type 1 glyph */
   1534   FT_LOCAL_DEF( FT_Error )
   1535   t1_decoder_parse_glyph( T1_Decoder  decoder,
   1536                           FT_UInt     glyph )
   1537   {
   1538     return decoder->parse_callback( decoder, glyph );
   1539   }
   1540 
   1541 
   1542   /* initialize T1 decoder */
   1543   FT_LOCAL_DEF( FT_Error )
   1544   t1_decoder_init( T1_Decoder           decoder,
   1545                    FT_Face              face,
   1546                    FT_Size              size,
   1547                    FT_GlyphSlot         slot,
   1548                    FT_Byte**            glyph_names,
   1549                    PS_Blend             blend,
   1550                    FT_Bool              hinting,
   1551                    FT_Render_Mode       hint_mode,
   1552                    T1_Decoder_Callback  parse_callback )
   1553   {
   1554     FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
   1555 
   1556     /* retrieve PSNames interface from list of current modules */
   1557     {
   1558       FT_Service_PsCMaps  psnames = 0;
   1559 
   1560 
   1561       FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
   1562       if ( !psnames )
   1563       {
   1564         FT_ERROR(( "t1_decoder_init:"
   1565                    " the `psnames' module is not available\n" ));
   1566         return PSaux_Err_Unimplemented_Feature;
   1567       }
   1568 
   1569       decoder->psnames = psnames;
   1570     }
   1571 
   1572     t1_builder_init( &decoder->builder, face, size, slot, hinting );
   1573 
   1574     /* decoder->buildchar and decoder->len_buildchar have to be  */
   1575     /* initialized by the caller since we cannot know the length */
   1576     /* of the BuildCharArray                                     */
   1577 
   1578     decoder->num_glyphs     = (FT_UInt)face->num_glyphs;
   1579     decoder->glyph_names    = glyph_names;
   1580     decoder->hint_mode      = hint_mode;
   1581     decoder->blend          = blend;
   1582     decoder->parse_callback = parse_callback;
   1583 
   1584     decoder->funcs          = t1_decoder_funcs;
   1585 
   1586     return PSaux_Err_Ok;
   1587   }
   1588 
   1589 
   1590   /* finalize T1 decoder */
   1591   FT_LOCAL_DEF( void )
   1592   t1_decoder_done( T1_Decoder  decoder )
   1593   {
   1594     t1_builder_done( &decoder->builder );
   1595   }
   1596 
   1597 
   1598 /* END */
   1599