Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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