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