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             /* note that we should not add a point for index 0; */
    768             /* this will move our current position to the flex  */
    769             /* point without adding any point to the outline    */
    770             idx = decoder->num_flex_vectors++;
    771             if ( idx > 0 && idx < 7 )
    772               t1_builder_add_point( builder,
    773                                     x,
    774                                     y,
    775                                     (FT_Byte)( idx == 3 || idx == 6 ) );
    776           }
    777           break;
    778 
    779         case 3:                     /* change hints */
    780           if ( arg_cnt != 1 )
    781             goto Unexpected_OtherSubr;
    782 
    783           known_othersubr_result_cnt = 1;
    784 
    785           if ( hinter )
    786             hinter->reset( hinter->hints, builder->current->n_points );
    787           break;
    788 
    789         case 12:
    790         case 13:
    791           /* counter control hints, clear stack */
    792           top = decoder->stack;
    793           break;
    794 
    795         case 14:
    796         case 15:
    797         case 16:
    798         case 17:
    799         case 18:                    /* multiple masters */
    800           {
    801             PS_Blend  blend = decoder->blend;
    802             FT_UInt   num_points, nn, mm;
    803             FT_Long*  delta;
    804             FT_Long*  values;
    805 
    806 
    807             if ( !blend )
    808             {
    809               FT_ERROR(( "t1_decoder_parse_charstrings:"
    810                          " unexpected multiple masters operator\n" ));
    811               goto Syntax_Error;
    812             }
    813 
    814             num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 );
    815             if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) )
    816             {
    817               FT_ERROR(( "t1_decoder_parse_charstrings:"
    818                          " incorrect number of multiple masters arguments\n" ));
    819               goto Syntax_Error;
    820             }
    821 
    822             /* We want to compute                                    */
    823             /*                                                       */
    824             /*   a0*w0 + a1*w1 + ... + ak*wk                         */
    825             /*                                                       */
    826             /* but we only have a0, a1-a0, a2-a0, ..., ak-a0.        */
    827             /*                                                       */
    828             /* However, given that w0 + w1 + ... + wk == 1, we can   */
    829             /* rewrite it easily as                                  */
    830             /*                                                       */
    831             /*   a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk     */
    832             /*                                                       */
    833             /* where k == num_designs-1.                             */
    834             /*                                                       */
    835             /* I guess that's why it's written in this `compact'     */
    836             /* form.                                                 */
    837             /*                                                       */
    838             delta  = top + num_points;
    839             values = top;
    840             for ( nn = 0; nn < num_points; nn++ )
    841             {
    842               FT_Long  tmp = values[0];
    843 
    844 
    845               for ( mm = 1; mm < blend->num_designs; mm++ )
    846                 tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
    847 
    848               *values++ = tmp;
    849             }
    850 
    851             known_othersubr_result_cnt = num_points;
    852             break;
    853           }
    854 
    855         case 19:
    856           /* <idx> 1 19 callothersubr                             */
    857           /* => replace elements starting from index cvi( <idx> ) */
    858           /*    of BuildCharArray with WeightVector               */
    859           {
    860             FT_Int    idx;
    861             PS_Blend  blend = decoder->blend;
    862 
    863 
    864             if ( arg_cnt != 1 || blend == NULL )
    865               goto Unexpected_OtherSubr;
    866 
    867             idx = Fix2Int( top[0] );
    868 
    869             if ( idx < 0                                           ||
    870                  idx + blend->num_designs > decoder->len_buildchar )
    871               goto Unexpected_OtherSubr;
    872 
    873             ft_memcpy( &decoder->buildchar[idx],
    874                        blend->weight_vector,
    875                        blend->num_designs *
    876                          sizeof( blend->weight_vector[0] ) );
    877           }
    878           break;
    879 
    880         case 20:
    881           /* <arg1> <arg2> 2 20 callothersubr pop   */
    882           /* ==> push <arg1> + <arg2> onto T1 stack */
    883           if ( arg_cnt != 2 )
    884             goto Unexpected_OtherSubr;
    885 
    886           top[0] += top[1]; /* XXX (over|under)flow */
    887 
    888           known_othersubr_result_cnt = 1;
    889           break;
    890 
    891         case 21:
    892           /* <arg1> <arg2> 2 21 callothersubr pop   */
    893           /* ==> push <arg1> - <arg2> onto T1 stack */
    894           if ( arg_cnt != 2 )
    895             goto Unexpected_OtherSubr;
    896 
    897           top[0] -= top[1]; /* XXX (over|under)flow */
    898 
    899           known_othersubr_result_cnt = 1;
    900           break;
    901 
    902         case 22:
    903           /* <arg1> <arg2> 2 22 callothersubr pop   */
    904           /* ==> push <arg1> * <arg2> onto T1 stack */
    905           if ( arg_cnt != 2 )
    906             goto Unexpected_OtherSubr;
    907 
    908           top[0] = FT_MulFix( top[0], top[1] );
    909 
    910           known_othersubr_result_cnt = 1;
    911           break;
    912 
    913         case 23:
    914           /* <arg1> <arg2> 2 23 callothersubr pop   */
    915           /* ==> push <arg1> / <arg2> onto T1 stack */
    916           if ( arg_cnt != 2 || top[1] == 0 )
    917             goto Unexpected_OtherSubr;
    918 
    919           top[0] = FT_DivFix( top[0], top[1] );
    920 
    921           known_othersubr_result_cnt = 1;
    922           break;
    923 
    924         case 24:
    925           /* <val> <idx> 2 24 callothersubr               */
    926           /* ==> set BuildCharArray[cvi( <idx> )] = <val> */
    927           {
    928             FT_Int    idx;
    929             PS_Blend  blend = decoder->blend;
    930 
    931 
    932             if ( arg_cnt != 2 || blend == NULL )
    933               goto Unexpected_OtherSubr;
    934 
    935             idx = Fix2Int( top[1] );
    936 
    937             if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
    938               goto Unexpected_OtherSubr;
    939 
    940             decoder->buildchar[idx] = top[0];
    941           }
    942           break;
    943 
    944         case 25:
    945           /* <idx> 1 25 callothersubr pop        */
    946           /* ==> push BuildCharArray[cvi( idx )] */
    947           /*     onto T1 stack                   */
    948           {
    949             FT_Int    idx;
    950             PS_Blend  blend = decoder->blend;
    951 
    952 
    953             if ( arg_cnt != 1 || blend == NULL )
    954               goto Unexpected_OtherSubr;
    955 
    956             idx = Fix2Int( top[0] );
    957 
    958             if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
    959               goto Unexpected_OtherSubr;
    960 
    961             top[0] = decoder->buildchar[idx];
    962           }
    963 
    964           known_othersubr_result_cnt = 1;
    965           break;
    966 
    967 #if 0
    968         case 26:
    969           /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
    970           /*                      leave mark on T1 stack                    */
    971           /* <val> <idx>      ==> set BuildCharArray[cvi( <idx> )] = <val>  */
    972           XXX which routine has left its mark on the (PostScript) stack?;
    973           break;
    974 #endif
    975 
    976         case 27:
    977           /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
    978           /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
    979           /*     otherwise push <res2>                          */
    980           if ( arg_cnt != 4 )
    981             goto Unexpected_OtherSubr;
    982 
    983           if ( top[2] > top[3] )
    984             top[0] = top[1];
    985 
    986           known_othersubr_result_cnt = 1;
    987           break;
    988 
    989         case 28:
    990           /* 0 28 callothersubr pop                               */
    991           /* => push random value from interval [0, 1) onto stack */
    992           if ( arg_cnt != 0 )
    993             goto Unexpected_OtherSubr;
    994 
    995           {
    996             FT_Fixed  Rand;
    997 
    998 
    999             Rand = seed;
   1000             if ( Rand >= 0x8000L )
   1001               Rand++;
   1002 
   1003             top[0] = Rand;
   1004 
   1005             seed = FT_MulFix( seed, 0x10000L - seed );
   1006             if ( seed == 0 )
   1007               seed += 0x2873;
   1008           }
   1009 
   1010           known_othersubr_result_cnt = 1;
   1011           break;
   1012 
   1013         default:
   1014           if ( arg_cnt >= 0 && subr_no >= 0 )
   1015           {
   1016             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1017                        " unknown othersubr [%d %d], wish me luck\n",
   1018                        arg_cnt, subr_no ));
   1019             unknown_othersubr_result_cnt = arg_cnt;
   1020             break;
   1021           }
   1022           /* fall through */
   1023 
   1024         Unexpected_OtherSubr:
   1025           FT_ERROR(( "t1_decoder_parse_charstrings:"
   1026                      " invalid othersubr [%d %d]\n", arg_cnt, subr_no ));
   1027           goto Syntax_Error;
   1028         }
   1029 
   1030         top += known_othersubr_result_cnt;
   1031 
   1032         decoder->top = top;
   1033       }
   1034       else  /* general operator */
   1035       {
   1036         FT_Int  num_args = t1_args_count[op];
   1037 
   1038 
   1039         FT_ASSERT( num_args >= 0 );
   1040 
   1041         if ( top - decoder->stack < num_args )
   1042           goto Stack_Underflow;
   1043 
   1044         /* XXX Operators usually take their operands from the        */
   1045         /*     bottom of the stack, i.e., the operands are           */
   1046         /*     decoder->stack[0], ..., decoder->stack[num_args - 1]; */
   1047         /*     only div, callsubr, and callothersubr are different.  */
   1048         /*     In practice it doesn't matter (?).                    */
   1049 
   1050 #ifdef FT_DEBUG_LEVEL_TRACE
   1051 
   1052         switch ( op )
   1053         {
   1054         case op_callsubr:
   1055         case op_div:
   1056         case op_callothersubr:
   1057         case op_pop:
   1058         case op_return:
   1059           break;
   1060 
   1061         default:
   1062           if ( top - decoder->stack != num_args )
   1063             FT_TRACE0(( "t1_decoder_parse_charstrings:"
   1064                         " too much operands on the stack"
   1065                         " (seen %d, expected %d)\n",
   1066                         top - decoder->stack, num_args ));
   1067             break;
   1068         }
   1069 
   1070 #endif /* FT_DEBUG_LEVEL_TRACE */
   1071 
   1072         top -= num_args;
   1073 
   1074         switch ( op )
   1075         {
   1076         case op_endchar:
   1077           FT_TRACE4(( " endchar\n" ));
   1078 
   1079           t1_builder_close_contour( builder );
   1080 
   1081           /* close hints recording session */
   1082           if ( hinter )
   1083           {
   1084             if ( hinter->close( hinter->hints, builder->current->n_points ) )
   1085               goto Syntax_Error;
   1086 
   1087             /* apply hints to the loaded glyph outline now */
   1088             hinter->apply( hinter->hints,
   1089                            builder->current,
   1090                            (PSH_Globals)builder->hints_globals,
   1091                            decoder->hint_mode );
   1092           }
   1093 
   1094           /* add current outline to the glyph slot */
   1095           FT_GlyphLoader_Add( builder->loader );
   1096 
   1097           /* the compiler should optimize away this empty loop but ... */
   1098 
   1099 #ifdef FT_DEBUG_LEVEL_TRACE
   1100 
   1101           if ( decoder->len_buildchar > 0 )
   1102           {
   1103             FT_UInt  i;
   1104 
   1105 
   1106             FT_TRACE4(( "BuildCharArray = [ " ));
   1107 
   1108             for ( i = 0; i < decoder->len_buildchar; ++i )
   1109               FT_TRACE4(( "%d ", decoder->buildchar[ i ] ));
   1110 
   1111             FT_TRACE4(( "]\n" ));
   1112           }
   1113 
   1114 #endif /* FT_DEBUG_LEVEL_TRACE */
   1115 
   1116           FT_TRACE4(( "\n" ));
   1117 
   1118           /* return now! */
   1119           return PSaux_Err_Ok;
   1120 
   1121         case op_hsbw:
   1122           FT_TRACE4(( " hsbw" ));
   1123 
   1124           builder->parse_state = T1_Parse_Have_Width;
   1125 
   1126           builder->left_bearing.x += top[0];
   1127           builder->advance.x       = top[1];
   1128           builder->advance.y       = 0;
   1129 
   1130           orig_x = x = builder->pos_x + top[0];
   1131           orig_y = y = builder->pos_y;
   1132 
   1133           FT_UNUSED( orig_y );
   1134 
   1135           /* the `metrics_only' indicates that we only want to compute */
   1136           /* the glyph's metrics (lsb + advance width), not load the   */
   1137           /* rest of it; so exit immediately                           */
   1138           if ( builder->metrics_only )
   1139             return PSaux_Err_Ok;
   1140 
   1141           break;
   1142 
   1143         case op_seac:
   1144           return t1operator_seac( decoder,
   1145                                   top[0],
   1146                                   top[1],
   1147                                   top[2],
   1148                                   Fix2Int( top[3] ),
   1149                                   Fix2Int( top[4] ) );
   1150 
   1151         case op_sbw:
   1152           FT_TRACE4(( " sbw" ));
   1153 
   1154           builder->parse_state = T1_Parse_Have_Width;
   1155 
   1156           builder->left_bearing.x += top[0];
   1157           builder->left_bearing.y += top[1];
   1158           builder->advance.x       = top[2];
   1159           builder->advance.y       = top[3];
   1160 
   1161           x = builder->pos_x + top[0];
   1162           y = builder->pos_y + top[1];
   1163 
   1164           /* the `metrics_only' indicates that we only want to compute */
   1165           /* the glyph's metrics (lsb + advance width), not load the   */
   1166           /* rest of it; so exit immediately                           */
   1167           if ( builder->metrics_only )
   1168             return PSaux_Err_Ok;
   1169 
   1170           break;
   1171 
   1172         case op_closepath:
   1173           FT_TRACE4(( " closepath" ));
   1174 
   1175           /* if there is no path, `closepath' is a no-op */
   1176           if ( builder->parse_state == T1_Parse_Have_Path   ||
   1177                builder->parse_state == T1_Parse_Have_Moveto )
   1178             t1_builder_close_contour( builder );
   1179 
   1180           builder->parse_state = T1_Parse_Have_Width;
   1181           break;
   1182 
   1183         case op_hlineto:
   1184           FT_TRACE4(( " hlineto" ));
   1185 
   1186           if ( ( error = t1_builder_start_point( builder, x, y ) )
   1187                  != PSaux_Err_Ok )
   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 ( ( error = t1_builder_start_point( builder, x, y ) )
   1209                  != PSaux_Err_Ok                                   ||
   1210                ( error = t1_builder_check_points( builder, 3 ) )
   1211                  != PSaux_Err_Ok                                   )
   1212             goto Fail;
   1213 
   1214           x += top[0];
   1215           t1_builder_add_point( builder, x, y, 0 );
   1216           x += top[1];
   1217           y += top[2];
   1218           t1_builder_add_point( builder, x, y, 0 );
   1219           y += top[3];
   1220           t1_builder_add_point( builder, x, y, 1 );
   1221           break;
   1222 
   1223         case op_rlineto:
   1224           FT_TRACE4(( " rlineto" ));
   1225 
   1226           if ( ( error = t1_builder_start_point( builder, x, y ) )
   1227                  != PSaux_Err_Ok )
   1228             goto Fail;
   1229 
   1230           x += top[0];
   1231           y += top[1];
   1232 
   1233         Add_Line:
   1234           if ( ( error = t1_builder_add_point1( builder, x, y ) )
   1235                  != PSaux_Err_Ok )
   1236             goto Fail;
   1237           break;
   1238 
   1239         case op_rmoveto:
   1240           FT_TRACE4(( " rmoveto" ));
   1241 
   1242           x += top[0];
   1243           y += top[1];
   1244           if ( !decoder->flex_state )
   1245           {
   1246             if ( builder->parse_state == T1_Parse_Start )
   1247               goto Syntax_Error;
   1248             builder->parse_state = T1_Parse_Have_Moveto;
   1249           }
   1250           break;
   1251 
   1252         case op_rrcurveto:
   1253           FT_TRACE4(( " rrcurveto" ));
   1254 
   1255           if ( ( error = t1_builder_start_point( builder, x, y ) )
   1256                  != PSaux_Err_Ok                                   ||
   1257                ( error = t1_builder_check_points( builder, 3 ) )
   1258                  != PSaux_Err_Ok                                   )
   1259             goto Fail;
   1260 
   1261           x += top[0];
   1262           y += top[1];
   1263           t1_builder_add_point( builder, x, y, 0 );
   1264 
   1265           x += top[2];
   1266           y += top[3];
   1267           t1_builder_add_point( builder, x, y, 0 );
   1268 
   1269           x += top[4];
   1270           y += top[5];
   1271           t1_builder_add_point( builder, x, y, 1 );
   1272           break;
   1273 
   1274         case op_vhcurveto:
   1275           FT_TRACE4(( " vhcurveto" ));
   1276 
   1277           if ( ( error = t1_builder_start_point( builder, x, y ) )
   1278                  != PSaux_Err_Ok                                   ||
   1279                ( error = t1_builder_check_points( builder, 3 ) )
   1280                  != PSaux_Err_Ok                                   )
   1281             goto Fail;
   1282 
   1283           y += top[0];
   1284           t1_builder_add_point( builder, x, y, 0 );
   1285           x += top[1];
   1286           y += top[2];
   1287           t1_builder_add_point( builder, x, y, 0 );
   1288           x += top[3];
   1289           t1_builder_add_point( builder, x, y, 1 );
   1290           break;
   1291 
   1292         case op_vlineto:
   1293           FT_TRACE4(( " vlineto" ));
   1294 
   1295           if ( ( error = t1_builder_start_point( builder, x, y ) )
   1296                  != PSaux_Err_Ok )
   1297             goto Fail;
   1298 
   1299           y += top[0];
   1300           goto Add_Line;
   1301 
   1302         case op_vmoveto:
   1303           FT_TRACE4(( " vmoveto" ));
   1304 
   1305           y += top[0];
   1306           if ( !decoder->flex_state )
   1307           {
   1308             if ( builder->parse_state == T1_Parse_Start )
   1309               goto Syntax_Error;
   1310             builder->parse_state = T1_Parse_Have_Moveto;
   1311           }
   1312           break;
   1313 
   1314         case op_div:
   1315           FT_TRACE4(( " div" ));
   1316 
   1317           /* if `large_int' is set, we divide unscaled numbers; */
   1318           /* otherwise, we divide numbers in 16.16 format --    */
   1319           /* in both cases, it is the same operation            */
   1320           *top = FT_DivFix( top[0], top[1] );
   1321           ++top;
   1322 
   1323           large_int = FALSE;
   1324           break;
   1325 
   1326         case op_callsubr:
   1327           {
   1328             FT_Int  idx;
   1329 
   1330 
   1331             FT_TRACE4(( " callsubr" ));
   1332 
   1333             idx = Fix2Int( top[0] );
   1334             if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs )
   1335             {
   1336               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1337                          " invalid subrs index\n" ));
   1338               goto Syntax_Error;
   1339             }
   1340 
   1341             if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
   1342             {
   1343               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1344                          " too many nested subrs\n" ));
   1345               goto Syntax_Error;
   1346             }
   1347 
   1348             zone->cursor = ip;  /* save current instruction pointer */
   1349 
   1350             zone++;
   1351 
   1352             /* The Type 1 driver stores subroutines without the seed bytes. */
   1353             /* The CID driver stores subroutines with seed bytes.  This     */
   1354             /* case is taken care of when decoder->subrs_len == 0.          */
   1355             zone->base = decoder->subrs[idx];
   1356 
   1357             if ( decoder->subrs_len )
   1358               zone->limit = zone->base + decoder->subrs_len[idx];
   1359             else
   1360             {
   1361               /* We are using subroutines from a CID font.  We must adjust */
   1362               /* for the seed bytes.                                       */
   1363               zone->base  += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
   1364               zone->limit  = decoder->subrs[idx + 1];
   1365             }
   1366 
   1367             zone->cursor = zone->base;
   1368 
   1369             if ( !zone->base )
   1370             {
   1371               FT_ERROR(( "t1_decoder_parse_charstrings:"
   1372                          " invoking empty subrs\n" ));
   1373               goto Syntax_Error;
   1374             }
   1375 
   1376             decoder->zone = zone;
   1377             ip            = zone->base;
   1378             limit         = zone->limit;
   1379             break;
   1380           }
   1381 
   1382         case op_pop:
   1383           FT_TRACE4(( " pop" ));
   1384 
   1385           if ( known_othersubr_result_cnt > 0 )
   1386           {
   1387             known_othersubr_result_cnt--;
   1388             /* ignore, we pushed the operands ourselves */
   1389             break;
   1390           }
   1391 
   1392           if ( unknown_othersubr_result_cnt == 0 )
   1393           {
   1394             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1395                        " no more operands for othersubr\n" ));
   1396             goto Syntax_Error;
   1397           }
   1398 
   1399           unknown_othersubr_result_cnt--;
   1400           top++;   /* `push' the operand to callothersubr onto the stack */
   1401           break;
   1402 
   1403         case op_return:
   1404           FT_TRACE4(( " return" ));
   1405 
   1406           if ( zone <= decoder->zones )
   1407           {
   1408             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1409                        " unexpected return\n" ));
   1410             goto Syntax_Error;
   1411           }
   1412 
   1413           zone--;
   1414           ip            = zone->cursor;
   1415           limit         = zone->limit;
   1416           decoder->zone = zone;
   1417           break;
   1418 
   1419         case op_dotsection:
   1420           FT_TRACE4(( " dotsection" ));
   1421 
   1422           break;
   1423 
   1424         case op_hstem:
   1425           FT_TRACE4(( " hstem" ));
   1426 
   1427           /* record horizontal hint */
   1428           if ( hinter )
   1429           {
   1430             /* top[0] += builder->left_bearing.y; */
   1431             hinter->stem( hinter->hints, 1, top );
   1432           }
   1433           break;
   1434 
   1435         case op_hstem3:
   1436           FT_TRACE4(( " hstem3" ));
   1437 
   1438           /* record horizontal counter-controlled hints */
   1439           if ( hinter )
   1440             hinter->stem3( hinter->hints, 1, top );
   1441           break;
   1442 
   1443         case op_vstem:
   1444           FT_TRACE4(( " vstem" ));
   1445 
   1446           /* record vertical hint */
   1447           if ( hinter )
   1448           {
   1449             top[0] += orig_x;
   1450             hinter->stem( hinter->hints, 0, top );
   1451           }
   1452           break;
   1453 
   1454         case op_vstem3:
   1455           FT_TRACE4(( " vstem3" ));
   1456 
   1457           /* record vertical counter-controlled hints */
   1458           if ( hinter )
   1459           {
   1460             FT_Pos  dx = orig_x;
   1461 
   1462 
   1463             top[0] += dx;
   1464             top[2] += dx;
   1465             top[4] += dx;
   1466             hinter->stem3( hinter->hints, 0, top );
   1467           }
   1468           break;
   1469 
   1470         case op_setcurrentpoint:
   1471           FT_TRACE4(( " setcurrentpoint" ));
   1472 
   1473           /* From the T1 specification, section 6.4:                */
   1474           /*                                                        */
   1475           /*   The setcurrentpoint command is used only in          */
   1476           /*   conjunction with results from OtherSubrs procedures. */
   1477 
   1478           /* known_othersubr_result_cnt != 0 is already handled     */
   1479           /* above.                                                 */
   1480 
   1481           /* Note, however, that both Ghostscript and Adobe         */
   1482           /* Distiller handle this situation by silently ignoring   */
   1483           /* the inappropriate `setcurrentpoint' instruction.  So   */
   1484           /* we do the same.                                        */
   1485 #if 0
   1486 
   1487           if ( decoder->flex_state != 1 )
   1488           {
   1489             FT_ERROR(( "t1_decoder_parse_charstrings:"
   1490                        " unexpected `setcurrentpoint'\n" ));
   1491             goto Syntax_Error;
   1492           }
   1493           else
   1494             ...
   1495 #endif
   1496 
   1497           x = top[0];
   1498           y = top[1];
   1499           decoder->flex_state = 0;
   1500           break;
   1501 
   1502         case op_unknown15:
   1503           FT_TRACE4(( " opcode_15" ));
   1504           /* nothing to do except to pop the two arguments */
   1505           break;
   1506 
   1507         default:
   1508           FT_ERROR(( "t1_decoder_parse_charstrings:"
   1509                      " unhandled opcode %d\n", op ));
   1510           goto Syntax_Error;
   1511         }
   1512 
   1513         /* XXX Operators usually clear the operand stack;  */
   1514         /*     only div, callsubr, callothersubr, pop, and */
   1515         /*     return are different.                       */
   1516         /*     In practice it doesn't matter (?).          */
   1517 
   1518         decoder->top = top;
   1519 
   1520 #ifdef FT_DEBUG_LEVEL_TRACE
   1521         FT_TRACE4(( "\n" ));
   1522         bol = TRUE;
   1523 #endif
   1524 
   1525       } /* general operator processing */
   1526 
   1527     } /* while ip < limit */
   1528 
   1529     FT_TRACE4(( "..end..\n\n" ));
   1530 
   1531   Fail:
   1532     return error;
   1533 
   1534   Syntax_Error:
   1535     return PSaux_Err_Syntax_Error;
   1536 
   1537   Stack_Underflow:
   1538     return PSaux_Err_Stack_Underflow;
   1539   }
   1540 
   1541 
   1542   /* parse a single Type 1 glyph */
   1543   FT_LOCAL_DEF( FT_Error )
   1544   t1_decoder_parse_glyph( T1_Decoder  decoder,
   1545                           FT_UInt     glyph )
   1546   {
   1547     return decoder->parse_callback( decoder, glyph );
   1548   }
   1549 
   1550 
   1551   /* initialize T1 decoder */
   1552   FT_LOCAL_DEF( FT_Error )
   1553   t1_decoder_init( T1_Decoder           decoder,
   1554                    FT_Face              face,
   1555                    FT_Size              size,
   1556                    FT_GlyphSlot         slot,
   1557                    FT_Byte**            glyph_names,
   1558                    PS_Blend             blend,
   1559                    FT_Bool              hinting,
   1560                    FT_Render_Mode       hint_mode,
   1561                    T1_Decoder_Callback  parse_callback )
   1562   {
   1563     FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
   1564 
   1565     /* retrieve PSNames interface from list of current modules */
   1566     {
   1567       FT_Service_PsCMaps  psnames = 0;
   1568 
   1569 
   1570       FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
   1571       if ( !psnames )
   1572       {
   1573         FT_ERROR(( "t1_decoder_init:"
   1574                    " the `psnames' module is not available\n" ));
   1575         return PSaux_Err_Unimplemented_Feature;
   1576       }
   1577 
   1578       decoder->psnames = psnames;
   1579     }
   1580 
   1581     t1_builder_init( &decoder->builder, face, size, slot, hinting );
   1582 
   1583     /* decoder->buildchar and decoder->len_buildchar have to be  */
   1584     /* initialized by the caller since we cannot know the length */
   1585     /* of the BuildCharArray                                     */
   1586 
   1587     decoder->num_glyphs     = (FT_UInt)face->num_glyphs;
   1588     decoder->glyph_names    = glyph_names;
   1589     decoder->hint_mode      = hint_mode;
   1590     decoder->blend          = blend;
   1591     decoder->parse_callback = parse_callback;
   1592 
   1593     decoder->funcs          = t1_decoder_funcs;
   1594 
   1595     return PSaux_Err_Ok;
   1596   }
   1597 
   1598 
   1599   /* finalize T1 decoder */
   1600   FT_LOCAL_DEF( void )
   1601   t1_decoder_done( T1_Decoder  decoder )
   1602   {
   1603     t1_builder_done( &decoder->builder );
   1604   }
   1605 
   1606 
   1607 /* END */
   1608