Home | History | Annotate | Download | only in cff
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  cf2intrp.c                                                             */
      4 /*                                                                         */
      5 /*    Adobe's CFF Interpreter (body).                                      */
      6 /*                                                                         */
      7 /*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
      8 /*                                                                         */
      9 /*  This software, and all works of authorship, whether in source or       */
     10 /*  object code form as indicated by the copyright notice(s) included      */
     11 /*  herein (collectively, the "Work") is made available, and may only be   */
     12 /*  used, modified, and distributed under the FreeType Project License,    */
     13 /*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
     14 /*  FreeType Project License, each contributor to the Work hereby grants   */
     15 /*  to any individual or legal entity exercising permissions granted by    */
     16 /*  the FreeType Project License and this section (hereafter, "You" or     */
     17 /*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
     18 /*  royalty-free, irrevocable (except as stated in this section) patent    */
     19 /*  license to make, have made, use, offer to sell, sell, import, and      */
     20 /*  otherwise transfer the Work, where such license applies only to those  */
     21 /*  patent claims licensable by such contributor that are necessarily      */
     22 /*  infringed by their contribution(s) alone or by combination of their    */
     23 /*  contribution(s) with the Work to which such contribution(s) was        */
     24 /*  submitted.  If You institute patent litigation against any entity      */
     25 /*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
     26 /*  the Work or a contribution incorporated within the Work constitutes    */
     27 /*  direct or contributory patent infringement, then any patent licenses   */
     28 /*  granted to You under this License for that Work shall terminate as of  */
     29 /*  the date such litigation is filed.                                     */
     30 /*                                                                         */
     31 /*  By using, modifying, or distributing the Work you indicate that you    */
     32 /*  have read and understood the terms and conditions of the               */
     33 /*  FreeType Project License as well as those provided in this section,    */
     34 /*  and you accept them fully.                                             */
     35 /*                                                                         */
     36 /***************************************************************************/
     37 
     38 
     39 #include "cf2ft.h"
     40 #include FT_INTERNAL_DEBUG_H
     41 
     42 #include "cf2glue.h"
     43 #include "cf2font.h"
     44 #include "cf2stack.h"
     45 #include "cf2hints.h"
     46 #include "cf2intrp.h"
     47 
     48 #include "cf2error.h"
     49 
     50 
     51   /*************************************************************************/
     52   /*                                                                       */
     53   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     54   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     55   /* messages during execution.                                            */
     56   /*                                                                       */
     57 #undef  FT_COMPONENT
     58 #define FT_COMPONENT  trace_cf2interp
     59 
     60 
     61   /* some operators are not implemented yet */
     62 #define CF2_FIXME  FT_TRACE4(( "cf2_interpT2CharString:"            \
     63                                " operator not implemented yet\n" ))
     64 
     65 
     66 
     67   FT_LOCAL_DEF( void )
     68   cf2_hintmask_init( CF2_HintMask  hintmask,
     69                      FT_Error*     error )
     70   {
     71     FT_ZERO( hintmask );
     72 
     73     hintmask->error = error;
     74   }
     75 
     76 
     77   FT_LOCAL_DEF( FT_Bool )
     78   cf2_hintmask_isValid( const CF2_HintMask  hintmask )
     79   {
     80     return hintmask->isValid;
     81   }
     82 
     83 
     84   FT_LOCAL_DEF( FT_Bool )
     85   cf2_hintmask_isNew( const CF2_HintMask  hintmask )
     86   {
     87     return hintmask->isNew;
     88   }
     89 
     90 
     91   FT_LOCAL_DEF( void )
     92   cf2_hintmask_setNew( CF2_HintMask  hintmask,
     93                        FT_Bool       val )
     94   {
     95     hintmask->isNew = val;
     96   }
     97 
     98 
     99   /* clients call `getMaskPtr' in order to iterate */
    100   /* through hint mask                             */
    101 
    102   FT_LOCAL_DEF( FT_Byte* )
    103   cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask )
    104   {
    105     return hintmask->mask;
    106   }
    107 
    108 
    109   static size_t
    110   cf2_hintmask_setCounts( CF2_HintMask  hintmask,
    111                           size_t        bitCount )
    112   {
    113     if ( bitCount > CF2_MAX_HINTS )
    114     {
    115       /* total of h and v stems must be <= 96 */
    116       CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format );
    117       return 0;
    118     }
    119 
    120     hintmask->bitCount  = bitCount;
    121     hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8;
    122 
    123     hintmask->isValid = TRUE;
    124     hintmask->isNew   = TRUE;
    125 
    126     return bitCount;
    127   }
    128 
    129 
    130   /* consume the hintmask bytes from the charstring, advancing the src */
    131   /* pointer                                                           */
    132   static void
    133   cf2_hintmask_read( CF2_HintMask  hintmask,
    134                      CF2_Buffer    charstring,
    135                      size_t        bitCount )
    136   {
    137     size_t  i;
    138 
    139 #ifndef CF2_NDEBUG
    140     /* these are the bits in the final mask byte that should be zero  */
    141     /* Note: this variable is only used in an assert expression below */
    142     /* and then only if CF2_NDEBUG is not defined                     */
    143     CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
    144 #endif
    145 
    146 
    147     /* initialize counts and isValid */
    148     if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
    149       return;
    150 
    151     FT_ASSERT( hintmask->byteCount > 0 );
    152 
    153     FT_TRACE4(( " (maskbytes:" ));
    154 
    155     /* set mask and advance interpreter's charstring pointer */
    156     for ( i = 0; i < hintmask->byteCount; i++ )
    157     {
    158       hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring );
    159       FT_TRACE4(( " 0x%02X", hintmask->mask[i] ));
    160     }
    161 
    162     FT_TRACE4(( ")\n" ));
    163 
    164     /* assert any unused bits in last byte are zero unless there's a prior */
    165     /* error                                                               */
    166     /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1      */
    167 #ifndef CF2_NDEBUG
    168     FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 ||
    169                *hintmask->error                                        );
    170 #endif
    171   }
    172 
    173 
    174   FT_LOCAL_DEF( void )
    175   cf2_hintmask_setAll( CF2_HintMask  hintmask,
    176                        size_t        bitCount )
    177   {
    178     size_t    i;
    179     CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
    180 
    181 
    182     /* initialize counts and isValid */
    183     if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
    184       return;
    185 
    186     FT_ASSERT( hintmask->byteCount > 0 );
    187     FT_ASSERT( hintmask->byteCount <
    188                  sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
    189 
    190     /* set mask to all ones */
    191     for ( i = 0; i < hintmask->byteCount; i++ )
    192       hintmask->mask[i] = 0xFF;
    193 
    194     /* clear unused bits                                              */
    195     /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
    196     hintmask->mask[hintmask->byteCount - 1] &= ~mask;
    197   }
    198 
    199 
    200   /* Type2 charstring opcodes */
    201   enum
    202   {
    203     cf2_cmdRESERVED_0,   /* 0 */
    204     cf2_cmdHSTEM,        /* 1 */
    205     cf2_cmdRESERVED_2,   /* 2 */
    206     cf2_cmdVSTEM,        /* 3 */
    207     cf2_cmdVMOVETO,      /* 4 */
    208     cf2_cmdRLINETO,      /* 5 */
    209     cf2_cmdHLINETO,      /* 6 */
    210     cf2_cmdVLINETO,      /* 7 */
    211     cf2_cmdRRCURVETO,    /* 8 */
    212     cf2_cmdRESERVED_9,   /* 9 */
    213     cf2_cmdCALLSUBR,     /* 10 */
    214     cf2_cmdRETURN,       /* 11 */
    215     cf2_cmdESC,          /* 12 */
    216     cf2_cmdRESERVED_13,  /* 13 */
    217     cf2_cmdENDCHAR,      /* 14 */
    218     cf2_cmdRESERVED_15,  /* 15 */
    219     cf2_cmdRESERVED_16,  /* 16 */
    220     cf2_cmdRESERVED_17,  /* 17 */
    221     cf2_cmdHSTEMHM,      /* 18 */
    222     cf2_cmdHINTMASK,     /* 19 */
    223     cf2_cmdCNTRMASK,     /* 20 */
    224     cf2_cmdRMOVETO,      /* 21 */
    225     cf2_cmdHMOVETO,      /* 22 */
    226     cf2_cmdVSTEMHM,      /* 23 */
    227     cf2_cmdRCURVELINE,   /* 24 */
    228     cf2_cmdRLINECURVE,   /* 25 */
    229     cf2_cmdVVCURVETO,    /* 26 */
    230     cf2_cmdHHCURVETO,    /* 27 */
    231     cf2_cmdEXTENDEDNMBR, /* 28 */
    232     cf2_cmdCALLGSUBR,    /* 29 */
    233     cf2_cmdVHCURVETO,    /* 30 */
    234     cf2_cmdHVCURVETO     /* 31 */
    235   };
    236 
    237   enum
    238   {
    239     cf2_escDOTSECTION,   /* 0 */
    240     cf2_escRESERVED_1,   /* 1 */
    241     cf2_escRESERVED_2,   /* 2 */
    242     cf2_escAND,          /* 3 */
    243     cf2_escOR,           /* 4 */
    244     cf2_escNOT,          /* 5 */
    245     cf2_escRESERVED_6,   /* 6 */
    246     cf2_escRESERVED_7,   /* 7 */
    247     cf2_escRESERVED_8,   /* 8 */
    248     cf2_escABS,          /* 9 */
    249     cf2_escADD,          /* 10     like otherADD */
    250     cf2_escSUB,          /* 11     like otherSUB */
    251     cf2_escDIV,          /* 12 */
    252     cf2_escRESERVED_13,  /* 13 */
    253     cf2_escNEG,          /* 14 */
    254     cf2_escEQ,           /* 15 */
    255     cf2_escRESERVED_16,  /* 16 */
    256     cf2_escRESERVED_17,  /* 17 */
    257     cf2_escDROP,         /* 18 */
    258     cf2_escRESERVED_19,  /* 19 */
    259     cf2_escPUT,          /* 20     like otherPUT    */
    260     cf2_escGET,          /* 21     like otherGET    */
    261     cf2_escIFELSE,       /* 22     like otherIFELSE */
    262     cf2_escRANDOM,       /* 23     like otherRANDOM */
    263     cf2_escMUL,          /* 24     like otherMUL    */
    264     cf2_escRESERVED_25,  /* 25 */
    265     cf2_escSQRT,         /* 26 */
    266     cf2_escDUP,          /* 27     like otherDUP    */
    267     cf2_escEXCH,         /* 28     like otherEXCH   */
    268     cf2_escINDEX,        /* 29 */
    269     cf2_escROLL,         /* 30 */
    270     cf2_escRESERVED_31,  /* 31 */
    271     cf2_escRESERVED_32,  /* 32 */
    272     cf2_escRESERVED_33,  /* 33 */
    273     cf2_escHFLEX,        /* 34 */
    274     cf2_escFLEX,         /* 35 */
    275     cf2_escHFLEX1,       /* 36 */
    276     cf2_escFLEX1         /* 37 */
    277   };
    278 
    279 
    280   /* `stemHintArray' does not change once we start drawing the outline. */
    281   static void
    282   cf2_doStems( const CF2_Font  font,
    283                CF2_Stack       opStack,
    284                CF2_ArrStack    stemHintArray,
    285                CF2_Fixed*      width,
    286                FT_Bool*        haveWidth,
    287                CF2_Fixed       hintOffset )
    288   {
    289     CF2_UInt  i;
    290     CF2_UInt  count       = cf2_stack_count( opStack );
    291     FT_Bool   hasWidthArg = (FT_Bool)( count & 1 );
    292 
    293     /* variable accumulates delta values from operand stack */
    294     CF2_Fixed  position = hintOffset;
    295 
    296     if ( hasWidthArg && ! *haveWidth )
    297       *width = cf2_stack_getReal( opStack, 0 ) +
    298                  cf2_getNominalWidthX( font->decoder );
    299 
    300     if ( font->decoder->width_only )
    301       goto exit;
    302 
    303     for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
    304     {
    305       /* construct a CF2_StemHint and push it onto the list */
    306       CF2_StemHintRec  stemhint;
    307 
    308 
    309       stemhint.min  =
    310         position   += cf2_stack_getReal( opStack, i );
    311       stemhint.max  =
    312         position   += cf2_stack_getReal( opStack, i + 1 );
    313 
    314       stemhint.used  = FALSE;
    315       stemhint.maxDS =
    316       stemhint.minDS = 0;
    317 
    318       cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
    319     }
    320 
    321     cf2_stack_clear( opStack );
    322 
    323   exit:
    324     /* cf2_doStems must define a width (may be default) */
    325     *haveWidth = TRUE;
    326   }
    327 
    328 
    329   static void
    330   cf2_doFlex( CF2_Stack       opStack,
    331               CF2_Fixed*      curX,
    332               CF2_Fixed*      curY,
    333               CF2_GlyphPath   glyphPath,
    334               const FT_Bool*  readFromStack,
    335               FT_Bool         doConditionalLastRead )
    336   {
    337     CF2_Fixed  vals[14];
    338     CF2_UInt   index;
    339     FT_Bool    isHFlex;
    340     CF2_Int    top, i, j;
    341 
    342 
    343     vals[0] = *curX;
    344     vals[1] = *curY;
    345     index   = 0;
    346     isHFlex = readFromStack[9] == FALSE;
    347     top     = isHFlex ? 9 : 10;
    348 
    349     for ( i = 0; i < top; i++ )
    350     {
    351       vals[i + 2] = vals[i];
    352       if ( readFromStack[i] )
    353         vals[i + 2] += cf2_stack_getReal( opStack, index++ );
    354     }
    355 
    356     if ( isHFlex )
    357       vals[9 + 2] = *curY;
    358 
    359     if ( doConditionalLastRead )
    360     {
    361       FT_Bool    lastIsX = (FT_Bool)( cf2_fixedAbs( vals[10] - *curX ) >
    362                                         cf2_fixedAbs( vals[11] - *curY ) );
    363       CF2_Fixed  lastVal = cf2_stack_getReal( opStack, index );
    364 
    365 
    366       if ( lastIsX )
    367       {
    368         vals[12] = vals[10] + lastVal;
    369         vals[13] = *curY;
    370       }
    371       else
    372       {
    373         vals[12] = *curX;
    374         vals[13] = vals[11] + lastVal;
    375       }
    376     }
    377     else
    378     {
    379       if ( readFromStack[10] )
    380         vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ );
    381       else
    382         vals[12] = *curX;
    383 
    384       if ( readFromStack[11] )
    385         vals[13] = vals[11] + cf2_stack_getReal( opStack, index );
    386       else
    387         vals[13] = *curY;
    388     }
    389 
    390     for ( j = 0; j < 2; j++ )
    391       cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
    392                                         vals[j * 6 + 3],
    393                                         vals[j * 6 + 4],
    394                                         vals[j * 6 + 5],
    395                                         vals[j * 6 + 6],
    396                                         vals[j * 6 + 7] );
    397 
    398     cf2_stack_clear( opStack );
    399 
    400     *curX = vals[12];
    401     *curY = vals[13];
    402   }
    403 
    404 
    405   /*
    406    * `error' is a shared error code used by many objects in this
    407    * routine.  Before the code continues from an error, it must check and
    408    * record the error in `*error'.  The idea is that this shared
    409    * error code will record the first error encountered.  If testing
    410    * for an error anyway, the cost of `goto exit' is small, so we do it,
    411    * even if continuing would be safe.  In this case, `lastError' is
    412    * set, so the testing and storing can be done in one place, at `exit'.
    413    *
    414    * Continuing after an error is intended for objects which do their own
    415    * testing of `*error', e.g., array stack functions.  This allows us to
    416    * avoid an extra test after the call.
    417    *
    418    * Unimplemented opcodes are ignored.
    419    *
    420    */
    421   FT_LOCAL_DEF( void )
    422   cf2_interpT2CharString( CF2_Font              font,
    423                           CF2_Buffer            buf,
    424                           CF2_OutlineCallbacks  callbacks,
    425                           const FT_Vector*      translation,
    426                           FT_Bool               doingSeac,
    427                           CF2_Fixed             curX,
    428                           CF2_Fixed             curY,
    429                           CF2_Fixed*            width )
    430   {
    431     /* lastError is used for errors that are immediately tested */
    432     FT_Error  lastError = FT_Err_Ok;
    433 
    434     /* pointer to parsed font object */
    435     CFF_Decoder*  decoder = font->decoder;
    436 
    437     FT_Error*  error  = &font->error;
    438     FT_Memory  memory = font->memory;
    439 
    440     CF2_Fixed  scaleY        = font->innerTransform.d;
    441     CF2_Fixed  nominalWidthX = cf2_getNominalWidthX( decoder );
    442 
    443     /* save this for hinting seac accents */
    444     CF2_Fixed  hintOriginY = curY;
    445 
    446     CF2_Stack  opStack = NULL;
    447     FT_Byte    op1;                       /* first opcode byte */
    448 
    449     /* instruction limit; 20,000,000 matches Avalon */
    450     FT_UInt32  instructionLimit = 20000000UL;
    451 
    452     CF2_ArrStackRec  subrStack;
    453 
    454     FT_Bool     haveWidth;
    455     CF2_Buffer  charstring = NULL;
    456 
    457     CF2_Int  charstringIndex = -1;       /* initialize to empty */
    458 
    459     /* TODO: placeholders for hint structures */
    460 
    461     /* objects used for hinting */
    462     CF2_ArrStackRec  hStemHintArray;
    463     CF2_ArrStackRec  vStemHintArray;
    464 
    465     CF2_HintMaskRec   hintMask;
    466     CF2_GlyphPathRec  glyphPath;
    467 
    468 
    469     /* initialize the remaining objects */
    470     cf2_arrstack_init( &subrStack,
    471                        memory,
    472                        error,
    473                        sizeof ( CF2_BufferRec ) );
    474     cf2_arrstack_init( &hStemHintArray,
    475                        memory,
    476                        error,
    477                        sizeof ( CF2_StemHintRec ) );
    478     cf2_arrstack_init( &vStemHintArray,
    479                        memory,
    480                        error,
    481                        sizeof ( CF2_StemHintRec ) );
    482 
    483     /* initialize CF2_StemHint arrays */
    484     cf2_hintmask_init( &hintMask, error );
    485 
    486     /* initialize path map to manage drawing operations */
    487 
    488     /* Note: last 4 params are used to handle `MoveToPermissive', which */
    489     /*       may need to call `hintMap.Build'                           */
    490     /* TODO: MoveToPermissive is gone; are these still needed?          */
    491     cf2_glyphpath_init( &glyphPath,
    492                         font,
    493                         callbacks,
    494                         scaleY,
    495                         /* hShift, */
    496                         &hStemHintArray,
    497                         &vStemHintArray,
    498                         &hintMask,
    499                         hintOriginY,
    500                         &font->blues,
    501                         translation );
    502 
    503     /*
    504      * Initialize state for width parsing.  From the CFF Spec:
    505      *
    506      *   The first stack-clearing operator, which must be one of hstem,
    507      *   hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
    508      *   rmoveto, or endchar, takes an additional argument - the width (as
    509      *   described earlier), which may be expressed as zero or one numeric
    510      *   argument.
    511      *
    512      * What we implement here uses the first validly specified width, but
    513      * does not detect errors for specifying more than one width.
    514      *
    515      * If one of the above operators occurs without explicitly specifying
    516      * a width, we assume the default width.
    517      *
    518      */
    519     haveWidth = FALSE;
    520     *width    = cf2_getDefaultWidthX( decoder );
    521 
    522     /*
    523      * Note: at this point, all pointers to resources must be NULL
    524      * and all local objects must be initialized.
    525      * There must be no branches to exit: above this point.
    526      *
    527      */
    528 
    529     /* allocate an operand stack */
    530     opStack = cf2_stack_init( memory, error );
    531     if ( !opStack )
    532     {
    533       lastError = FT_THROW( Out_Of_Memory );
    534       goto exit;
    535     }
    536 
    537     /* initialize subroutine stack by placing top level charstring as */
    538     /* first element (max depth plus one for the charstring)          */
    539     /* Note: Caller owns and must finalize the first charstring.      */
    540     /*       Our copy of it does not change that requirement.         */
    541     cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
    542 
    543     charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
    544     *charstring = *buf;    /* structure copy */
    545 
    546     charstringIndex = 0;       /* entry is valid now */
    547 
    548     /* catch errors so far */
    549     if ( *error )
    550       goto exit;
    551 
    552     /* main interpreter loop */
    553     while ( 1 )
    554     {
    555       if ( cf2_buf_isEnd( charstring ) )
    556       {
    557         /* If we've reached the end of the charstring, simulate a */
    558         /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
    559         if ( charstringIndex )
    560           op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
    561         else
    562           op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
    563       }
    564       else
    565         op1 = (FT_Byte)cf2_buf_readByte( charstring );
    566 
    567       /* check for errors once per loop */
    568       if ( *error )
    569         goto exit;
    570 
    571       instructionLimit--;
    572       if ( instructionLimit == 0 )
    573       {
    574         lastError = FT_THROW( Invalid_Glyph_Format );
    575         goto exit;
    576       }
    577 
    578       switch( op1 )
    579       {
    580       case cf2_cmdRESERVED_0:
    581       case cf2_cmdRESERVED_2:
    582       case cf2_cmdRESERVED_9:
    583       case cf2_cmdRESERVED_13:
    584       case cf2_cmdRESERVED_15:
    585       case cf2_cmdRESERVED_16:
    586       case cf2_cmdRESERVED_17:
    587         /* we may get here if we have a prior error */
    588         FT_TRACE4(( " unknown op (%d)\n", op1 ));
    589         break;
    590 
    591       case cf2_cmdHSTEMHM:
    592       case cf2_cmdHSTEM:
    593         FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
    594 
    595         /* never add hints after the mask is computed */
    596         if ( cf2_hintmask_isValid( &hintMask ) )
    597         {
    598           FT_TRACE4(( "cf2_interpT2CharString:"
    599                       " invalid horizontal hint mask\n" ));
    600           break;
    601         }
    602 
    603         cf2_doStems( font,
    604                      opStack,
    605                      &hStemHintArray,
    606                      width,
    607                      &haveWidth,
    608                      0 );
    609 
    610         if ( font->decoder->width_only )
    611             goto exit;
    612 
    613         break;
    614 
    615       case cf2_cmdVSTEMHM:
    616       case cf2_cmdVSTEM:
    617         FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
    618 
    619         /* never add hints after the mask is computed */
    620         if ( cf2_hintmask_isValid( &hintMask ) )
    621         {
    622           FT_TRACE4(( "cf2_interpT2CharString:"
    623                       " invalid vertical hint mask\n" ));
    624           break;
    625         }
    626 
    627         cf2_doStems( font,
    628                      opStack,
    629                      &vStemHintArray,
    630                      width,
    631                      &haveWidth,
    632                      0 );
    633 
    634         if ( font->decoder->width_only )
    635             goto exit;
    636 
    637         break;
    638 
    639       case cf2_cmdVMOVETO:
    640         FT_TRACE4(( " vmoveto\n" ));
    641 
    642         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
    643           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
    644 
    645         /* width is defined or default after this */
    646         haveWidth = TRUE;
    647 
    648         if ( font->decoder->width_only )
    649             goto exit;
    650 
    651         curY += cf2_stack_popFixed( opStack );
    652 
    653         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
    654 
    655         break;
    656 
    657       case cf2_cmdRLINETO:
    658         {
    659           CF2_UInt  index;
    660           CF2_UInt  count = cf2_stack_count( opStack );
    661 
    662 
    663           FT_TRACE4(( " rlineto\n" ));
    664 
    665           for ( index = 0; index < count; index += 2 )
    666           {
    667             curX += cf2_stack_getReal( opStack, index + 0 );
    668             curY += cf2_stack_getReal( opStack, index + 1 );
    669 
    670             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
    671           }
    672 
    673           cf2_stack_clear( opStack );
    674         }
    675         continue; /* no need to clear stack again */
    676 
    677       case cf2_cmdHLINETO:
    678       case cf2_cmdVLINETO:
    679         {
    680           CF2_UInt  index;
    681           CF2_UInt  count = cf2_stack_count( opStack );
    682 
    683           FT_Bool  isX = op1 == cf2_cmdHLINETO;
    684 
    685 
    686           FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
    687 
    688           for ( index = 0; index < count; index++ )
    689           {
    690             CF2_Fixed  v = cf2_stack_getReal( opStack, index );
    691 
    692 
    693             if ( isX )
    694               curX += v;
    695             else
    696               curY += v;
    697 
    698             isX = !isX;
    699 
    700             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
    701           }
    702 
    703           cf2_stack_clear( opStack );
    704         }
    705         continue;
    706 
    707       case cf2_cmdRCURVELINE:
    708       case cf2_cmdRRCURVETO:
    709         {
    710           CF2_UInt  count = cf2_stack_count( opStack );
    711           CF2_UInt  index = 0;
    712 
    713 
    714           FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
    715                                                : " rrcurveto\n" ));
    716 
    717           while ( index + 6 <= count )
    718           {
    719             CF2_Fixed  x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
    720             CF2_Fixed  y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
    721             CF2_Fixed  x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
    722             CF2_Fixed  y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
    723             CF2_Fixed  x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
    724             CF2_Fixed  y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
    725 
    726 
    727             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
    728 
    729             curX   = x3;
    730             curY   = y3;
    731             index += 6;
    732           }
    733 
    734           if ( op1 == cf2_cmdRCURVELINE )
    735           {
    736             curX += cf2_stack_getReal( opStack, index + 0 );
    737             curY += cf2_stack_getReal( opStack, index + 1 );
    738 
    739             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
    740           }
    741 
    742           cf2_stack_clear( opStack );
    743         }
    744         continue; /* no need to clear stack again */
    745 
    746       case cf2_cmdCALLGSUBR:
    747       case cf2_cmdCALLSUBR:
    748         {
    749           CF2_UInt  subrIndex;
    750 
    751 
    752           FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
    753                                               : " callsubr" ));
    754 
    755           if ( charstringIndex > CF2_MAX_SUBR )
    756           {
    757             /* max subr plus one for charstring */
    758             lastError = FT_THROW( Invalid_Glyph_Format );
    759             goto exit;                      /* overflow of stack */
    760           }
    761 
    762           /* push our current CFF charstring region on subrStack */
    763           charstring = (CF2_Buffer)
    764                          cf2_arrstack_getPointer(
    765                            &subrStack,
    766                            (size_t)charstringIndex + 1 );
    767 
    768           /* set up the new CFF region and pointer */
    769           subrIndex = (CF2_UInt)cf2_stack_popInt( opStack );
    770 
    771           switch ( op1 )
    772           {
    773           case cf2_cmdCALLGSUBR:
    774             FT_TRACE4(( " (idx %d, entering level %d)\n",
    775                         subrIndex + (CF2_UInt)decoder->globals_bias,
    776                         charstringIndex + 1 ));
    777 
    778             if ( cf2_initGlobalRegionBuffer( decoder,
    779                                              subrIndex,
    780                                              charstring ) )
    781             {
    782               lastError = FT_THROW( Invalid_Glyph_Format );
    783               goto exit;  /* subroutine lookup or stream error */
    784             }
    785             break;
    786 
    787           default:
    788             /* cf2_cmdCALLSUBR */
    789             FT_TRACE4(( " (idx %d, entering level %d)\n",
    790                         subrIndex + (CF2_UInt)decoder->locals_bias,
    791                         charstringIndex + 1 ));
    792 
    793             if ( cf2_initLocalRegionBuffer( decoder,
    794                                             subrIndex,
    795                                             charstring ) )
    796             {
    797               lastError = FT_THROW( Invalid_Glyph_Format );
    798               goto exit;  /* subroutine lookup or stream error */
    799             }
    800           }
    801 
    802           charstringIndex += 1;       /* entry is valid now */
    803         }
    804         continue; /* do not clear the stack */
    805 
    806       case cf2_cmdRETURN:
    807         FT_TRACE4(( " return (leaving level %d)\n", charstringIndex ));
    808 
    809         if ( charstringIndex < 1 )
    810         {
    811           /* Note: cannot return from top charstring */
    812           lastError = FT_THROW( Invalid_Glyph_Format );
    813           goto exit;                      /* underflow of stack */
    814         }
    815 
    816         /* restore position in previous charstring */
    817         charstring = (CF2_Buffer)
    818                        cf2_arrstack_getPointer(
    819                          &subrStack,
    820                          (CF2_UInt)--charstringIndex );
    821         continue;     /* do not clear the stack */
    822 
    823       case cf2_cmdESC:
    824         {
    825           FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
    826 
    827 
    828           switch ( op2 )
    829           {
    830           case cf2_escDOTSECTION:
    831             /* something about `flip type of locking' -- ignore it */
    832             FT_TRACE4(( " dotsection\n" ));
    833 
    834             break;
    835 
    836           /* TODO: should these operators be supported? */
    837           case cf2_escAND: /* in spec */
    838             FT_TRACE4(( " and\n" ));
    839 
    840             CF2_FIXME;
    841             break;
    842 
    843           case cf2_escOR: /* in spec */
    844             FT_TRACE4(( " or\n" ));
    845 
    846             CF2_FIXME;
    847             break;
    848 
    849           case cf2_escNOT: /* in spec */
    850             FT_TRACE4(( " not\n" ));
    851 
    852             CF2_FIXME;
    853             break;
    854 
    855           case cf2_escABS: /* in spec */
    856             FT_TRACE4(( " abs\n" ));
    857 
    858             CF2_FIXME;
    859             break;
    860 
    861           case cf2_escADD: /* in spec */
    862             FT_TRACE4(( " add\n" ));
    863 
    864             CF2_FIXME;
    865             break;
    866 
    867           case cf2_escSUB: /* in spec */
    868             FT_TRACE4(( " sub\n" ));
    869 
    870             CF2_FIXME;
    871             break;
    872 
    873           case cf2_escDIV: /* in spec */
    874             FT_TRACE4(( " div\n" ));
    875 
    876             CF2_FIXME;
    877             break;
    878 
    879           case cf2_escNEG: /* in spec */
    880             FT_TRACE4(( " neg\n" ));
    881 
    882             CF2_FIXME;
    883             break;
    884 
    885           case cf2_escEQ: /* in spec */
    886             FT_TRACE4(( " eq\n" ));
    887 
    888             CF2_FIXME;
    889             break;
    890 
    891           case cf2_escDROP: /* in spec */
    892             FT_TRACE4(( " drop\n" ));
    893 
    894             CF2_FIXME;
    895             break;
    896 
    897           case cf2_escPUT: /* in spec */
    898             FT_TRACE4(( " put\n" ));
    899 
    900             CF2_FIXME;
    901             break;
    902 
    903           case cf2_escGET: /* in spec */
    904             FT_TRACE4(( " get\n" ));
    905 
    906             CF2_FIXME;
    907             break;
    908 
    909           case cf2_escIFELSE: /* in spec */
    910             FT_TRACE4(( " ifelse\n" ));
    911 
    912             CF2_FIXME;
    913             break;
    914 
    915           case cf2_escRANDOM: /* in spec */
    916             FT_TRACE4(( " random\n" ));
    917 
    918             CF2_FIXME;
    919             break;
    920 
    921           case cf2_escMUL: /* in spec */
    922             FT_TRACE4(( " mul\n" ));
    923 
    924             CF2_FIXME;
    925             break;
    926 
    927           case cf2_escSQRT: /* in spec */
    928             FT_TRACE4(( " sqrt\n" ));
    929 
    930             CF2_FIXME;
    931             break;
    932 
    933           case cf2_escDUP: /* in spec */
    934             FT_TRACE4(( " dup\n" ));
    935 
    936             CF2_FIXME;
    937             break;
    938 
    939           case cf2_escEXCH: /* in spec */
    940             FT_TRACE4(( " exch\n" ));
    941 
    942             CF2_FIXME;
    943             break;
    944 
    945           case cf2_escINDEX: /* in spec */
    946             FT_TRACE4(( " index\n" ));
    947 
    948             CF2_FIXME;
    949             break;
    950 
    951           case cf2_escROLL: /* in spec */
    952             FT_TRACE4(( " roll\n" ));
    953 
    954             CF2_FIXME;
    955             break;
    956 
    957           case cf2_escHFLEX:
    958             {
    959               static const FT_Bool  readFromStack[12] =
    960               {
    961                 TRUE /* dx1 */, FALSE /* dy1 */,
    962                 TRUE /* dx2 */, TRUE  /* dy2 */,
    963                 TRUE /* dx3 */, FALSE /* dy3 */,
    964                 TRUE /* dx4 */, FALSE /* dy4 */,
    965                 TRUE /* dx5 */, FALSE /* dy5 */,
    966                 TRUE /* dx6 */, FALSE /* dy6 */
    967               };
    968 
    969 
    970               FT_TRACE4(( " hflex\n" ));
    971 
    972               cf2_doFlex( opStack,
    973                           &curX,
    974                           &curY,
    975                           &glyphPath,
    976                           readFromStack,
    977                           FALSE /* doConditionalLastRead */ );
    978             }
    979             continue;
    980 
    981           case cf2_escFLEX:
    982             {
    983               static const FT_Bool  readFromStack[12] =
    984               {
    985                 TRUE /* dx1 */, TRUE /* dy1 */,
    986                 TRUE /* dx2 */, TRUE /* dy2 */,
    987                 TRUE /* dx3 */, TRUE /* dy3 */,
    988                 TRUE /* dx4 */, TRUE /* dy4 */,
    989                 TRUE /* dx5 */, TRUE /* dy5 */,
    990                 TRUE /* dx6 */, TRUE /* dy6 */
    991               };
    992 
    993 
    994               FT_TRACE4(( " flex\n" ));
    995 
    996               cf2_doFlex( opStack,
    997                           &curX,
    998                           &curY,
    999                           &glyphPath,
   1000                           readFromStack,
   1001                           FALSE /* doConditionalLastRead */ );
   1002             }
   1003             break;      /* TODO: why is this not a continue? */
   1004 
   1005           case cf2_escHFLEX1:
   1006             {
   1007               static const FT_Bool  readFromStack[12] =
   1008               {
   1009                 TRUE /* dx1 */, TRUE  /* dy1 */,
   1010                 TRUE /* dx2 */, TRUE  /* dy2 */,
   1011                 TRUE /* dx3 */, FALSE /* dy3 */,
   1012                 TRUE /* dx4 */, FALSE /* dy4 */,
   1013                 TRUE /* dx5 */, TRUE  /* dy5 */,
   1014                 TRUE /* dx6 */, FALSE /* dy6 */
   1015               };
   1016 
   1017 
   1018               FT_TRACE4(( " hflex1\n" ));
   1019 
   1020               cf2_doFlex( opStack,
   1021                           &curX,
   1022                           &curY,
   1023                           &glyphPath,
   1024                           readFromStack,
   1025                           FALSE /* doConditionalLastRead */ );
   1026             }
   1027             continue;
   1028 
   1029           case cf2_escFLEX1:
   1030             {
   1031               static const FT_Bool  readFromStack[12] =
   1032               {
   1033                 TRUE  /* dx1 */, TRUE  /* dy1 */,
   1034                 TRUE  /* dx2 */, TRUE  /* dy2 */,
   1035                 TRUE  /* dx3 */, TRUE  /* dy3 */,
   1036                 TRUE  /* dx4 */, TRUE  /* dy4 */,
   1037                 TRUE  /* dx5 */, TRUE  /* dy5 */,
   1038                 FALSE /* dx6 */, FALSE /* dy6 */
   1039               };
   1040 
   1041 
   1042               FT_TRACE4(( " flex1\n" ));
   1043 
   1044               cf2_doFlex( opStack,
   1045                           &curX,
   1046                           &curY,
   1047                           &glyphPath,
   1048                           readFromStack,
   1049                           TRUE /* doConditionalLastRead */ );
   1050             }
   1051             continue;
   1052 
   1053           case cf2_escRESERVED_1:
   1054           case cf2_escRESERVED_2:
   1055           case cf2_escRESERVED_6:
   1056           case cf2_escRESERVED_7:
   1057           case cf2_escRESERVED_8:
   1058           case cf2_escRESERVED_13:
   1059           case cf2_escRESERVED_16:
   1060           case cf2_escRESERVED_17:
   1061           case cf2_escRESERVED_19:
   1062           case cf2_escRESERVED_25:
   1063           case cf2_escRESERVED_31:
   1064           case cf2_escRESERVED_32:
   1065           case cf2_escRESERVED_33:
   1066           default:
   1067             FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
   1068 
   1069           }; /* end of switch statement checking `op2' */
   1070 
   1071         } /* case cf2_cmdESC */
   1072         break;
   1073 
   1074       case cf2_cmdENDCHAR:
   1075         FT_TRACE4(( " endchar\n" ));
   1076 
   1077         if ( cf2_stack_count( opStack ) == 1 ||
   1078              cf2_stack_count( opStack ) == 5 )
   1079         {
   1080           if ( !haveWidth )
   1081             *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
   1082         }
   1083 
   1084         /* width is defined or default after this */
   1085         haveWidth = TRUE;
   1086 
   1087         if ( font->decoder->width_only )
   1088             goto exit;
   1089 
   1090         /* close path if still open */
   1091         cf2_glyphpath_closeOpenPath( &glyphPath );
   1092 
   1093         if ( cf2_stack_count( opStack ) > 1 )
   1094         {
   1095           /* must be either 4 or 5 --                       */
   1096           /* this is a (deprecated) implied `seac' operator */
   1097 
   1098           CF2_Int        achar;
   1099           CF2_Int        bchar;
   1100           CF2_BufferRec  component;
   1101           CF2_Fixed      dummyWidth;   /* ignore component width */
   1102           FT_Error       error2;
   1103 
   1104 
   1105           if ( doingSeac )
   1106           {
   1107             lastError = FT_THROW( Invalid_Glyph_Format );
   1108             goto exit;      /* nested seac */
   1109           }
   1110 
   1111           achar = cf2_stack_popInt( opStack );
   1112           bchar = cf2_stack_popInt( opStack );
   1113 
   1114           curY = cf2_stack_popFixed( opStack );
   1115           curX = cf2_stack_popFixed( opStack );
   1116 
   1117           error2 = cf2_getSeacComponent( decoder, achar, &component );
   1118           if ( error2 )
   1119           {
   1120              lastError = error2;      /* pass FreeType error through */
   1121              goto exit;
   1122           }
   1123           cf2_interpT2CharString( font,
   1124                                   &component,
   1125                                   callbacks,
   1126                                   translation,
   1127                                   TRUE,
   1128                                   curX,
   1129                                   curY,
   1130                                   &dummyWidth );
   1131           cf2_freeSeacComponent( decoder, &component );
   1132 
   1133           error2 = cf2_getSeacComponent( decoder, bchar, &component );
   1134           if ( error2 )
   1135           {
   1136             lastError = error2;      /* pass FreeType error through */
   1137             goto exit;
   1138           }
   1139           cf2_interpT2CharString( font,
   1140                                   &component,
   1141                                   callbacks,
   1142                                   translation,
   1143                                   TRUE,
   1144                                   0,
   1145                                   0,
   1146                                   &dummyWidth );
   1147           cf2_freeSeacComponent( decoder, &component );
   1148         }
   1149         goto exit;
   1150 
   1151       case cf2_cmdCNTRMASK:
   1152       case cf2_cmdHINTMASK:
   1153         /* the final \n in the tracing message gets added in      */
   1154         /* `cf2_hintmask_read' (which also traces the mask bytes) */
   1155         FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
   1156 
   1157         /* never add hints after the mask is computed */
   1158         if ( cf2_stack_count( opStack ) > 1    &&
   1159              cf2_hintmask_isValid( &hintMask ) )
   1160         {
   1161           FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
   1162           break;
   1163         }
   1164 
   1165         /* if there are arguments on the stack, there this is an */
   1166         /* implied cf2_cmdVSTEMHM                                */
   1167         cf2_doStems( font,
   1168                      opStack,
   1169                      &vStemHintArray,
   1170                      width,
   1171                      &haveWidth,
   1172                      0 );
   1173 
   1174         if ( font->decoder->width_only )
   1175             goto exit;
   1176 
   1177         if ( op1 == cf2_cmdHINTMASK )
   1178         {
   1179           /* consume the hint mask bytes which follow the operator */
   1180           cf2_hintmask_read( &hintMask,
   1181                              charstring,
   1182                              cf2_arrstack_size( &hStemHintArray ) +
   1183                                cf2_arrstack_size( &vStemHintArray ) );
   1184         }
   1185         else
   1186         {
   1187           /*
   1188            * Consume the counter mask bytes which follow the operator:
   1189            * Build a temporary hint map, just to place and lock those
   1190            * stems participating in the counter mask.  These are most
   1191            * likely the dominant hstems, and are grouped together in a
   1192            * few counter groups, not necessarily in correspondence
   1193            * with the hint groups.  This reduces the chances of
   1194            * conflicts between hstems that are initially placed in
   1195            * separate hint groups and then brought together.  The
   1196            * positions are copied back to `hStemHintArray', so we can
   1197            * discard `counterMask' and `counterHintMap'.
   1198            *
   1199            */
   1200           CF2_HintMapRec   counterHintMap;
   1201           CF2_HintMaskRec  counterMask;
   1202 
   1203 
   1204           cf2_hintmap_init( &counterHintMap,
   1205                             font,
   1206                             &glyphPath.initialHintMap,
   1207                             &glyphPath.hintMoves,
   1208                             scaleY );
   1209           cf2_hintmask_init( &counterMask, error );
   1210 
   1211           cf2_hintmask_read( &counterMask,
   1212                              charstring,
   1213                              cf2_arrstack_size( &hStemHintArray ) +
   1214                                cf2_arrstack_size( &vStemHintArray ) );
   1215           cf2_hintmap_build( &counterHintMap,
   1216                              &hStemHintArray,
   1217                              &vStemHintArray,
   1218                              &counterMask,
   1219                              0,
   1220                              FALSE );
   1221         }
   1222         break;
   1223 
   1224       case cf2_cmdRMOVETO:
   1225         FT_TRACE4(( " rmoveto\n" ));
   1226 
   1227         if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
   1228           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
   1229 
   1230         /* width is defined or default after this */
   1231         haveWidth = TRUE;
   1232 
   1233         if ( font->decoder->width_only )
   1234             goto exit;
   1235 
   1236         curY += cf2_stack_popFixed( opStack );
   1237         curX += cf2_stack_popFixed( opStack );
   1238 
   1239         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
   1240 
   1241         break;
   1242 
   1243       case cf2_cmdHMOVETO:
   1244         FT_TRACE4(( " hmoveto\n" ));
   1245 
   1246         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
   1247           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
   1248 
   1249         /* width is defined or default after this */
   1250         haveWidth = TRUE;
   1251 
   1252         if ( font->decoder->width_only )
   1253             goto exit;
   1254 
   1255         curX += cf2_stack_popFixed( opStack );
   1256 
   1257         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
   1258 
   1259         break;
   1260 
   1261       case cf2_cmdRLINECURVE:
   1262         {
   1263           CF2_UInt  count = cf2_stack_count( opStack );
   1264           CF2_UInt  index = 0;
   1265 
   1266 
   1267           FT_TRACE4(( " rlinecurve\n" ));
   1268 
   1269           while ( index + 6 < count )
   1270           {
   1271             curX += cf2_stack_getReal( opStack, index + 0 );
   1272             curY += cf2_stack_getReal( opStack, index + 1 );
   1273 
   1274             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
   1275             index += 2;
   1276           }
   1277 
   1278           while ( index < count )
   1279           {
   1280             CF2_Fixed  x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
   1281             CF2_Fixed  y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
   1282             CF2_Fixed  x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
   1283             CF2_Fixed  y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
   1284             CF2_Fixed  x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
   1285             CF2_Fixed  y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
   1286 
   1287 
   1288             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
   1289 
   1290             curX   = x3;
   1291             curY   = y3;
   1292             index += 6;
   1293           }
   1294 
   1295           cf2_stack_clear( opStack );
   1296         }
   1297         continue; /* no need to clear stack again */
   1298 
   1299       case cf2_cmdVVCURVETO:
   1300         {
   1301           CF2_UInt  count, count1 = cf2_stack_count( opStack );
   1302           CF2_UInt  index = 0;
   1303 
   1304 
   1305           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
   1306           /* we enforce it by clearing the second bit           */
   1307           /* (and sorting the stack indexing to suit)           */
   1308           count  = count1 & ~2;
   1309           index += count1 - count;
   1310 
   1311           FT_TRACE4(( " vvcurveto\n" ));
   1312 
   1313           while ( index < count )
   1314           {
   1315             CF2_Fixed  x1, y1, x2, y2, x3, y3;
   1316 
   1317 
   1318             if ( ( count - index ) & 1 )
   1319             {
   1320               x1 = cf2_stack_getReal( opStack, index ) + curX;
   1321 
   1322               ++index;
   1323             }
   1324             else
   1325               x1 = curX;
   1326 
   1327             y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
   1328             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
   1329             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
   1330             x3 = x2;
   1331             y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
   1332 
   1333             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
   1334 
   1335             curX   = x3;
   1336             curY   = y3;
   1337             index += 4;
   1338           }
   1339 
   1340           cf2_stack_clear( opStack );
   1341         }
   1342         continue; /* no need to clear stack again */
   1343 
   1344       case cf2_cmdHHCURVETO:
   1345         {
   1346           CF2_UInt  count, count1 = cf2_stack_count( opStack );
   1347           CF2_UInt  index = 0;
   1348 
   1349 
   1350           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
   1351           /* we enforce it by clearing the second bit           */
   1352           /* (and sorting the stack indexing to suit)           */
   1353           count  = count1 & ~2;
   1354           index += count1 - count;
   1355 
   1356           FT_TRACE4(( " hhcurveto\n" ));
   1357 
   1358           while ( index < count )
   1359           {
   1360             CF2_Fixed  x1, y1, x2, y2, x3, y3;
   1361 
   1362 
   1363             if ( ( count - index ) & 1 )
   1364             {
   1365               y1 = cf2_stack_getReal( opStack, index ) + curY;
   1366 
   1367               ++index;
   1368             }
   1369             else
   1370               y1 = curY;
   1371 
   1372             x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
   1373             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
   1374             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
   1375             x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
   1376             y3 = y2;
   1377 
   1378             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
   1379 
   1380             curX   = x3;
   1381             curY   = y3;
   1382             index += 4;
   1383           }
   1384 
   1385           cf2_stack_clear( opStack );
   1386         }
   1387         continue; /* no need to clear stack again */
   1388 
   1389       case cf2_cmdVHCURVETO:
   1390       case cf2_cmdHVCURVETO:
   1391         {
   1392           CF2_UInt  count, count1 = cf2_stack_count( opStack );
   1393           CF2_UInt  index = 0;
   1394 
   1395           FT_Bool  alternate = op1 == cf2_cmdHVCURVETO;
   1396 
   1397 
   1398           /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */
   1399           /* 8n+4, or 8n+5, we enforce it by clearing the     */
   1400           /* second bit                                       */
   1401           /* (and sorting the stack indexing to suit)         */
   1402           count  = count1 & ~2;
   1403           index += count1 - count;
   1404 
   1405           FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
   1406 
   1407           while ( index < count )
   1408           {
   1409             CF2_Fixed x1, x2, x3, y1, y2, y3;
   1410 
   1411 
   1412             if ( alternate )
   1413             {
   1414               x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
   1415               y1 = curY;
   1416               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
   1417               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
   1418               y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
   1419 
   1420               if ( count - index == 5 )
   1421               {
   1422                 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
   1423 
   1424                 ++index;
   1425               }
   1426               else
   1427                 x3 = x2;
   1428 
   1429               alternate = FALSE;
   1430             }
   1431             else
   1432             {
   1433               x1 = curX;
   1434               y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
   1435               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
   1436               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
   1437               x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
   1438 
   1439               if ( count - index == 5 )
   1440               {
   1441                 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
   1442 
   1443                 ++index;
   1444               }
   1445               else
   1446                 y3 = y2;
   1447 
   1448               alternate = TRUE;
   1449             }
   1450 
   1451             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
   1452 
   1453             curX   = x3;
   1454             curY   = y3;
   1455             index += 4;
   1456           }
   1457 
   1458           cf2_stack_clear( opStack );
   1459         }
   1460         continue;     /* no need to clear stack again */
   1461 
   1462       case cf2_cmdEXTENDEDNMBR:
   1463         {
   1464           CF2_Int  v;
   1465 
   1466 
   1467           v = (FT_Short)( ( cf2_buf_readByte( charstring ) << 8 ) |
   1468                             cf2_buf_readByte( charstring )        );
   1469 
   1470           FT_TRACE4(( " %d", v ));
   1471 
   1472           cf2_stack_pushInt( opStack, v );
   1473         }
   1474         continue;
   1475 
   1476       default:
   1477         /* numbers */
   1478         {
   1479           if ( /* op1 >= 32 && */ op1 <= 246 )
   1480           {
   1481             CF2_Int  v;
   1482 
   1483 
   1484             v = op1 - 139;
   1485 
   1486             FT_TRACE4(( " %d", v ));
   1487 
   1488             /* -107 .. 107 */
   1489             cf2_stack_pushInt( opStack, v );
   1490           }
   1491 
   1492           else if ( /* op1 >= 247 && */ op1 <= 250 )
   1493           {
   1494             CF2_Int  v;
   1495 
   1496 
   1497             v  = op1;
   1498             v -= 247;
   1499             v *= 256;
   1500             v += cf2_buf_readByte( charstring );
   1501             v += 108;
   1502 
   1503             FT_TRACE4(( " %d", v ));
   1504 
   1505             /* 108 .. 1131 */
   1506             cf2_stack_pushInt( opStack, v );
   1507           }
   1508 
   1509           else if ( /* op1 >= 251 && */ op1 <= 254 )
   1510           {
   1511             CF2_Int  v;
   1512 
   1513 
   1514             v  = op1;
   1515             v -= 251;
   1516             v *= 256;
   1517             v += cf2_buf_readByte( charstring );
   1518             v  = -v - 108;
   1519 
   1520             FT_TRACE4(( " %d", v ));
   1521 
   1522             /* -1131 .. -108 */
   1523             cf2_stack_pushInt( opStack, v );
   1524           }
   1525 
   1526           else /* op1 == 255 */
   1527           {
   1528             CF2_Fixed  v;
   1529 
   1530 
   1531             v = (CF2_Fixed)
   1532                   ( ( (FT_UInt32)cf2_buf_readByte( charstring ) << 24 ) |
   1533                     ( (FT_UInt32)cf2_buf_readByte( charstring ) << 16 ) |
   1534                     ( (FT_UInt32)cf2_buf_readByte( charstring ) <<  8 ) |
   1535                       (FT_UInt32)cf2_buf_readByte( charstring )         );
   1536 
   1537             FT_TRACE4(( " %.2f", v / 65536.0 ));
   1538 
   1539             cf2_stack_pushFixed( opStack, v );
   1540           }
   1541         }
   1542         continue;   /* don't clear stack */
   1543 
   1544       } /* end of switch statement checking `op1' */
   1545 
   1546       cf2_stack_clear( opStack );
   1547 
   1548     } /* end of main interpreter loop */
   1549 
   1550     /* we get here if the charstring ends without cf2_cmdENDCHAR */
   1551     FT_TRACE4(( "cf2_interpT2CharString:"
   1552                 "  charstring ends without ENDCHAR\n" ));
   1553 
   1554   exit:
   1555     /* check whether last error seen is also the first one */
   1556     cf2_setError( error, lastError );
   1557 
   1558     /* free resources from objects we've used */
   1559     cf2_glyphpath_finalize( &glyphPath );
   1560     cf2_arrstack_finalize( &vStemHintArray );
   1561     cf2_arrstack_finalize( &hStemHintArray );
   1562     cf2_arrstack_finalize( &subrStack );
   1563     cf2_stack_free( opStack );
   1564 
   1565     FT_TRACE4(( "\n" ));
   1566 
   1567     return;
   1568   }
   1569 
   1570 
   1571 /* END */
   1572