Home | History | Annotate | Download | only in truetype
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ttinterp.c                                                             */
      4 /*                                                                         */
      5 /*    TrueType bytecode interpreter (body).                                */
      6 /*                                                                         */
      7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
      8 /*            2010                                                         */
      9 /*  by David Turner, Robert Wilhelm, and Werner Lemberg.                   */
     10 /*                                                                         */
     11 /*  This file is part of the FreeType project, and may only be used,       */
     12 /*  modified, and distributed under the terms of the FreeType project      */
     13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     14 /*  this file you indicate that you have read the license and              */
     15 /*  understand and accept it fully.                                        */
     16 /*                                                                         */
     17 /***************************************************************************/
     18 
     19 
     20 #include <ft2build.h>
     21 #include FT_INTERNAL_DEBUG_H
     22 #include FT_INTERNAL_CALC_H
     23 #include FT_TRIGONOMETRY_H
     24 #include FT_SYSTEM_H
     25 
     26 #include "ttinterp.h"
     27 
     28 #include "tterrors.h"
     29 
     30 
     31 #ifdef TT_USE_BYTECODE_INTERPRETER
     32 
     33 
     34 #define TT_MULFIX           FT_MulFix
     35 #define TT_MULDIV           FT_MulDiv
     36 #define TT_MULDIV_NO_ROUND  FT_MulDiv_No_Round
     37 
     38 
     39   /*************************************************************************/
     40   /*                                                                       */
     41   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     42   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     43   /* messages during execution.                                            */
     44   /*                                                                       */
     45 #undef  FT_COMPONENT
     46 #define FT_COMPONENT  trace_ttinterp
     47 
     48   /*************************************************************************/
     49   /*                                                                       */
     50   /* In order to detect infinite loops in the code, we set up a counter    */
     51   /* within the run loop.  A single stroke of interpretation is now        */
     52   /* limited to a maximal number of opcodes defined below.                 */
     53   /*                                                                       */
     54 #define MAX_RUNNABLE_OPCODES  1000000L
     55 
     56 
     57   /*************************************************************************/
     58   /*                                                                       */
     59   /* There are two kinds of implementations:                               */
     60   /*                                                                       */
     61   /* a. static implementation                                              */
     62   /*                                                                       */
     63   /*    The current execution context is a static variable, which fields   */
     64   /*    are accessed directly by the interpreter during execution.  The    */
     65   /*    context is named `cur'.                                            */
     66   /*                                                                       */
     67   /*    This version is non-reentrant, of course.                          */
     68   /*                                                                       */
     69   /* b. indirect implementation                                            */
     70   /*                                                                       */
     71   /*    The current execution context is passed to _each_ function as its  */
     72   /*    first argument, and each field is thus accessed indirectly.        */
     73   /*                                                                       */
     74   /*    This version is fully re-entrant.                                  */
     75   /*                                                                       */
     76   /* The idea is that an indirect implementation may be slower to execute  */
     77   /* on low-end processors that are used in some systems (like 386s or     */
     78   /* even 486s).                                                           */
     79   /*                                                                       */
     80   /* As a consequence, the indirect implementation is now the default, as  */
     81   /* its performance costs can be considered negligible in our context.    */
     82   /* Note, however, that we kept the same source with macros because:      */
     83   /*                                                                       */
     84   /* - The code is kept very close in design to the Pascal code used for   */
     85   /*   development.                                                        */
     86   /*                                                                       */
     87   /* - It's much more readable that way!                                   */
     88   /*                                                                       */
     89   /* - It's still open to experimentation and tuning.                      */
     90   /*                                                                       */
     91   /*************************************************************************/
     92 
     93 
     94 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER     /* indirect implementation */
     95 
     96 #define CUR  (*exc)                             /* see ttobjs.h */
     97 
     98   /*************************************************************************/
     99   /*                                                                       */
    100   /* This macro is used whenever `exec' is unused in a function, to avoid  */
    101   /* stupid warnings from pedantic compilers.                              */
    102   /*                                                                       */
    103 #define FT_UNUSED_EXEC  FT_UNUSED( exc )
    104 
    105 #else                                           /* static implementation */
    106 
    107 #define CUR  cur
    108 
    109 #define FT_UNUSED_EXEC  int  __dummy = __dummy
    110 
    111   static
    112   TT_ExecContextRec  cur;   /* static exec. context variable */
    113 
    114   /* apparently, we have a _lot_ of direct indexing when accessing  */
    115   /* the static `cur', which makes the code bigger (due to all the  */
    116   /* four bytes addresses).                                         */
    117 
    118 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
    119 
    120 
    121   /*************************************************************************/
    122   /*                                                                       */
    123   /* The instruction argument stack.                                       */
    124   /*                                                                       */
    125 #define INS_ARG  EXEC_OP_ FT_Long*  args    /* see ttobjs.h for EXEC_OP_ */
    126 
    127 
    128   /*************************************************************************/
    129   /*                                                                       */
    130   /* This macro is used whenever `args' is unused in a function, to avoid  */
    131   /* stupid warnings from pedantic compilers.                              */
    132   /*                                                                       */
    133 #define FT_UNUSED_ARG  FT_UNUSED_EXEC; FT_UNUSED( args )
    134 
    135 
    136   /*************************************************************************/
    137   /*                                                                       */
    138   /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to        */
    139   /* increase readability of the code.                                     */
    140   /*                                                                       */
    141   /*************************************************************************/
    142 
    143 
    144 #define SKIP_Code() \
    145           SkipCode( EXEC_ARG )
    146 
    147 #define GET_ShortIns() \
    148           GetShortIns( EXEC_ARG )
    149 
    150 #define NORMalize( x, y, v ) \
    151           Normalize( EXEC_ARG_ x, y, v )
    152 
    153 #define SET_SuperRound( scale, flags ) \
    154           SetSuperRound( EXEC_ARG_ scale, flags )
    155 
    156 #define ROUND_None( d, c ) \
    157           Round_None( EXEC_ARG_ d, c )
    158 
    159 #define INS_Goto_CodeRange( range, ip ) \
    160           Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
    161 
    162 #define CUR_Func_move( z, p, d ) \
    163           CUR.func_move( EXEC_ARG_ z, p, d )
    164 
    165 #define CUR_Func_move_orig( z, p, d ) \
    166           CUR.func_move_orig( EXEC_ARG_ z, p, d )
    167 
    168 #define CUR_Func_round( d, c ) \
    169           CUR.func_round( EXEC_ARG_ d, c )
    170 
    171 #define CUR_Func_read_cvt( index ) \
    172           CUR.func_read_cvt( EXEC_ARG_ index )
    173 
    174 #define CUR_Func_write_cvt( index, val ) \
    175           CUR.func_write_cvt( EXEC_ARG_ index, val )
    176 
    177 #define CUR_Func_move_cvt( index, val ) \
    178           CUR.func_move_cvt( EXEC_ARG_ index, val )
    179 
    180 #define CURRENT_Ratio() \
    181           Current_Ratio( EXEC_ARG )
    182 
    183 #define CURRENT_Ppem() \
    184           Current_Ppem( EXEC_ARG )
    185 
    186 #define CUR_Ppem() \
    187           Cur_PPEM( EXEC_ARG )
    188 
    189 #define INS_SxVTL( a, b, c, d ) \
    190           Ins_SxVTL( EXEC_ARG_ a, b, c, d )
    191 
    192 #define COMPUTE_Funcs() \
    193           Compute_Funcs( EXEC_ARG )
    194 
    195 #define COMPUTE_Round( a ) \
    196           Compute_Round( EXEC_ARG_ a )
    197 
    198 #define COMPUTE_Point_Displacement( a, b, c, d ) \
    199           Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
    200 
    201 #define MOVE_Zp2_Point( a, b, c, t ) \
    202           Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
    203 
    204 
    205 #define CUR_Func_project( v1, v2 )  \
    206           CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
    207 
    208 #define CUR_Func_dualproj( v1, v2 )  \
    209           CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
    210 
    211 #define CUR_fast_project( v ) \
    212           CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
    213 
    214 #define CUR_fast_dualproj( v ) \
    215           CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
    216 
    217 
    218   /*************************************************************************/
    219   /*                                                                       */
    220   /* Instruction dispatch function, as used by the interpreter.            */
    221   /*                                                                       */
    222   typedef void  (*TInstruction_Function)( INS_ARG );
    223 
    224 
    225   /*************************************************************************/
    226   /*                                                                       */
    227   /* Two simple bounds-checking macros.                                    */
    228   /*                                                                       */
    229 #define BOUNDS( x, n )   ( (FT_UInt)(x)  >= (FT_UInt)(n)  )
    230 #define BOUNDSL( x, n )  ( (FT_ULong)(x) >= (FT_ULong)(n) )
    231 
    232 #undef  SUCCESS
    233 #define SUCCESS  0
    234 
    235 #undef  FAILURE
    236 #define FAILURE  1
    237 
    238 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    239 #define GUESS_VECTOR( V )                                         \
    240   if ( CUR.face->unpatented_hinting )                             \
    241   {                                                               \
    242     CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
    243     CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
    244   }
    245 #else
    246 #define GUESS_VECTOR( V )
    247 #endif
    248 
    249   /*************************************************************************/
    250   /*                                                                       */
    251   /*                        CODERANGE FUNCTIONS                            */
    252   /*                                                                       */
    253   /*************************************************************************/
    254 
    255 
    256   /*************************************************************************/
    257   /*                                                                       */
    258   /* <Function>                                                            */
    259   /*    TT_Goto_CodeRange                                                  */
    260   /*                                                                       */
    261   /* <Description>                                                         */
    262   /*    Switches to a new code range (updates the code related elements in */
    263   /*    `exec', and `IP').                                                 */
    264   /*                                                                       */
    265   /* <Input>                                                               */
    266   /*    range :: The new execution code range.                             */
    267   /*                                                                       */
    268   /*    IP    :: The new IP in the new code range.                         */
    269   /*                                                                       */
    270   /* <InOut>                                                               */
    271   /*    exec  :: The target execution context.                             */
    272   /*                                                                       */
    273   /* <Return>                                                              */
    274   /*    FreeType error code.  0 means success.                             */
    275   /*                                                                       */
    276   FT_LOCAL_DEF( FT_Error )
    277   TT_Goto_CodeRange( TT_ExecContext  exec,
    278                      FT_Int          range,
    279                      FT_Long         IP )
    280   {
    281     TT_CodeRange*  coderange;
    282 
    283 
    284     FT_ASSERT( range >= 1 && range <= 3 );
    285 
    286     coderange = &exec->codeRangeTable[range - 1];
    287 
    288     FT_ASSERT( coderange->base != NULL );
    289 
    290     /* NOTE: Because the last instruction of a program may be a CALL */
    291     /*       which will return to the first byte *after* the code    */
    292     /*       range, we test for IP <= Size instead of IP < Size.     */
    293     /*                                                               */
    294     FT_ASSERT( (FT_ULong)IP <= coderange->size );
    295 
    296     exec->code     = coderange->base;
    297     exec->codeSize = coderange->size;
    298     exec->IP       = IP;
    299     exec->curRange = range;
    300 
    301     return TT_Err_Ok;
    302   }
    303 
    304 
    305   /*************************************************************************/
    306   /*                                                                       */
    307   /* <Function>                                                            */
    308   /*    TT_Set_CodeRange                                                   */
    309   /*                                                                       */
    310   /* <Description>                                                         */
    311   /*    Sets a code range.                                                 */
    312   /*                                                                       */
    313   /* <Input>                                                               */
    314   /*    range  :: The code range index.                                    */
    315   /*                                                                       */
    316   /*    base   :: The new code base.                                       */
    317   /*                                                                       */
    318   /*    length :: The range size in bytes.                                 */
    319   /*                                                                       */
    320   /* <InOut>                                                               */
    321   /*    exec   :: The target execution context.                            */
    322   /*                                                                       */
    323   /* <Return>                                                              */
    324   /*    FreeType error code.  0 means success.                             */
    325   /*                                                                       */
    326   FT_LOCAL_DEF( FT_Error )
    327   TT_Set_CodeRange( TT_ExecContext  exec,
    328                     FT_Int          range,
    329                     void*           base,
    330                     FT_Long         length )
    331   {
    332     FT_ASSERT( range >= 1 && range <= 3 );
    333 
    334     exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
    335     exec->codeRangeTable[range - 1].size = length;
    336 
    337     return TT_Err_Ok;
    338   }
    339 
    340 
    341   /*************************************************************************/
    342   /*                                                                       */
    343   /* <Function>                                                            */
    344   /*    TT_Clear_CodeRange                                                 */
    345   /*                                                                       */
    346   /* <Description>                                                         */
    347   /*    Clears a code range.                                               */
    348   /*                                                                       */
    349   /* <Input>                                                               */
    350   /*    range :: The code range index.                                     */
    351   /*                                                                       */
    352   /* <InOut>                                                               */
    353   /*    exec  :: The target execution context.                             */
    354   /*                                                                       */
    355   /* <Return>                                                              */
    356   /*    FreeType error code.  0 means success.                             */
    357   /*                                                                       */
    358   /* <Note>                                                                */
    359   /*    Does not set the Error variable.                                   */
    360   /*                                                                       */
    361   FT_LOCAL_DEF( FT_Error )
    362   TT_Clear_CodeRange( TT_ExecContext  exec,
    363                       FT_Int          range )
    364   {
    365     FT_ASSERT( range >= 1 && range <= 3 );
    366 
    367     exec->codeRangeTable[range - 1].base = NULL;
    368     exec->codeRangeTable[range - 1].size = 0;
    369 
    370     return TT_Err_Ok;
    371   }
    372 
    373 
    374   /*************************************************************************/
    375   /*                                                                       */
    376   /*                   EXECUTION CONTEXT ROUTINES                          */
    377   /*                                                                       */
    378   /*************************************************************************/
    379 
    380 
    381   /*************************************************************************/
    382   /*                                                                       */
    383   /* <Function>                                                            */
    384   /*    TT_Done_Context                                                    */
    385   /*                                                                       */
    386   /* <Description>                                                         */
    387   /*    Destroys a given context.                                          */
    388   /*                                                                       */
    389   /* <Input>                                                               */
    390   /*    exec   :: A handle to the target execution context.                */
    391   /*                                                                       */
    392   /*    memory :: A handle to the parent memory object.                    */
    393   /*                                                                       */
    394   /* <Return>                                                              */
    395   /*    FreeType error code.  0 means success.                             */
    396   /*                                                                       */
    397   /* <Note>                                                                */
    398   /*    Only the glyph loader and debugger should call this function.      */
    399   /*                                                                       */
    400   FT_LOCAL_DEF( FT_Error )
    401   TT_Done_Context( TT_ExecContext  exec )
    402   {
    403     FT_Memory  memory = exec->memory;
    404 
    405 
    406     /* points zone */
    407     exec->maxPoints   = 0;
    408     exec->maxContours = 0;
    409 
    410     /* free stack */
    411     FT_FREE( exec->stack );
    412     exec->stackSize = 0;
    413 
    414     /* free call stack */
    415     FT_FREE( exec->callStack );
    416     exec->callSize = 0;
    417     exec->callTop  = 0;
    418 
    419     /* free glyph code range */
    420     FT_FREE( exec->glyphIns );
    421     exec->glyphSize = 0;
    422 
    423     exec->size = NULL;
    424     exec->face = NULL;
    425 
    426     FT_FREE( exec );
    427 
    428     return TT_Err_Ok;
    429   }
    430 
    431 
    432   /*************************************************************************/
    433   /*                                                                       */
    434   /* <Function>                                                            */
    435   /*    Init_Context                                                       */
    436   /*                                                                       */
    437   /* <Description>                                                         */
    438   /*    Initializes a context object.                                      */
    439   /*                                                                       */
    440   /* <Input>                                                               */
    441   /*    memory :: A handle to the parent memory object.                    */
    442   /*                                                                       */
    443   /* <InOut>                                                               */
    444   /*    exec   :: A handle to the target execution context.                */
    445   /*                                                                       */
    446   /* <Return>                                                              */
    447   /*    FreeType error code.  0 means success.                             */
    448   /*                                                                       */
    449   static FT_Error
    450   Init_Context( TT_ExecContext  exec,
    451                 FT_Memory       memory )
    452   {
    453     FT_Error  error;
    454 
    455 
    456     FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
    457 
    458     exec->memory   = memory;
    459     exec->callSize = 32;
    460 
    461     if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
    462       goto Fail_Memory;
    463 
    464     /* all values in the context are set to 0 already, but this is */
    465     /* here as a remainder                                         */
    466     exec->maxPoints   = 0;
    467     exec->maxContours = 0;
    468 
    469     exec->stackSize = 0;
    470     exec->glyphSize = 0;
    471 
    472     exec->stack     = NULL;
    473     exec->glyphIns  = NULL;
    474 
    475     exec->face = NULL;
    476     exec->size = NULL;
    477 
    478     return TT_Err_Ok;
    479 
    480   Fail_Memory:
    481     FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
    482                (FT_Long)exec ));
    483     TT_Done_Context( exec );
    484 
    485     return error;
    486  }
    487 
    488 
    489   /*************************************************************************/
    490   /*                                                                       */
    491   /* <Function>                                                            */
    492   /*    Update_Max                                                         */
    493   /*                                                                       */
    494   /* <Description>                                                         */
    495   /*    Checks the size of a buffer and reallocates it if necessary.       */
    496   /*                                                                       */
    497   /* <Input>                                                               */
    498   /*    memory     :: A handle to the parent memory object.                */
    499   /*                                                                       */
    500   /*    multiplier :: The size in bytes of each element in the buffer.     */
    501   /*                                                                       */
    502   /*    new_max    :: The new capacity (size) of the buffer.               */
    503   /*                                                                       */
    504   /* <InOut>                                                               */
    505   /*    size       :: The address of the buffer's current size expressed   */
    506   /*                  in elements.                                         */
    507   /*                                                                       */
    508   /*    buff       :: The address of the buffer base pointer.              */
    509   /*                                                                       */
    510   /* <Return>                                                              */
    511   /*    FreeType error code.  0 means success.                             */
    512   /*                                                                       */
    513   FT_LOCAL_DEF( FT_Error )
    514   Update_Max( FT_Memory  memory,
    515               FT_ULong*  size,
    516               FT_Long    multiplier,
    517               void*      _pbuff,
    518               FT_ULong   new_max )
    519   {
    520     FT_Error  error;
    521     void**    pbuff = (void**)_pbuff;
    522 
    523 
    524     if ( *size < new_max )
    525     {
    526       if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
    527         return error;
    528       *size = new_max;
    529     }
    530 
    531     return TT_Err_Ok;
    532   }
    533 
    534 
    535   /*************************************************************************/
    536   /*                                                                       */
    537   /* <Function>                                                            */
    538   /*    TT_Load_Context                                                    */
    539   /*                                                                       */
    540   /* <Description>                                                         */
    541   /*    Prepare an execution context for glyph hinting.                    */
    542   /*                                                                       */
    543   /* <Input>                                                               */
    544   /*    face :: A handle to the source face object.                        */
    545   /*                                                                       */
    546   /*    size :: A handle to the source size object.                        */
    547   /*                                                                       */
    548   /* <InOut>                                                               */
    549   /*    exec :: A handle to the target execution context.                  */
    550   /*                                                                       */
    551   /* <Return>                                                              */
    552   /*    FreeType error code.  0 means success.                             */
    553   /*                                                                       */
    554   /* <Note>                                                                */
    555   /*    Only the glyph loader and debugger should call this function.      */
    556   /*                                                                       */
    557   FT_LOCAL_DEF( FT_Error )
    558   TT_Load_Context( TT_ExecContext  exec,
    559                    TT_Face         face,
    560                    TT_Size         size )
    561   {
    562     FT_Int          i;
    563     FT_ULong        tmp;
    564     TT_MaxProfile*  maxp;
    565     FT_Error        error;
    566 
    567 
    568     exec->face = face;
    569     maxp       = &face->max_profile;
    570     exec->size = size;
    571 
    572     if ( size )
    573     {
    574       exec->numFDefs   = size->num_function_defs;
    575       exec->maxFDefs   = size->max_function_defs;
    576       exec->numIDefs   = size->num_instruction_defs;
    577       exec->maxIDefs   = size->max_instruction_defs;
    578       exec->FDefs      = size->function_defs;
    579       exec->IDefs      = size->instruction_defs;
    580       exec->tt_metrics = size->ttmetrics;
    581       exec->metrics    = size->metrics;
    582 
    583       exec->maxFunc    = size->max_func;
    584       exec->maxIns     = size->max_ins;
    585 
    586       for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
    587         exec->codeRangeTable[i] = size->codeRangeTable[i];
    588 
    589       /* set graphics state */
    590       exec->GS = size->GS;
    591 
    592       exec->cvtSize = size->cvt_size;
    593       exec->cvt     = size->cvt;
    594 
    595       exec->storeSize = size->storage_size;
    596       exec->storage   = size->storage;
    597 
    598       exec->twilight  = size->twilight;
    599     }
    600 
    601     /* XXX: We reserve a little more elements on the stack to deal safely */
    602     /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
    603     tmp = exec->stackSize;
    604     error = Update_Max( exec->memory,
    605                         &tmp,
    606                         sizeof ( FT_F26Dot6 ),
    607                         (void*)&exec->stack,
    608                         maxp->maxStackElements + 32 );
    609     exec->stackSize = (FT_UInt)tmp;
    610     if ( error )
    611       return error;
    612 
    613     tmp = exec->glyphSize;
    614     error = Update_Max( exec->memory,
    615                         &tmp,
    616                         sizeof ( FT_Byte ),
    617                         (void*)&exec->glyphIns,
    618                         maxp->maxSizeOfInstructions );
    619     exec->glyphSize = (FT_UShort)tmp;
    620     if ( error )
    621       return error;
    622 
    623     exec->pts.n_points   = 0;
    624     exec->pts.n_contours = 0;
    625 
    626     exec->zp1 = exec->pts;
    627     exec->zp2 = exec->pts;
    628     exec->zp0 = exec->pts;
    629 
    630     exec->instruction_trap = FALSE;
    631 
    632     return TT_Err_Ok;
    633   }
    634 
    635 
    636   /*************************************************************************/
    637   /*                                                                       */
    638   /* <Function>                                                            */
    639   /*    TT_Save_Context                                                    */
    640   /*                                                                       */
    641   /* <Description>                                                         */
    642   /*    Saves the code ranges in a `size' object.                          */
    643   /*                                                                       */
    644   /* <Input>                                                               */
    645   /*    exec :: A handle to the source execution context.                  */
    646   /*                                                                       */
    647   /* <InOut>                                                               */
    648   /*    size :: A handle to the target size object.                        */
    649   /*                                                                       */
    650   /* <Return>                                                              */
    651   /*    FreeType error code.  0 means success.                             */
    652   /*                                                                       */
    653   /* <Note>                                                                */
    654   /*    Only the glyph loader and debugger should call this function.      */
    655   /*                                                                       */
    656   FT_LOCAL_DEF( FT_Error )
    657   TT_Save_Context( TT_ExecContext  exec,
    658                    TT_Size         size )
    659   {
    660     FT_Int  i;
    661 
    662 
    663     /* XXXX: Will probably disappear soon with all the code range */
    664     /*       management, which is now rather obsolete.            */
    665     /*                                                            */
    666     size->num_function_defs    = exec->numFDefs;
    667     size->num_instruction_defs = exec->numIDefs;
    668 
    669     size->max_func = exec->maxFunc;
    670     size->max_ins  = exec->maxIns;
    671 
    672     for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
    673       size->codeRangeTable[i] = exec->codeRangeTable[i];
    674 
    675     return TT_Err_Ok;
    676   }
    677 
    678 
    679   /*************************************************************************/
    680   /*                                                                       */
    681   /* <Function>                                                            */
    682   /*    TT_Run_Context                                                     */
    683   /*                                                                       */
    684   /* <Description>                                                         */
    685   /*    Executes one or more instructions in the execution context.        */
    686   /*                                                                       */
    687   /* <Input>                                                               */
    688   /*    debug :: A Boolean flag.  If set, the function sets some internal  */
    689   /*             variables and returns immediately, otherwise TT_RunIns()  */
    690   /*             is called.                                                */
    691   /*                                                                       */
    692   /*             This is commented out currently.                          */
    693   /*                                                                       */
    694   /* <Input>                                                               */
    695   /*    exec  :: A handle to the target execution context.                 */
    696   /*                                                                       */
    697   /* <Return>                                                              */
    698   /*    TrueType error code.  0 means success.                             */
    699   /*                                                                       */
    700   /* <Note>                                                                */
    701   /*    Only the glyph loader and debugger should call this function.      */
    702   /*                                                                       */
    703   FT_LOCAL_DEF( FT_Error )
    704   TT_Run_Context( TT_ExecContext  exec,
    705                   FT_Bool         debug )
    706   {
    707     FT_Error  error;
    708 
    709 
    710     if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0  ) )
    711            != TT_Err_Ok )
    712       return error;
    713 
    714     exec->zp0 = exec->pts;
    715     exec->zp1 = exec->pts;
    716     exec->zp2 = exec->pts;
    717 
    718     exec->GS.gep0 = 1;
    719     exec->GS.gep1 = 1;
    720     exec->GS.gep2 = 1;
    721 
    722     exec->GS.projVector.x = 0x4000;
    723     exec->GS.projVector.y = 0x0000;
    724 
    725     exec->GS.freeVector = exec->GS.projVector;
    726     exec->GS.dualVector = exec->GS.projVector;
    727 
    728 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    729     exec->GS.both_x_axis = TRUE;
    730 #endif
    731 
    732     exec->GS.round_state = 1;
    733     exec->GS.loop        = 1;
    734 
    735     /* some glyphs leave something on the stack. so we clean it */
    736     /* before a new execution.                                  */
    737     exec->top     = 0;
    738     exec->callTop = 0;
    739 
    740 #if 1
    741     FT_UNUSED( debug );
    742 
    743     return exec->face->interpreter( exec );
    744 #else
    745     if ( !debug )
    746       return TT_RunIns( exec );
    747     else
    748       return TT_Err_Ok;
    749 #endif
    750   }
    751 
    752 
    753   /* The default value for `scan_control' is documented as FALSE in the */
    754   /* TrueType specification.  This is confusing since it implies a      */
    755   /* Boolean value.  However, this is not the case, thus both the       */
    756   /* default values of our `scan_type' and `scan_control' fields (which */
    757   /* the documentation's `scan_control' variable is split into) are     */
    758   /* zero.                                                              */
    759 
    760   const TT_GraphicsState  tt_default_graphics_state =
    761   {
    762     0, 0, 0,
    763     { 0x4000, 0 },
    764     { 0x4000, 0 },
    765     { 0x4000, 0 },
    766 
    767 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    768     TRUE,
    769 #endif
    770 
    771     1, 64, 1,
    772     TRUE, 68, 0, 0, 9, 3,
    773     0, FALSE, 0, 1, 1, 1
    774   };
    775 
    776 
    777   /* documentation is in ttinterp.h */
    778 
    779   FT_EXPORT_DEF( TT_ExecContext )
    780   TT_New_Context( TT_Driver  driver )
    781   {
    782     TT_ExecContext  exec;
    783     FT_Memory       memory;
    784 
    785 
    786     memory = driver->root.root.memory;
    787     exec   = driver->context;
    788 
    789     if ( !driver->context )
    790     {
    791       FT_Error  error;
    792 
    793 
    794       /* allocate object */
    795       if ( FT_NEW( exec ) )
    796         goto Fail;
    797 
    798       /* initialize it; in case of error this deallocates `exec' too */
    799       error = Init_Context( exec, memory );
    800       if ( error )
    801         goto Fail;
    802 
    803       /* store it into the driver */
    804       driver->context = exec;
    805     }
    806 
    807     return driver->context;
    808 
    809   Fail:
    810     return NULL;
    811   }
    812 
    813 
    814   /*************************************************************************/
    815   /*                                                                       */
    816   /* Before an opcode is executed, the interpreter verifies that there are */
    817   /* enough arguments on the stack, with the help of the `Pop_Push_Count'  */
    818   /* table.                                                                */
    819   /*                                                                       */
    820   /* For each opcode, the first column gives the number of arguments that  */
    821   /* are popped from the stack; the second one gives the number of those   */
    822   /* that are pushed in result.                                            */
    823   /*                                                                       */
    824   /* Opcodes which have a varying number of parameters in the data stream  */
    825   /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
    826   /* the `opcode_length' table, and the value in `Pop_Push_Count' is set   */
    827   /* to zero.                                                              */
    828   /*                                                                       */
    829   /*************************************************************************/
    830 
    831 
    832 #undef  PACK
    833 #define PACK( x, y )  ( ( x << 4 ) | y )
    834 
    835 
    836   static
    837   const FT_Byte  Pop_Push_Count[256] =
    838   {
    839     /* opcodes are gathered in groups of 16 */
    840     /* please keep the spaces as they are   */
    841 
    842     /*  SVTCA  y  */  PACK( 0, 0 ),
    843     /*  SVTCA  x  */  PACK( 0, 0 ),
    844     /*  SPvTCA y  */  PACK( 0, 0 ),
    845     /*  SPvTCA x  */  PACK( 0, 0 ),
    846     /*  SFvTCA y  */  PACK( 0, 0 ),
    847     /*  SFvTCA x  */  PACK( 0, 0 ),
    848     /*  SPvTL //  */  PACK( 2, 0 ),
    849     /*  SPvTL +   */  PACK( 2, 0 ),
    850     /*  SFvTL //  */  PACK( 2, 0 ),
    851     /*  SFvTL +   */  PACK( 2, 0 ),
    852     /*  SPvFS     */  PACK( 2, 0 ),
    853     /*  SFvFS     */  PACK( 2, 0 ),
    854     /*  GPV       */  PACK( 0, 2 ),
    855     /*  GFV       */  PACK( 0, 2 ),
    856     /*  SFvTPv    */  PACK( 0, 0 ),
    857     /*  ISECT     */  PACK( 5, 0 ),
    858 
    859     /*  SRP0      */  PACK( 1, 0 ),
    860     /*  SRP1      */  PACK( 1, 0 ),
    861     /*  SRP2      */  PACK( 1, 0 ),
    862     /*  SZP0      */  PACK( 1, 0 ),
    863     /*  SZP1      */  PACK( 1, 0 ),
    864     /*  SZP2      */  PACK( 1, 0 ),
    865     /*  SZPS      */  PACK( 1, 0 ),
    866     /*  SLOOP     */  PACK( 1, 0 ),
    867     /*  RTG       */  PACK( 0, 0 ),
    868     /*  RTHG      */  PACK( 0, 0 ),
    869     /*  SMD       */  PACK( 1, 0 ),
    870     /*  ELSE      */  PACK( 0, 0 ),
    871     /*  JMPR      */  PACK( 1, 0 ),
    872     /*  SCvTCi    */  PACK( 1, 0 ),
    873     /*  SSwCi     */  PACK( 1, 0 ),
    874     /*  SSW       */  PACK( 1, 0 ),
    875 
    876     /*  DUP       */  PACK( 1, 2 ),
    877     /*  POP       */  PACK( 1, 0 ),
    878     /*  CLEAR     */  PACK( 0, 0 ),
    879     /*  SWAP      */  PACK( 2, 2 ),
    880     /*  DEPTH     */  PACK( 0, 1 ),
    881     /*  CINDEX    */  PACK( 1, 1 ),
    882     /*  MINDEX    */  PACK( 1, 0 ),
    883     /*  AlignPTS  */  PACK( 2, 0 ),
    884     /*  INS_$28   */  PACK( 0, 0 ),
    885     /*  UTP       */  PACK( 1, 0 ),
    886     /*  LOOPCALL  */  PACK( 2, 0 ),
    887     /*  CALL      */  PACK( 1, 0 ),
    888     /*  FDEF      */  PACK( 1, 0 ),
    889     /*  ENDF      */  PACK( 0, 0 ),
    890     /*  MDAP[0]   */  PACK( 1, 0 ),
    891     /*  MDAP[1]   */  PACK( 1, 0 ),
    892 
    893     /*  IUP[0]    */  PACK( 0, 0 ),
    894     /*  IUP[1]    */  PACK( 0, 0 ),
    895     /*  SHP[0]    */  PACK( 0, 0 ),
    896     /*  SHP[1]    */  PACK( 0, 0 ),
    897     /*  SHC[0]    */  PACK( 1, 0 ),
    898     /*  SHC[1]    */  PACK( 1, 0 ),
    899     /*  SHZ[0]    */  PACK( 1, 0 ),
    900     /*  SHZ[1]    */  PACK( 1, 0 ),
    901     /*  SHPIX     */  PACK( 1, 0 ),
    902     /*  IP        */  PACK( 0, 0 ),
    903     /*  MSIRP[0]  */  PACK( 2, 0 ),
    904     /*  MSIRP[1]  */  PACK( 2, 0 ),
    905     /*  AlignRP   */  PACK( 0, 0 ),
    906     /*  RTDG      */  PACK( 0, 0 ),
    907     /*  MIAP[0]   */  PACK( 2, 0 ),
    908     /*  MIAP[1]   */  PACK( 2, 0 ),
    909 
    910     /*  NPushB    */  PACK( 0, 0 ),
    911     /*  NPushW    */  PACK( 0, 0 ),
    912     /*  WS        */  PACK( 2, 0 ),
    913     /*  RS        */  PACK( 1, 1 ),
    914     /*  WCvtP     */  PACK( 2, 0 ),
    915     /*  RCvt      */  PACK( 1, 1 ),
    916     /*  GC[0]     */  PACK( 1, 1 ),
    917     /*  GC[1]     */  PACK( 1, 1 ),
    918     /*  SCFS      */  PACK( 2, 0 ),
    919     /*  MD[0]     */  PACK( 2, 1 ),
    920     /*  MD[1]     */  PACK( 2, 1 ),
    921     /*  MPPEM     */  PACK( 0, 1 ),
    922     /*  MPS       */  PACK( 0, 1 ),
    923     /*  FlipON    */  PACK( 0, 0 ),
    924     /*  FlipOFF   */  PACK( 0, 0 ),
    925     /*  DEBUG     */  PACK( 1, 0 ),
    926 
    927     /*  LT        */  PACK( 2, 1 ),
    928     /*  LTEQ      */  PACK( 2, 1 ),
    929     /*  GT        */  PACK( 2, 1 ),
    930     /*  GTEQ      */  PACK( 2, 1 ),
    931     /*  EQ        */  PACK( 2, 1 ),
    932     /*  NEQ       */  PACK( 2, 1 ),
    933     /*  ODD       */  PACK( 1, 1 ),
    934     /*  EVEN      */  PACK( 1, 1 ),
    935     /*  IF        */  PACK( 1, 0 ),
    936     /*  EIF       */  PACK( 0, 0 ),
    937     /*  AND       */  PACK( 2, 1 ),
    938     /*  OR        */  PACK( 2, 1 ),
    939     /*  NOT       */  PACK( 1, 1 ),
    940     /*  DeltaP1   */  PACK( 1, 0 ),
    941     /*  SDB       */  PACK( 1, 0 ),
    942     /*  SDS       */  PACK( 1, 0 ),
    943 
    944     /*  ADD       */  PACK( 2, 1 ),
    945     /*  SUB       */  PACK( 2, 1 ),
    946     /*  DIV       */  PACK( 2, 1 ),
    947     /*  MUL       */  PACK( 2, 1 ),
    948     /*  ABS       */  PACK( 1, 1 ),
    949     /*  NEG       */  PACK( 1, 1 ),
    950     /*  FLOOR     */  PACK( 1, 1 ),
    951     /*  CEILING   */  PACK( 1, 1 ),
    952     /*  ROUND[0]  */  PACK( 1, 1 ),
    953     /*  ROUND[1]  */  PACK( 1, 1 ),
    954     /*  ROUND[2]  */  PACK( 1, 1 ),
    955     /*  ROUND[3]  */  PACK( 1, 1 ),
    956     /*  NROUND[0] */  PACK( 1, 1 ),
    957     /*  NROUND[1] */  PACK( 1, 1 ),
    958     /*  NROUND[2] */  PACK( 1, 1 ),
    959     /*  NROUND[3] */  PACK( 1, 1 ),
    960 
    961     /*  WCvtF     */  PACK( 2, 0 ),
    962     /*  DeltaP2   */  PACK( 1, 0 ),
    963     /*  DeltaP3   */  PACK( 1, 0 ),
    964     /*  DeltaCn[0] */ PACK( 1, 0 ),
    965     /*  DeltaCn[1] */ PACK( 1, 0 ),
    966     /*  DeltaCn[2] */ PACK( 1, 0 ),
    967     /*  SROUND    */  PACK( 1, 0 ),
    968     /*  S45Round  */  PACK( 1, 0 ),
    969     /*  JROT      */  PACK( 2, 0 ),
    970     /*  JROF      */  PACK( 2, 0 ),
    971     /*  ROFF      */  PACK( 0, 0 ),
    972     /*  INS_$7B   */  PACK( 0, 0 ),
    973     /*  RUTG      */  PACK( 0, 0 ),
    974     /*  RDTG      */  PACK( 0, 0 ),
    975     /*  SANGW     */  PACK( 1, 0 ),
    976     /*  AA        */  PACK( 1, 0 ),
    977 
    978     /*  FlipPT    */  PACK( 0, 0 ),
    979     /*  FlipRgON  */  PACK( 2, 0 ),
    980     /*  FlipRgOFF */  PACK( 2, 0 ),
    981     /*  INS_$83   */  PACK( 0, 0 ),
    982     /*  INS_$84   */  PACK( 0, 0 ),
    983     /*  ScanCTRL  */  PACK( 1, 0 ),
    984     /*  SDVPTL[0] */  PACK( 2, 0 ),
    985     /*  SDVPTL[1] */  PACK( 2, 0 ),
    986     /*  GetINFO   */  PACK( 1, 1 ),
    987     /*  IDEF      */  PACK( 1, 0 ),
    988     /*  ROLL      */  PACK( 3, 3 ),
    989     /*  MAX       */  PACK( 2, 1 ),
    990     /*  MIN       */  PACK( 2, 1 ),
    991     /*  ScanTYPE  */  PACK( 1, 0 ),
    992     /*  InstCTRL  */  PACK( 2, 0 ),
    993     /*  INS_$8F   */  PACK( 0, 0 ),
    994 
    995     /*  INS_$90  */   PACK( 0, 0 ),
    996     /*  INS_$91  */   PACK( 0, 0 ),
    997     /*  INS_$92  */   PACK( 0, 0 ),
    998     /*  INS_$93  */   PACK( 0, 0 ),
    999     /*  INS_$94  */   PACK( 0, 0 ),
   1000     /*  INS_$95  */   PACK( 0, 0 ),
   1001     /*  INS_$96  */   PACK( 0, 0 ),
   1002     /*  INS_$97  */   PACK( 0, 0 ),
   1003     /*  INS_$98  */   PACK( 0, 0 ),
   1004     /*  INS_$99  */   PACK( 0, 0 ),
   1005     /*  INS_$9A  */   PACK( 0, 0 ),
   1006     /*  INS_$9B  */   PACK( 0, 0 ),
   1007     /*  INS_$9C  */   PACK( 0, 0 ),
   1008     /*  INS_$9D  */   PACK( 0, 0 ),
   1009     /*  INS_$9E  */   PACK( 0, 0 ),
   1010     /*  INS_$9F  */   PACK( 0, 0 ),
   1011 
   1012     /*  INS_$A0  */   PACK( 0, 0 ),
   1013     /*  INS_$A1  */   PACK( 0, 0 ),
   1014     /*  INS_$A2  */   PACK( 0, 0 ),
   1015     /*  INS_$A3  */   PACK( 0, 0 ),
   1016     /*  INS_$A4  */   PACK( 0, 0 ),
   1017     /*  INS_$A5  */   PACK( 0, 0 ),
   1018     /*  INS_$A6  */   PACK( 0, 0 ),
   1019     /*  INS_$A7  */   PACK( 0, 0 ),
   1020     /*  INS_$A8  */   PACK( 0, 0 ),
   1021     /*  INS_$A9  */   PACK( 0, 0 ),
   1022     /*  INS_$AA  */   PACK( 0, 0 ),
   1023     /*  INS_$AB  */   PACK( 0, 0 ),
   1024     /*  INS_$AC  */   PACK( 0, 0 ),
   1025     /*  INS_$AD  */   PACK( 0, 0 ),
   1026     /*  INS_$AE  */   PACK( 0, 0 ),
   1027     /*  INS_$AF  */   PACK( 0, 0 ),
   1028 
   1029     /*  PushB[0]  */  PACK( 0, 1 ),
   1030     /*  PushB[1]  */  PACK( 0, 2 ),
   1031     /*  PushB[2]  */  PACK( 0, 3 ),
   1032     /*  PushB[3]  */  PACK( 0, 4 ),
   1033     /*  PushB[4]  */  PACK( 0, 5 ),
   1034     /*  PushB[5]  */  PACK( 0, 6 ),
   1035     /*  PushB[6]  */  PACK( 0, 7 ),
   1036     /*  PushB[7]  */  PACK( 0, 8 ),
   1037     /*  PushW[0]  */  PACK( 0, 1 ),
   1038     /*  PushW[1]  */  PACK( 0, 2 ),
   1039     /*  PushW[2]  */  PACK( 0, 3 ),
   1040     /*  PushW[3]  */  PACK( 0, 4 ),
   1041     /*  PushW[4]  */  PACK( 0, 5 ),
   1042     /*  PushW[5]  */  PACK( 0, 6 ),
   1043     /*  PushW[6]  */  PACK( 0, 7 ),
   1044     /*  PushW[7]  */  PACK( 0, 8 ),
   1045 
   1046     /*  MDRP[00]  */  PACK( 1, 0 ),
   1047     /*  MDRP[01]  */  PACK( 1, 0 ),
   1048     /*  MDRP[02]  */  PACK( 1, 0 ),
   1049     /*  MDRP[03]  */  PACK( 1, 0 ),
   1050     /*  MDRP[04]  */  PACK( 1, 0 ),
   1051     /*  MDRP[05]  */  PACK( 1, 0 ),
   1052     /*  MDRP[06]  */  PACK( 1, 0 ),
   1053     /*  MDRP[07]  */  PACK( 1, 0 ),
   1054     /*  MDRP[08]  */  PACK( 1, 0 ),
   1055     /*  MDRP[09]  */  PACK( 1, 0 ),
   1056     /*  MDRP[10]  */  PACK( 1, 0 ),
   1057     /*  MDRP[11]  */  PACK( 1, 0 ),
   1058     /*  MDRP[12]  */  PACK( 1, 0 ),
   1059     /*  MDRP[13]  */  PACK( 1, 0 ),
   1060     /*  MDRP[14]  */  PACK( 1, 0 ),
   1061     /*  MDRP[15]  */  PACK( 1, 0 ),
   1062 
   1063     /*  MDRP[16]  */  PACK( 1, 0 ),
   1064     /*  MDRP[17]  */  PACK( 1, 0 ),
   1065     /*  MDRP[18]  */  PACK( 1, 0 ),
   1066     /*  MDRP[19]  */  PACK( 1, 0 ),
   1067     /*  MDRP[20]  */  PACK( 1, 0 ),
   1068     /*  MDRP[21]  */  PACK( 1, 0 ),
   1069     /*  MDRP[22]  */  PACK( 1, 0 ),
   1070     /*  MDRP[23]  */  PACK( 1, 0 ),
   1071     /*  MDRP[24]  */  PACK( 1, 0 ),
   1072     /*  MDRP[25]  */  PACK( 1, 0 ),
   1073     /*  MDRP[26]  */  PACK( 1, 0 ),
   1074     /*  MDRP[27]  */  PACK( 1, 0 ),
   1075     /*  MDRP[28]  */  PACK( 1, 0 ),
   1076     /*  MDRP[29]  */  PACK( 1, 0 ),
   1077     /*  MDRP[30]  */  PACK( 1, 0 ),
   1078     /*  MDRP[31]  */  PACK( 1, 0 ),
   1079 
   1080     /*  MIRP[00]  */  PACK( 2, 0 ),
   1081     /*  MIRP[01]  */  PACK( 2, 0 ),
   1082     /*  MIRP[02]  */  PACK( 2, 0 ),
   1083     /*  MIRP[03]  */  PACK( 2, 0 ),
   1084     /*  MIRP[04]  */  PACK( 2, 0 ),
   1085     /*  MIRP[05]  */  PACK( 2, 0 ),
   1086     /*  MIRP[06]  */  PACK( 2, 0 ),
   1087     /*  MIRP[07]  */  PACK( 2, 0 ),
   1088     /*  MIRP[08]  */  PACK( 2, 0 ),
   1089     /*  MIRP[09]  */  PACK( 2, 0 ),
   1090     /*  MIRP[10]  */  PACK( 2, 0 ),
   1091     /*  MIRP[11]  */  PACK( 2, 0 ),
   1092     /*  MIRP[12]  */  PACK( 2, 0 ),
   1093     /*  MIRP[13]  */  PACK( 2, 0 ),
   1094     /*  MIRP[14]  */  PACK( 2, 0 ),
   1095     /*  MIRP[15]  */  PACK( 2, 0 ),
   1096 
   1097     /*  MIRP[16]  */  PACK( 2, 0 ),
   1098     /*  MIRP[17]  */  PACK( 2, 0 ),
   1099     /*  MIRP[18]  */  PACK( 2, 0 ),
   1100     /*  MIRP[19]  */  PACK( 2, 0 ),
   1101     /*  MIRP[20]  */  PACK( 2, 0 ),
   1102     /*  MIRP[21]  */  PACK( 2, 0 ),
   1103     /*  MIRP[22]  */  PACK( 2, 0 ),
   1104     /*  MIRP[23]  */  PACK( 2, 0 ),
   1105     /*  MIRP[24]  */  PACK( 2, 0 ),
   1106     /*  MIRP[25]  */  PACK( 2, 0 ),
   1107     /*  MIRP[26]  */  PACK( 2, 0 ),
   1108     /*  MIRP[27]  */  PACK( 2, 0 ),
   1109     /*  MIRP[28]  */  PACK( 2, 0 ),
   1110     /*  MIRP[29]  */  PACK( 2, 0 ),
   1111     /*  MIRP[30]  */  PACK( 2, 0 ),
   1112     /*  MIRP[31]  */  PACK( 2, 0 )
   1113   };
   1114 
   1115 
   1116 #ifdef FT_DEBUG_LEVEL_TRACE
   1117 
   1118   static
   1119   const char*  const opcode_name[256] =
   1120   {
   1121     "SVTCA y",
   1122     "SVTCA x",
   1123     "SPvTCA y",
   1124     "SPvTCA x",
   1125     "SFvTCA y",
   1126     "SFvTCA x",
   1127     "SPvTL ||",
   1128     "SPvTL +",
   1129     "SFvTL ||",
   1130     "SFvTL +",
   1131     "SPvFS",
   1132     "SFvFS",
   1133     "GPV",
   1134     "GFV",
   1135     "SFvTPv",
   1136     "ISECT",
   1137 
   1138     "SRP0",
   1139     "SRP1",
   1140     "SRP2",
   1141     "SZP0",
   1142     "SZP1",
   1143     "SZP2",
   1144     "SZPS",
   1145     "SLOOP",
   1146     "RTG",
   1147     "RTHG",
   1148     "SMD",
   1149     "ELSE",
   1150     "JMPR",
   1151     "SCvTCi",
   1152     "SSwCi",
   1153     "SSW",
   1154 
   1155     "DUP",
   1156     "POP",
   1157     "CLEAR",
   1158     "SWAP",
   1159     "DEPTH",
   1160     "CINDEX",
   1161     "MINDEX",
   1162     "AlignPTS",
   1163     "INS_$28",
   1164     "UTP",
   1165     "LOOPCALL",
   1166     "CALL",
   1167     "FDEF",
   1168     "ENDF",
   1169     "MDAP[0]",
   1170     "MDAP[1]",
   1171 
   1172     "IUP[0]",
   1173     "IUP[1]",
   1174     "SHP[0]",
   1175     "SHP[1]",
   1176     "SHC[0]",
   1177     "SHC[1]",
   1178     "SHZ[0]",
   1179     "SHZ[1]",
   1180     "SHPIX",
   1181     "IP",
   1182     "MSIRP[0]",
   1183     "MSIRP[1]",
   1184     "AlignRP",
   1185     "RTDG",
   1186     "MIAP[0]",
   1187     "MIAP[1]",
   1188 
   1189     "NPushB",
   1190     "NPushW",
   1191     "WS",
   1192     "RS",
   1193     "WCvtP",
   1194     "RCvt",
   1195     "GC[0]",
   1196     "GC[1]",
   1197     "SCFS",
   1198     "MD[0]",
   1199     "MD[1]",
   1200     "MPPEM",
   1201     "MPS",
   1202     "FlipON",
   1203     "FlipOFF",
   1204     "DEBUG",
   1205 
   1206     "LT",
   1207     "LTEQ",
   1208     "GT",
   1209     "GTEQ",
   1210     "EQ",
   1211     "NEQ",
   1212     "ODD",
   1213     "EVEN",
   1214     "IF",
   1215     "EIF",
   1216     "AND",
   1217     "OR",
   1218     "NOT",
   1219     "DeltaP1",
   1220     "SDB",
   1221     "SDS",
   1222 
   1223     "ADD",
   1224     "SUB",
   1225     "DIV",
   1226     "MUL",
   1227     "ABS",
   1228     "NEG",
   1229     "FLOOR",
   1230     "CEILING",
   1231     "ROUND[0]",
   1232     "ROUND[1]",
   1233     "ROUND[2]",
   1234     "ROUND[3]",
   1235     "NROUND[0]",
   1236     "NROUND[1]",
   1237     "NROUND[2]",
   1238     "NROUND[3]",
   1239 
   1240     "WCvtF",
   1241     "DeltaP2",
   1242     "DeltaP3",
   1243     "DeltaCn[0]",
   1244     "DeltaCn[1]",
   1245     "DeltaCn[2]",
   1246     "SROUND",
   1247     "S45Round",
   1248     "JROT",
   1249     "JROF",
   1250     "ROFF",
   1251     "INS_$7B",
   1252     "RUTG",
   1253     "RDTG",
   1254     "SANGW",
   1255     "AA",
   1256 
   1257     "FlipPT",
   1258     "FlipRgON",
   1259     "FlipRgOFF",
   1260     "INS_$83",
   1261     "INS_$84",
   1262     "ScanCTRL",
   1263     "SDVPTL[0]",
   1264     "SDVPTL[1]",
   1265     "GetINFO",
   1266     "IDEF",
   1267     "ROLL",
   1268     "MAX",
   1269     "MIN",
   1270     "ScanTYPE",
   1271     "InstCTRL",
   1272     "INS_$8F",
   1273 
   1274     "INS_$90",
   1275     "INS_$91",
   1276     "INS_$92",
   1277     "INS_$93",
   1278     "INS_$94",
   1279     "INS_$95",
   1280     "INS_$96",
   1281     "INS_$97",
   1282     "INS_$98",
   1283     "INS_$99",
   1284     "INS_$9A",
   1285     "INS_$9B",
   1286     "INS_$9C",
   1287     "INS_$9D",
   1288     "INS_$9E",
   1289     "INS_$9F",
   1290 
   1291     "INS_$A0",
   1292     "INS_$A1",
   1293     "INS_$A2",
   1294     "INS_$A3",
   1295     "INS_$A4",
   1296     "INS_$A5",
   1297     "INS_$A6",
   1298     "INS_$A7",
   1299     "INS_$A8",
   1300     "INS_$A9",
   1301     "INS_$AA",
   1302     "INS_$AB",
   1303     "INS_$AC",
   1304     "INS_$AD",
   1305     "INS_$AE",
   1306     "INS_$AF",
   1307 
   1308     "PushB[0]",
   1309     "PushB[1]",
   1310     "PushB[2]",
   1311     "PushB[3]",
   1312     "PushB[4]",
   1313     "PushB[5]",
   1314     "PushB[6]",
   1315     "PushB[7]",
   1316     "PushW[0]",
   1317     "PushW[1]",
   1318     "PushW[2]",
   1319     "PushW[3]",
   1320     "PushW[4]",
   1321     "PushW[5]",
   1322     "PushW[6]",
   1323     "PushW[7]",
   1324 
   1325     "MDRP[00]",
   1326     "MDRP[01]",
   1327     "MDRP[02]",
   1328     "MDRP[03]",
   1329     "MDRP[04]",
   1330     "MDRP[05]",
   1331     "MDRP[06]",
   1332     "MDRP[07]",
   1333     "MDRP[08]",
   1334     "MDRP[09]",
   1335     "MDRP[10]",
   1336     "MDRP[11]",
   1337     "MDRP[12]",
   1338     "MDRP[13]",
   1339     "MDRP[14]",
   1340     "MDRP[15]",
   1341 
   1342     "MDRP[16]",
   1343     "MDRP[17]",
   1344     "MDRP[18]",
   1345     "MDRP[19]",
   1346     "MDRP[20]",
   1347     "MDRP[21]",
   1348     "MDRP[22]",
   1349     "MDRP[23]",
   1350     "MDRP[24]",
   1351     "MDRP[25]",
   1352     "MDRP[26]",
   1353     "MDRP[27]",
   1354     "MDRP[28]",
   1355     "MDRP[29]",
   1356     "MDRP[30]",
   1357     "MDRP[31]",
   1358 
   1359     "MIRP[00]",
   1360     "MIRP[01]",
   1361     "MIRP[02]",
   1362     "MIRP[03]",
   1363     "MIRP[04]",
   1364     "MIRP[05]",
   1365     "MIRP[06]",
   1366     "MIRP[07]",
   1367     "MIRP[08]",
   1368     "MIRP[09]",
   1369     "MIRP[10]",
   1370     "MIRP[11]",
   1371     "MIRP[12]",
   1372     "MIRP[13]",
   1373     "MIRP[14]",
   1374     "MIRP[15]",
   1375 
   1376     "MIRP[16]",
   1377     "MIRP[17]",
   1378     "MIRP[18]",
   1379     "MIRP[19]",
   1380     "MIRP[20]",
   1381     "MIRP[21]",
   1382     "MIRP[22]",
   1383     "MIRP[23]",
   1384     "MIRP[24]",
   1385     "MIRP[25]",
   1386     "MIRP[26]",
   1387     "MIRP[27]",
   1388     "MIRP[28]",
   1389     "MIRP[29]",
   1390     "MIRP[30]",
   1391     "MIRP[31]"
   1392   };
   1393 
   1394 #endif /* FT_DEBUG_LEVEL_TRACE */
   1395 
   1396 
   1397   static
   1398   const FT_Char  opcode_length[256] =
   1399   {
   1400     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1401     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1402     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1403     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1404 
   1405    -1,-2, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1406     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1407     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1408     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1409 
   1410     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1411     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1412     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1413     2, 3, 4, 5,  6, 7, 8, 9,  3, 5, 7, 9, 11,13,15,17,
   1414 
   1415     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1416     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1417     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
   1418     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1
   1419   };
   1420 
   1421 #undef PACK
   1422 
   1423 #if 1
   1424 
   1425   static FT_Int32
   1426   TT_MulFix14( FT_Int32  a,
   1427                FT_Int    b )
   1428   {
   1429     FT_Int32   sign;
   1430     FT_UInt32  ah, al, mid, lo, hi;
   1431 
   1432 
   1433     sign = a ^ b;
   1434 
   1435     if ( a < 0 )
   1436       a = -a;
   1437     if ( b < 0 )
   1438       b = -b;
   1439 
   1440     ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
   1441     al = (FT_UInt32)( a & 0xFFFFU );
   1442 
   1443     lo    = al * b;
   1444     mid   = ah * b;
   1445     hi    = mid >> 16;
   1446     mid   = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
   1447     lo   += mid;
   1448     if ( lo < mid )
   1449       hi += 1;
   1450 
   1451     mid = ( lo >> 14 ) | ( hi << 18 );
   1452 
   1453     return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
   1454   }
   1455 
   1456 #else
   1457 
   1458   /* compute (a*b)/2^14 with maximal accuracy and rounding */
   1459   static FT_Int32
   1460   TT_MulFix14( FT_Int32  a,
   1461                FT_Int    b )
   1462   {
   1463     FT_Int32   m, s, hi;
   1464     FT_UInt32  l, lo;
   1465 
   1466 
   1467     /* compute ax*bx as 64-bit value */
   1468     l  = (FT_UInt32)( ( a & 0xFFFFU ) * b );
   1469     m  = ( a >> 16 ) * b;
   1470 
   1471     lo = l + (FT_UInt32)( m << 16 );
   1472     hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
   1473 
   1474     /* divide the result by 2^14 with rounding */
   1475     s   = hi >> 31;
   1476     l   = lo + (FT_UInt32)s;
   1477     hi += s + ( l < lo );
   1478     lo  = l;
   1479 
   1480     l   = lo + 0x2000U;
   1481     hi += l < lo;
   1482 
   1483     return ( hi << 18 ) | ( l >> 14 );
   1484   }
   1485 #endif
   1486 
   1487 
   1488   /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
   1489   static FT_Int32
   1490   TT_DotFix14( FT_Int32  ax,
   1491                FT_Int32  ay,
   1492                FT_Int    bx,
   1493                FT_Int    by )
   1494   {
   1495     FT_Int32   m, s, hi1, hi2, hi;
   1496     FT_UInt32  l, lo1, lo2, lo;
   1497 
   1498 
   1499     /* compute ax*bx as 64-bit value */
   1500     l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
   1501     m = ( ax >> 16 ) * bx;
   1502 
   1503     lo1 = l + (FT_UInt32)( m << 16 );
   1504     hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
   1505 
   1506     /* compute ay*by as 64-bit value */
   1507     l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
   1508     m = ( ay >> 16 ) * by;
   1509 
   1510     lo2 = l + (FT_UInt32)( m << 16 );
   1511     hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
   1512 
   1513     /* add them */
   1514     lo = lo1 + lo2;
   1515     hi = hi1 + hi2 + ( lo < lo1 );
   1516 
   1517     /* divide the result by 2^14 with rounding */
   1518     s   = hi >> 31;
   1519     l   = lo + (FT_UInt32)s;
   1520     hi += s + ( l < lo );
   1521     lo  = l;
   1522 
   1523     l   = lo + 0x2000U;
   1524     hi += ( l < lo );
   1525 
   1526     return ( hi << 18 ) | ( l >> 14 );
   1527   }
   1528 
   1529 
   1530   /* return length of given vector */
   1531 
   1532 #if 0
   1533 
   1534   static FT_Int32
   1535   TT_VecLen( FT_Int32  x,
   1536              FT_Int32  y )
   1537   {
   1538     FT_Int32   m, hi1, hi2, hi;
   1539     FT_UInt32  l, lo1, lo2, lo;
   1540 
   1541 
   1542     /* compute x*x as 64-bit value */
   1543     lo = (FT_UInt32)( x & 0xFFFFU );
   1544     hi = x >> 16;
   1545 
   1546     l  = lo * lo;
   1547     m  = hi * lo;
   1548     hi = hi * hi;
   1549 
   1550     lo1 = l + (FT_UInt32)( m << 17 );
   1551     hi1 = hi + ( m >> 15 ) + ( lo1 < l );
   1552 
   1553     /* compute y*y as 64-bit value */
   1554     lo = (FT_UInt32)( y & 0xFFFFU );
   1555     hi = y >> 16;
   1556 
   1557     l  = lo * lo;
   1558     m  = hi * lo;
   1559     hi = hi * hi;
   1560 
   1561     lo2 = l + (FT_UInt32)( m << 17 );
   1562     hi2 = hi + ( m >> 15 ) + ( lo2 < l );
   1563 
   1564     /* add them to get 'x*x+y*y' as 64-bit value */
   1565     lo = lo1 + lo2;
   1566     hi = hi1 + hi2 + ( lo < lo1 );
   1567 
   1568     /* compute the square root of this value */
   1569     {
   1570       FT_UInt32  root, rem, test_div;
   1571       FT_Int     count;
   1572 
   1573 
   1574       root = 0;
   1575 
   1576       {
   1577         rem   = 0;
   1578         count = 32;
   1579         do
   1580         {
   1581           rem      = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
   1582           hi       = (  hi << 2 ) | (            lo >> 30 );
   1583           lo     <<= 2;
   1584           root   <<= 1;
   1585           test_div = ( root << 1 ) + 1;
   1586 
   1587           if ( rem >= test_div )
   1588           {
   1589             rem  -= test_div;
   1590             root += 1;
   1591           }
   1592         } while ( --count );
   1593       }
   1594 
   1595       return (FT_Int32)root;
   1596     }
   1597   }
   1598 
   1599 #else
   1600 
   1601   /* this version uses FT_Vector_Length which computes the same value */
   1602   /* much, much faster..                                              */
   1603   /*                                                                  */
   1604   static FT_F26Dot6
   1605   TT_VecLen( FT_F26Dot6  X,
   1606              FT_F26Dot6  Y )
   1607   {
   1608     FT_Vector  v;
   1609 
   1610 
   1611     v.x = X;
   1612     v.y = Y;
   1613 
   1614     return FT_Vector_Length( &v );
   1615   }
   1616 
   1617 #endif
   1618 
   1619 
   1620   /*************************************************************************/
   1621   /*                                                                       */
   1622   /* <Function>                                                            */
   1623   /*    Current_Ratio                                                      */
   1624   /*                                                                       */
   1625   /* <Description>                                                         */
   1626   /*    Returns the current aspect ratio scaling factor depending on the   */
   1627   /*    projection vector's state and device resolutions.                  */
   1628   /*                                                                       */
   1629   /* <Return>                                                              */
   1630   /*    The aspect ratio in 16.16 format, always <= 1.0 .                  */
   1631   /*                                                                       */
   1632   static FT_Long
   1633   Current_Ratio( EXEC_OP )
   1634   {
   1635     if ( !CUR.tt_metrics.ratio )
   1636     {
   1637 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   1638       if ( CUR.face->unpatented_hinting )
   1639       {
   1640         if ( CUR.GS.both_x_axis )
   1641           CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
   1642         else
   1643           CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
   1644       }
   1645       else
   1646 #endif
   1647       {
   1648         if ( CUR.GS.projVector.y == 0 )
   1649           CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
   1650 
   1651         else if ( CUR.GS.projVector.x == 0 )
   1652           CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
   1653 
   1654         else
   1655         {
   1656           FT_Long  x, y;
   1657 
   1658 
   1659           x = TT_MULDIV( CUR.GS.projVector.x,
   1660                          CUR.tt_metrics.x_ratio, 0x4000 );
   1661           y = TT_MULDIV( CUR.GS.projVector.y,
   1662                          CUR.tt_metrics.y_ratio, 0x4000 );
   1663           CUR.tt_metrics.ratio = TT_VecLen( x, y );
   1664         }
   1665       }
   1666     }
   1667     return CUR.tt_metrics.ratio;
   1668   }
   1669 
   1670 
   1671   static FT_Long
   1672   Current_Ppem( EXEC_OP )
   1673   {
   1674     return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
   1675   }
   1676 
   1677 
   1678   /*************************************************************************/
   1679   /*                                                                       */
   1680   /* Functions related to the control value table (CVT).                   */
   1681   /*                                                                       */
   1682   /*************************************************************************/
   1683 
   1684 
   1685   FT_CALLBACK_DEF( FT_F26Dot6 )
   1686   Read_CVT( EXEC_OP_ FT_ULong  idx )
   1687   {
   1688     return CUR.cvt[idx];
   1689   }
   1690 
   1691 
   1692   FT_CALLBACK_DEF( FT_F26Dot6 )
   1693   Read_CVT_Stretched( EXEC_OP_ FT_ULong  idx )
   1694   {
   1695     return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
   1696   }
   1697 
   1698 
   1699   FT_CALLBACK_DEF( void )
   1700   Write_CVT( EXEC_OP_ FT_ULong    idx,
   1701                       FT_F26Dot6  value )
   1702   {
   1703     CUR.cvt[idx] = value;
   1704   }
   1705 
   1706 
   1707   FT_CALLBACK_DEF( void )
   1708   Write_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
   1709                                 FT_F26Dot6  value )
   1710   {
   1711     CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
   1712   }
   1713 
   1714 
   1715   FT_CALLBACK_DEF( void )
   1716   Move_CVT( EXEC_OP_ FT_ULong    idx,
   1717                      FT_F26Dot6  value )
   1718   {
   1719     CUR.cvt[idx] += value;
   1720   }
   1721 
   1722 
   1723   FT_CALLBACK_DEF( void )
   1724   Move_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
   1725                                FT_F26Dot6  value )
   1726   {
   1727     CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
   1728   }
   1729 
   1730 
   1731   /*************************************************************************/
   1732   /*                                                                       */
   1733   /* <Function>                                                            */
   1734   /*    GetShortIns                                                        */
   1735   /*                                                                       */
   1736   /* <Description>                                                         */
   1737   /*    Returns a short integer taken from the instruction stream at       */
   1738   /*    address IP.                                                        */
   1739   /*                                                                       */
   1740   /* <Return>                                                              */
   1741   /*    Short read at code[IP].                                            */
   1742   /*                                                                       */
   1743   /* <Note>                                                                */
   1744   /*    This one could become a macro.                                     */
   1745   /*                                                                       */
   1746   static FT_Short
   1747   GetShortIns( EXEC_OP )
   1748   {
   1749     /* Reading a byte stream so there is no endianess (DaveP) */
   1750     CUR.IP += 2;
   1751     return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
   1752                          CUR.code[CUR.IP - 1]      );
   1753   }
   1754 
   1755 
   1756   /*************************************************************************/
   1757   /*                                                                       */
   1758   /* <Function>                                                            */
   1759   /*    Ins_Goto_CodeRange                                                 */
   1760   /*                                                                       */
   1761   /* <Description>                                                         */
   1762   /*    Goes to a certain code range in the instruction stream.            */
   1763   /*                                                                       */
   1764   /* <Input>                                                               */
   1765   /*    aRange :: The index of the code range.                             */
   1766   /*                                                                       */
   1767   /*    aIP    :: The new IP address in the code range.                    */
   1768   /*                                                                       */
   1769   /* <Return>                                                              */
   1770   /*    SUCCESS or FAILURE.                                                */
   1771   /*                                                                       */
   1772   static FT_Bool
   1773   Ins_Goto_CodeRange( EXEC_OP_ FT_Int    aRange,
   1774                                FT_ULong  aIP )
   1775   {
   1776     TT_CodeRange*  range;
   1777 
   1778 
   1779     if ( aRange < 1 || aRange > 3 )
   1780     {
   1781       CUR.error = TT_Err_Bad_Argument;
   1782       return FAILURE;
   1783     }
   1784 
   1785     range = &CUR.codeRangeTable[aRange - 1];
   1786 
   1787     if ( range->base == NULL )     /* invalid coderange */
   1788     {
   1789       CUR.error = TT_Err_Invalid_CodeRange;
   1790       return FAILURE;
   1791     }
   1792 
   1793     /* NOTE: Because the last instruction of a program may be a CALL */
   1794     /*       which will return to the first byte *after* the code    */
   1795     /*       range, we test for AIP <= Size, instead of AIP < Size.  */
   1796 
   1797     if ( aIP > range->size )
   1798     {
   1799       CUR.error = TT_Err_Code_Overflow;
   1800       return FAILURE;
   1801     }
   1802 
   1803     CUR.code     = range->base;
   1804     CUR.codeSize = range->size;
   1805     CUR.IP       = aIP;
   1806     CUR.curRange = aRange;
   1807 
   1808     return SUCCESS;
   1809   }
   1810 
   1811 
   1812   /*************************************************************************/
   1813   /*                                                                       */
   1814   /* <Function>                                                            */
   1815   /*    Direct_Move                                                        */
   1816   /*                                                                       */
   1817   /* <Description>                                                         */
   1818   /*    Moves a point by a given distance along the freedom vector.  The   */
   1819   /*    point will be `touched'.                                           */
   1820   /*                                                                       */
   1821   /* <Input>                                                               */
   1822   /*    point    :: The index of the point to move.                        */
   1823   /*                                                                       */
   1824   /*    distance :: The distance to apply.                                 */
   1825   /*                                                                       */
   1826   /* <InOut>                                                               */
   1827   /*    zone     :: The affected glyph zone.                               */
   1828   /*                                                                       */
   1829   static void
   1830   Direct_Move( EXEC_OP_ TT_GlyphZone  zone,
   1831                         FT_UShort     point,
   1832                         FT_F26Dot6    distance )
   1833   {
   1834     FT_F26Dot6  v;
   1835 
   1836 
   1837 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   1838     FT_ASSERT( !CUR.face->unpatented_hinting );
   1839 #endif
   1840 
   1841     v = CUR.GS.freeVector.x;
   1842 
   1843     if ( v != 0 )
   1844     {
   1845       zone->cur[point].x += TT_MULDIV( distance,
   1846                                        v * 0x10000L,
   1847                                        CUR.F_dot_P );
   1848 
   1849       zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
   1850     }
   1851 
   1852     v = CUR.GS.freeVector.y;
   1853 
   1854     if ( v != 0 )
   1855     {
   1856       zone->cur[point].y += TT_MULDIV( distance,
   1857                                        v * 0x10000L,
   1858                                        CUR.F_dot_P );
   1859 
   1860       zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
   1861     }
   1862   }
   1863 
   1864 
   1865   /*************************************************************************/
   1866   /*                                                                       */
   1867   /* <Function>                                                            */
   1868   /*    Direct_Move_Orig                                                   */
   1869   /*                                                                       */
   1870   /* <Description>                                                         */
   1871   /*    Moves the *original* position of a point by a given distance along */
   1872   /*    the freedom vector.  Obviously, the point will not be `touched'.   */
   1873   /*                                                                       */
   1874   /* <Input>                                                               */
   1875   /*    point    :: The index of the point to move.                        */
   1876   /*                                                                       */
   1877   /*    distance :: The distance to apply.                                 */
   1878   /*                                                                       */
   1879   /* <InOut>                                                               */
   1880   /*    zone     :: The affected glyph zone.                               */
   1881   /*                                                                       */
   1882   static void
   1883   Direct_Move_Orig( EXEC_OP_ TT_GlyphZone  zone,
   1884                              FT_UShort     point,
   1885                              FT_F26Dot6    distance )
   1886   {
   1887     FT_F26Dot6  v;
   1888 
   1889 
   1890 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   1891     FT_ASSERT( !CUR.face->unpatented_hinting );
   1892 #endif
   1893 
   1894     v = CUR.GS.freeVector.x;
   1895 
   1896     if ( v != 0 )
   1897       zone->org[point].x += TT_MULDIV( distance,
   1898                                        v * 0x10000L,
   1899                                        CUR.F_dot_P );
   1900 
   1901     v = CUR.GS.freeVector.y;
   1902 
   1903     if ( v != 0 )
   1904       zone->org[point].y += TT_MULDIV( distance,
   1905                                        v * 0x10000L,
   1906                                        CUR.F_dot_P );
   1907   }
   1908 
   1909 
   1910   /*************************************************************************/
   1911   /*                                                                       */
   1912   /* Special versions of Direct_Move()                                     */
   1913   /*                                                                       */
   1914   /*   The following versions are used whenever both vectors are both      */
   1915   /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
   1916   /*                                                                       */
   1917   /*************************************************************************/
   1918 
   1919 
   1920   static void
   1921   Direct_Move_X( EXEC_OP_ TT_GlyphZone  zone,
   1922                           FT_UShort     point,
   1923                           FT_F26Dot6    distance )
   1924   {
   1925     FT_UNUSED_EXEC;
   1926 
   1927     zone->cur[point].x += distance;
   1928     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
   1929   }
   1930 
   1931 
   1932   static void
   1933   Direct_Move_Y( EXEC_OP_ TT_GlyphZone  zone,
   1934                           FT_UShort     point,
   1935                           FT_F26Dot6    distance )
   1936   {
   1937     FT_UNUSED_EXEC;
   1938 
   1939     zone->cur[point].y += distance;
   1940     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_Y;
   1941   }
   1942 
   1943 
   1944   /*************************************************************************/
   1945   /*                                                                       */
   1946   /* Special versions of Direct_Move_Orig()                                */
   1947   /*                                                                       */
   1948   /*   The following versions are used whenever both vectors are both      */
   1949   /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
   1950   /*                                                                       */
   1951   /*************************************************************************/
   1952 
   1953 
   1954   static void
   1955   Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone  zone,
   1956                                FT_UShort     point,
   1957                                FT_F26Dot6    distance )
   1958   {
   1959     FT_UNUSED_EXEC;
   1960 
   1961     zone->org[point].x += distance;
   1962   }
   1963 
   1964 
   1965   static void
   1966   Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone  zone,
   1967                                FT_UShort     point,
   1968                                FT_F26Dot6    distance )
   1969   {
   1970     FT_UNUSED_EXEC;
   1971 
   1972     zone->org[point].y += distance;
   1973   }
   1974 
   1975 
   1976   /*************************************************************************/
   1977   /*                                                                       */
   1978   /* <Function>                                                            */
   1979   /*    Round_None                                                         */
   1980   /*                                                                       */
   1981   /* <Description>                                                         */
   1982   /*    Does not round, but adds engine compensation.                      */
   1983   /*                                                                       */
   1984   /* <Input>                                                               */
   1985   /*    distance     :: The distance (not) to round.                       */
   1986   /*                                                                       */
   1987   /*    compensation :: The engine compensation.                           */
   1988   /*                                                                       */
   1989   /* <Return>                                                              */
   1990   /*    The compensated distance.                                          */
   1991   /*                                                                       */
   1992   /* <Note>                                                                */
   1993   /*    The TrueType specification says very few about the relationship    */
   1994   /*    between rounding and engine compensation.  However, it seems from  */
   1995   /*    the description of super round that we should add the compensation */
   1996   /*    before rounding.                                                   */
   1997   /*                                                                       */
   1998   static FT_F26Dot6
   1999   Round_None( EXEC_OP_ FT_F26Dot6  distance,
   2000                        FT_F26Dot6  compensation )
   2001   {
   2002     FT_F26Dot6  val;
   2003 
   2004     FT_UNUSED_EXEC;
   2005 
   2006 
   2007     if ( distance >= 0 )
   2008     {
   2009       val = distance + compensation;
   2010       if ( distance && val < 0 )
   2011         val = 0;
   2012     }
   2013     else
   2014     {
   2015       val = distance - compensation;
   2016       if ( val > 0 )
   2017         val = 0;
   2018     }
   2019     return val;
   2020   }
   2021 
   2022 
   2023   /*************************************************************************/
   2024   /*                                                                       */
   2025   /* <Function>                                                            */
   2026   /*    Round_To_Grid                                                      */
   2027   /*                                                                       */
   2028   /* <Description>                                                         */
   2029   /*    Rounds value to grid after adding engine compensation.             */
   2030   /*                                                                       */
   2031   /* <Input>                                                               */
   2032   /*    distance     :: The distance to round.                             */
   2033   /*                                                                       */
   2034   /*    compensation :: The engine compensation.                           */
   2035   /*                                                                       */
   2036   /* <Return>                                                              */
   2037   /*    Rounded distance.                                                  */
   2038   /*                                                                       */
   2039   static FT_F26Dot6
   2040   Round_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
   2041                           FT_F26Dot6  compensation )
   2042   {
   2043     FT_F26Dot6  val;
   2044 
   2045     FT_UNUSED_EXEC;
   2046 
   2047 
   2048     if ( distance >= 0 )
   2049     {
   2050       val = distance + compensation + 32;
   2051       if ( distance && val > 0 )
   2052         val &= ~63;
   2053       else
   2054         val = 0;
   2055     }
   2056     else
   2057     {
   2058       val = -FT_PIX_ROUND( compensation - distance );
   2059       if ( val > 0 )
   2060         val = 0;
   2061     }
   2062 
   2063     return  val;
   2064   }
   2065 
   2066 
   2067   /*************************************************************************/
   2068   /*                                                                       */
   2069   /* <Function>                                                            */
   2070   /*    Round_To_Half_Grid                                                 */
   2071   /*                                                                       */
   2072   /* <Description>                                                         */
   2073   /*    Rounds value to half grid after adding engine compensation.        */
   2074   /*                                                                       */
   2075   /* <Input>                                                               */
   2076   /*    distance     :: The distance to round.                             */
   2077   /*                                                                       */
   2078   /*    compensation :: The engine compensation.                           */
   2079   /*                                                                       */
   2080   /* <Return>                                                              */
   2081   /*    Rounded distance.                                                  */
   2082   /*                                                                       */
   2083   static FT_F26Dot6
   2084   Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6  distance,
   2085                                FT_F26Dot6  compensation )
   2086   {
   2087     FT_F26Dot6  val;
   2088 
   2089     FT_UNUSED_EXEC;
   2090 
   2091 
   2092     if ( distance >= 0 )
   2093     {
   2094       val = FT_PIX_FLOOR( distance + compensation ) + 32;
   2095       if ( distance && val < 0 )
   2096         val = 0;
   2097     }
   2098     else
   2099     {
   2100       val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
   2101       if ( val > 0 )
   2102         val = 0;
   2103     }
   2104 
   2105     return val;
   2106   }
   2107 
   2108 
   2109   /*************************************************************************/
   2110   /*                                                                       */
   2111   /* <Function>                                                            */
   2112   /*    Round_Down_To_Grid                                                 */
   2113   /*                                                                       */
   2114   /* <Description>                                                         */
   2115   /*    Rounds value down to grid after adding engine compensation.        */
   2116   /*                                                                       */
   2117   /* <Input>                                                               */
   2118   /*    distance     :: The distance to round.                             */
   2119   /*                                                                       */
   2120   /*    compensation :: The engine compensation.                           */
   2121   /*                                                                       */
   2122   /* <Return>                                                              */
   2123   /*    Rounded distance.                                                  */
   2124   /*                                                                       */
   2125   static FT_F26Dot6
   2126   Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
   2127                                FT_F26Dot6  compensation )
   2128   {
   2129     FT_F26Dot6  val;
   2130 
   2131     FT_UNUSED_EXEC;
   2132 
   2133 
   2134     if ( distance >= 0 )
   2135     {
   2136       val = distance + compensation;
   2137       if ( distance && val > 0 )
   2138         val &= ~63;
   2139       else
   2140         val = 0;
   2141     }
   2142     else
   2143     {
   2144       val = -( ( compensation - distance ) & -64 );
   2145       if ( val > 0 )
   2146         val = 0;
   2147     }
   2148 
   2149     return val;
   2150   }
   2151 
   2152 
   2153   /*************************************************************************/
   2154   /*                                                                       */
   2155   /* <Function>                                                            */
   2156   /*    Round_Up_To_Grid                                                   */
   2157   /*                                                                       */
   2158   /* <Description>                                                         */
   2159   /*    Rounds value up to grid after adding engine compensation.          */
   2160   /*                                                                       */
   2161   /* <Input>                                                               */
   2162   /*    distance     :: The distance to round.                             */
   2163   /*                                                                       */
   2164   /*    compensation :: The engine compensation.                           */
   2165   /*                                                                       */
   2166   /* <Return>                                                              */
   2167   /*    Rounded distance.                                                  */
   2168   /*                                                                       */
   2169   static FT_F26Dot6
   2170   Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
   2171                              FT_F26Dot6  compensation )
   2172   {
   2173     FT_F26Dot6  val;
   2174 
   2175     FT_UNUSED_EXEC;
   2176 
   2177 
   2178     if ( distance >= 0 )
   2179     {
   2180       val = distance + compensation + 63;
   2181       if ( distance && val > 0 )
   2182         val &= ~63;
   2183       else
   2184         val = 0;
   2185     }
   2186     else
   2187     {
   2188       val = - FT_PIX_CEIL( compensation - distance );
   2189       if ( val > 0 )
   2190         val = 0;
   2191     }
   2192 
   2193     return val;
   2194   }
   2195 
   2196 
   2197   /*************************************************************************/
   2198   /*                                                                       */
   2199   /* <Function>                                                            */
   2200   /*    Round_To_Double_Grid                                               */
   2201   /*                                                                       */
   2202   /* <Description>                                                         */
   2203   /*    Rounds value to double grid after adding engine compensation.      */
   2204   /*                                                                       */
   2205   /* <Input>                                                               */
   2206   /*    distance     :: The distance to round.                             */
   2207   /*                                                                       */
   2208   /*    compensation :: The engine compensation.                           */
   2209   /*                                                                       */
   2210   /* <Return>                                                              */
   2211   /*    Rounded distance.                                                  */
   2212   /*                                                                       */
   2213   static FT_F26Dot6
   2214   Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6  distance,
   2215                                  FT_F26Dot6  compensation )
   2216   {
   2217     FT_F26Dot6 val;
   2218 
   2219     FT_UNUSED_EXEC;
   2220 
   2221 
   2222     if ( distance >= 0 )
   2223     {
   2224       val = distance + compensation + 16;
   2225       if ( distance && val > 0 )
   2226         val &= ~31;
   2227       else
   2228         val = 0;
   2229     }
   2230     else
   2231     {
   2232       val = -FT_PAD_ROUND( compensation - distance, 32 );
   2233       if ( val > 0 )
   2234         val = 0;
   2235     }
   2236 
   2237     return val;
   2238   }
   2239 
   2240 
   2241   /*************************************************************************/
   2242   /*                                                                       */
   2243   /* <Function>                                                            */
   2244   /*    Round_Super                                                        */
   2245   /*                                                                       */
   2246   /* <Description>                                                         */
   2247   /*    Super-rounds value to grid after adding engine compensation.       */
   2248   /*                                                                       */
   2249   /* <Input>                                                               */
   2250   /*    distance     :: The distance to round.                             */
   2251   /*                                                                       */
   2252   /*    compensation :: The engine compensation.                           */
   2253   /*                                                                       */
   2254   /* <Return>                                                              */
   2255   /*    Rounded distance.                                                  */
   2256   /*                                                                       */
   2257   /* <Note>                                                                */
   2258   /*    The TrueType specification says very few about the relationship    */
   2259   /*    between rounding and engine compensation.  However, it seems from  */
   2260   /*    the description of super round that we should add the compensation */
   2261   /*    before rounding.                                                   */
   2262   /*                                                                       */
   2263   static FT_F26Dot6
   2264   Round_Super( EXEC_OP_ FT_F26Dot6  distance,
   2265                         FT_F26Dot6  compensation )
   2266   {
   2267     FT_F26Dot6  val;
   2268 
   2269 
   2270     if ( distance >= 0 )
   2271     {
   2272       val = ( distance - CUR.phase + CUR.threshold + compensation ) &
   2273               -CUR.period;
   2274       if ( distance && val < 0 )
   2275         val = 0;
   2276       val += CUR.phase;
   2277     }
   2278     else
   2279     {
   2280       val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
   2281                -CUR.period );
   2282       if ( val > 0 )
   2283         val = 0;
   2284       val -= CUR.phase;
   2285     }
   2286 
   2287     return val;
   2288   }
   2289 
   2290 
   2291   /*************************************************************************/
   2292   /*                                                                       */
   2293   /* <Function>                                                            */
   2294   /*    Round_Super_45                                                     */
   2295   /*                                                                       */
   2296   /* <Description>                                                         */
   2297   /*    Super-rounds value to grid after adding engine compensation.       */
   2298   /*                                                                       */
   2299   /* <Input>                                                               */
   2300   /*    distance     :: The distance to round.                             */
   2301   /*                                                                       */
   2302   /*    compensation :: The engine compensation.                           */
   2303   /*                                                                       */
   2304   /* <Return>                                                              */
   2305   /*    Rounded distance.                                                  */
   2306   /*                                                                       */
   2307   /* <Note>                                                                */
   2308   /*    There is a separate function for Round_Super_45() as we may need   */
   2309   /*    greater precision.                                                 */
   2310   /*                                                                       */
   2311   static FT_F26Dot6
   2312   Round_Super_45( EXEC_OP_ FT_F26Dot6  distance,
   2313                            FT_F26Dot6  compensation )
   2314   {
   2315     FT_F26Dot6  val;
   2316 
   2317 
   2318     if ( distance >= 0 )
   2319     {
   2320       val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
   2321                 CUR.period ) * CUR.period;
   2322       if ( distance && val < 0 )
   2323         val = 0;
   2324       val += CUR.phase;
   2325     }
   2326     else
   2327     {
   2328       val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
   2329                    CUR.period ) * CUR.period );
   2330       if ( val > 0 )
   2331         val = 0;
   2332       val -= CUR.phase;
   2333     }
   2334 
   2335     return val;
   2336   }
   2337 
   2338 
   2339   /*************************************************************************/
   2340   /*                                                                       */
   2341   /* <Function>                                                            */
   2342   /*    Compute_Round                                                      */
   2343   /*                                                                       */
   2344   /* <Description>                                                         */
   2345   /*    Sets the rounding mode.                                            */
   2346   /*                                                                       */
   2347   /* <Input>                                                               */
   2348   /*    round_mode :: The rounding mode to be used.                        */
   2349   /*                                                                       */
   2350   static void
   2351   Compute_Round( EXEC_OP_ FT_Byte  round_mode )
   2352   {
   2353     switch ( round_mode )
   2354     {
   2355     case TT_Round_Off:
   2356       CUR.func_round = (TT_Round_Func)Round_None;
   2357       break;
   2358 
   2359     case TT_Round_To_Grid:
   2360       CUR.func_round = (TT_Round_Func)Round_To_Grid;
   2361       break;
   2362 
   2363     case TT_Round_Up_To_Grid:
   2364       CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
   2365       break;
   2366 
   2367     case TT_Round_Down_To_Grid:
   2368       CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
   2369       break;
   2370 
   2371     case TT_Round_To_Half_Grid:
   2372       CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
   2373       break;
   2374 
   2375     case TT_Round_To_Double_Grid:
   2376       CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
   2377       break;
   2378 
   2379     case TT_Round_Super:
   2380       CUR.func_round = (TT_Round_Func)Round_Super;
   2381       break;
   2382 
   2383     case TT_Round_Super_45:
   2384       CUR.func_round = (TT_Round_Func)Round_Super_45;
   2385       break;
   2386     }
   2387   }
   2388 
   2389 
   2390   /*************************************************************************/
   2391   /*                                                                       */
   2392   /* <Function>                                                            */
   2393   /*    SetSuperRound                                                      */
   2394   /*                                                                       */
   2395   /* <Description>                                                         */
   2396   /*    Sets Super Round parameters.                                       */
   2397   /*                                                                       */
   2398   /* <Input>                                                               */
   2399   /*    GridPeriod :: Grid period                                          */
   2400   /*    selector   :: SROUND opcode                                        */
   2401   /*                                                                       */
   2402   static void
   2403   SetSuperRound( EXEC_OP_ FT_F26Dot6  GridPeriod,
   2404                           FT_Long     selector )
   2405   {
   2406     switch ( (FT_Int)( selector & 0xC0 ) )
   2407     {
   2408       case 0:
   2409         CUR.period = GridPeriod / 2;
   2410         break;
   2411 
   2412       case 0x40:
   2413         CUR.period = GridPeriod;
   2414         break;
   2415 
   2416       case 0x80:
   2417         CUR.period = GridPeriod * 2;
   2418         break;
   2419 
   2420       /* This opcode is reserved, but... */
   2421 
   2422       case 0xC0:
   2423         CUR.period = GridPeriod;
   2424         break;
   2425     }
   2426 
   2427     switch ( (FT_Int)( selector & 0x30 ) )
   2428     {
   2429     case 0:
   2430       CUR.phase = 0;
   2431       break;
   2432 
   2433     case 0x10:
   2434       CUR.phase = CUR.period / 4;
   2435       break;
   2436 
   2437     case 0x20:
   2438       CUR.phase = CUR.period / 2;
   2439       break;
   2440 
   2441     case 0x30:
   2442       CUR.phase = CUR.period * 3 / 4;
   2443       break;
   2444     }
   2445 
   2446     if ( ( selector & 0x0F ) == 0 )
   2447       CUR.threshold = CUR.period - 1;
   2448     else
   2449       CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
   2450 
   2451     CUR.period    /= 256;
   2452     CUR.phase     /= 256;
   2453     CUR.threshold /= 256;
   2454   }
   2455 
   2456 
   2457   /*************************************************************************/
   2458   /*                                                                       */
   2459   /* <Function>                                                            */
   2460   /*    Project                                                            */
   2461   /*                                                                       */
   2462   /* <Description>                                                         */
   2463   /*    Computes the projection of vector given by (v2-v1) along the       */
   2464   /*    current projection vector.                                         */
   2465   /*                                                                       */
   2466   /* <Input>                                                               */
   2467   /*    v1 :: First input vector.                                          */
   2468   /*    v2 :: Second input vector.                                         */
   2469   /*                                                                       */
   2470   /* <Return>                                                              */
   2471   /*    The distance in F26dot6 format.                                    */
   2472   /*                                                                       */
   2473   static FT_F26Dot6
   2474   Project( EXEC_OP_ FT_Pos  dx,
   2475                     FT_Pos  dy )
   2476   {
   2477 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   2478     FT_ASSERT( !CUR.face->unpatented_hinting );
   2479 #endif
   2480 
   2481     return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
   2482                         CUR.GS.projVector.x,
   2483                         CUR.GS.projVector.y );
   2484   }
   2485 
   2486 
   2487   /*************************************************************************/
   2488   /*                                                                       */
   2489   /* <Function>                                                            */
   2490   /*    Dual_Project                                                       */
   2491   /*                                                                       */
   2492   /* <Description>                                                         */
   2493   /*    Computes the projection of the vector given by (v2-v1) along the   */
   2494   /*    current dual vector.                                               */
   2495   /*                                                                       */
   2496   /* <Input>                                                               */
   2497   /*    v1 :: First input vector.                                          */
   2498   /*    v2 :: Second input vector.                                         */
   2499   /*                                                                       */
   2500   /* <Return>                                                              */
   2501   /*    The distance in F26dot6 format.                                    */
   2502   /*                                                                       */
   2503   static FT_F26Dot6
   2504   Dual_Project( EXEC_OP_ FT_Pos  dx,
   2505                          FT_Pos  dy )
   2506   {
   2507     return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
   2508                         CUR.GS.dualVector.x,
   2509                         CUR.GS.dualVector.y );
   2510   }
   2511 
   2512 
   2513   /*************************************************************************/
   2514   /*                                                                       */
   2515   /* <Function>                                                            */
   2516   /*    Project_x                                                          */
   2517   /*                                                                       */
   2518   /* <Description>                                                         */
   2519   /*    Computes the projection of the vector given by (v2-v1) along the   */
   2520   /*    horizontal axis.                                                   */
   2521   /*                                                                       */
   2522   /* <Input>                                                               */
   2523   /*    v1 :: First input vector.                                          */
   2524   /*    v2 :: Second input vector.                                         */
   2525   /*                                                                       */
   2526   /* <Return>                                                              */
   2527   /*    The distance in F26dot6 format.                                    */
   2528   /*                                                                       */
   2529   static FT_F26Dot6
   2530   Project_x( EXEC_OP_ FT_Pos  dx,
   2531                       FT_Pos  dy )
   2532   {
   2533     FT_UNUSED_EXEC;
   2534     FT_UNUSED( dy );
   2535 
   2536     return dx;
   2537   }
   2538 
   2539 
   2540   /*************************************************************************/
   2541   /*                                                                       */
   2542   /* <Function>                                                            */
   2543   /*    Project_y                                                          */
   2544   /*                                                                       */
   2545   /* <Description>                                                         */
   2546   /*    Computes the projection of the vector given by (v2-v1) along the   */
   2547   /*    vertical axis.                                                     */
   2548   /*                                                                       */
   2549   /* <Input>                                                               */
   2550   /*    v1 :: First input vector.                                          */
   2551   /*    v2 :: Second input vector.                                         */
   2552   /*                                                                       */
   2553   /* <Return>                                                              */
   2554   /*    The distance in F26dot6 format.                                    */
   2555   /*                                                                       */
   2556   static FT_F26Dot6
   2557   Project_y( EXEC_OP_ FT_Pos  dx,
   2558                       FT_Pos  dy )
   2559   {
   2560     FT_UNUSED_EXEC;
   2561     FT_UNUSED( dx );
   2562 
   2563     return dy;
   2564   }
   2565 
   2566 
   2567   /*************************************************************************/
   2568   /*                                                                       */
   2569   /* <Function>                                                            */
   2570   /*    Compute_Funcs                                                      */
   2571   /*                                                                       */
   2572   /* <Description>                                                         */
   2573   /*    Computes the projection and movement function pointers according   */
   2574   /*    to the current graphics state.                                     */
   2575   /*                                                                       */
   2576   static void
   2577   Compute_Funcs( EXEC_OP )
   2578   {
   2579 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   2580     if ( CUR.face->unpatented_hinting )
   2581     {
   2582       /* If both vectors point rightwards along the x axis, set             */
   2583       /* `both-x-axis' true, otherwise set it false.  The x values only     */
   2584       /* need be tested because the vector has been normalised to a unit    */
   2585       /* vector of length 0x4000 = unity.                                   */
   2586       CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
   2587                                       CUR.GS.freeVector.x == 0x4000 );
   2588 
   2589       /* Throw away projection and freedom vector information */
   2590       /* because the patents don't allow them to be stored.   */
   2591       /* The relevant US Patents are 5155805 and 5325479.     */
   2592       CUR.GS.projVector.x = 0;
   2593       CUR.GS.projVector.y = 0;
   2594       CUR.GS.freeVector.x = 0;
   2595       CUR.GS.freeVector.y = 0;
   2596 
   2597       if ( CUR.GS.both_x_axis )
   2598       {
   2599         CUR.func_project   = Project_x;
   2600         CUR.func_move      = Direct_Move_X;
   2601         CUR.func_move_orig = Direct_Move_Orig_X;
   2602       }
   2603       else
   2604       {
   2605         CUR.func_project   = Project_y;
   2606         CUR.func_move      = Direct_Move_Y;
   2607         CUR.func_move_orig = Direct_Move_Orig_Y;
   2608       }
   2609 
   2610       if ( CUR.GS.dualVector.x == 0x4000 )
   2611         CUR.func_dualproj = Project_x;
   2612       else
   2613       {
   2614         if ( CUR.GS.dualVector.y == 0x4000 )
   2615           CUR.func_dualproj = Project_y;
   2616         else
   2617           CUR.func_dualproj = Dual_Project;
   2618       }
   2619 
   2620       /* Force recalculation of cached aspect ratio */
   2621       CUR.tt_metrics.ratio = 0;
   2622 
   2623       return;
   2624     }
   2625 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
   2626 
   2627     if ( CUR.GS.freeVector.x == 0x4000 )
   2628       CUR.F_dot_P       = CUR.GS.projVector.x * 0x10000L;
   2629     else
   2630     {
   2631       if ( CUR.GS.freeVector.y == 0x4000 )
   2632         CUR.F_dot_P       = CUR.GS.projVector.y * 0x10000L;
   2633       else
   2634         CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
   2635                       (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
   2636     }
   2637 
   2638     if ( CUR.GS.projVector.x == 0x4000 )
   2639       CUR.func_project = (TT_Project_Func)Project_x;
   2640     else
   2641     {
   2642       if ( CUR.GS.projVector.y == 0x4000 )
   2643         CUR.func_project = (TT_Project_Func)Project_y;
   2644       else
   2645         CUR.func_project = (TT_Project_Func)Project;
   2646     }
   2647 
   2648     if ( CUR.GS.dualVector.x == 0x4000 )
   2649       CUR.func_dualproj = (TT_Project_Func)Project_x;
   2650     else
   2651     {
   2652       if ( CUR.GS.dualVector.y == 0x4000 )
   2653         CUR.func_dualproj = (TT_Project_Func)Project_y;
   2654       else
   2655         CUR.func_dualproj = (TT_Project_Func)Dual_Project;
   2656     }
   2657 
   2658     CUR.func_move      = (TT_Move_Func)Direct_Move;
   2659     CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
   2660 
   2661     if ( CUR.F_dot_P == 0x40000000L )
   2662     {
   2663       if ( CUR.GS.freeVector.x == 0x4000 )
   2664       {
   2665         CUR.func_move      = (TT_Move_Func)Direct_Move_X;
   2666         CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
   2667       }
   2668       else
   2669       {
   2670         if ( CUR.GS.freeVector.y == 0x4000 )
   2671         {
   2672           CUR.func_move      = (TT_Move_Func)Direct_Move_Y;
   2673           CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
   2674         }
   2675       }
   2676     }
   2677 
   2678     /* at small sizes, F_dot_P can become too small, resulting   */
   2679     /* in overflows and `spikes' in a number of glyphs like `w'. */
   2680 
   2681     if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
   2682       CUR.F_dot_P = 0x40000000L;
   2683 
   2684     /* Disable cached aspect ratio */
   2685     CUR.tt_metrics.ratio = 0;
   2686   }
   2687 
   2688 
   2689   /*************************************************************************/
   2690   /*                                                                       */
   2691   /* <Function>                                                            */
   2692   /*    Normalize                                                          */
   2693   /*                                                                       */
   2694   /* <Description>                                                         */
   2695   /*    Norms a vector.                                                    */
   2696   /*                                                                       */
   2697   /* <Input>                                                               */
   2698   /*    Vx :: The horizontal input vector coordinate.                      */
   2699   /*    Vy :: The vertical input vector coordinate.                        */
   2700   /*                                                                       */
   2701   /* <Output>                                                              */
   2702   /*    R  :: The normed unit vector.                                      */
   2703   /*                                                                       */
   2704   /* <Return>                                                              */
   2705   /*    Returns FAILURE if a vector parameter is zero.                     */
   2706   /*                                                                       */
   2707   /* <Note>                                                                */
   2708   /*    In case Vx and Vy are both zero, Normalize() returns SUCCESS, and  */
   2709   /*    R is undefined.                                                    */
   2710   /*                                                                       */
   2711 
   2712 
   2713   static FT_Bool
   2714   Normalize( EXEC_OP_ FT_F26Dot6      Vx,
   2715                       FT_F26Dot6      Vy,
   2716                       FT_UnitVector*  R )
   2717   {
   2718     FT_F26Dot6  W;
   2719     FT_Bool     S1, S2;
   2720 
   2721     FT_UNUSED_EXEC;
   2722 
   2723 
   2724     if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
   2725     {
   2726       Vx *= 0x100;
   2727       Vy *= 0x100;
   2728 
   2729       W = TT_VecLen( Vx, Vy );
   2730 
   2731       if ( W == 0 )
   2732       {
   2733         /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
   2734         /*      to normalize the vector (0,0).  Return immediately. */
   2735         return SUCCESS;
   2736       }
   2737 
   2738       R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
   2739       R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
   2740 
   2741       return SUCCESS;
   2742     }
   2743 
   2744     W = TT_VecLen( Vx, Vy );
   2745 
   2746     Vx = FT_MulDiv( Vx, 0x4000L, W );
   2747     Vy = FT_MulDiv( Vy, 0x4000L, W );
   2748 
   2749     W = Vx * Vx + Vy * Vy;
   2750 
   2751     /* Now, we want that Sqrt( W ) = 0x4000 */
   2752     /* Or 0x10000000 <= W < 0x10004000        */
   2753 
   2754     if ( Vx < 0 )
   2755     {
   2756       Vx = -Vx;
   2757       S1 = TRUE;
   2758     }
   2759     else
   2760       S1 = FALSE;
   2761 
   2762     if ( Vy < 0 )
   2763     {
   2764       Vy = -Vy;
   2765       S2 = TRUE;
   2766     }
   2767     else
   2768       S2 = FALSE;
   2769 
   2770     while ( W < 0x10000000L )
   2771     {
   2772       /* We need to increase W by a minimal amount */
   2773       if ( Vx < Vy )
   2774         Vx++;
   2775       else
   2776         Vy++;
   2777 
   2778       W = Vx * Vx + Vy * Vy;
   2779     }
   2780 
   2781     while ( W >= 0x10004000L )
   2782     {
   2783       /* We need to decrease W by a minimal amount */
   2784       if ( Vx < Vy )
   2785         Vx--;
   2786       else
   2787         Vy--;
   2788 
   2789       W = Vx * Vx + Vy * Vy;
   2790     }
   2791 
   2792     /* Note that in various cases, we can only  */
   2793     /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
   2794 
   2795     if ( S1 )
   2796       Vx = -Vx;
   2797 
   2798     if ( S2 )
   2799       Vy = -Vy;
   2800 
   2801     R->x = (FT_F2Dot14)Vx;   /* Type conversion */
   2802     R->y = (FT_F2Dot14)Vy;   /* Type conversion */
   2803 
   2804     return SUCCESS;
   2805   }
   2806 
   2807 
   2808   /*************************************************************************/
   2809   /*                                                                       */
   2810   /* Here we start with the implementation of the various opcodes.         */
   2811   /*                                                                       */
   2812   /*************************************************************************/
   2813 
   2814 
   2815   static FT_Bool
   2816   Ins_SxVTL( EXEC_OP_ FT_UShort       aIdx1,
   2817                       FT_UShort       aIdx2,
   2818                       FT_Int          aOpc,
   2819                       FT_UnitVector*  Vec )
   2820   {
   2821     FT_Long     A, B, C;
   2822     FT_Vector*  p1;
   2823     FT_Vector*  p2;
   2824 
   2825 
   2826     if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
   2827          BOUNDS( aIdx2, CUR.zp1.n_points ) )
   2828     {
   2829       if ( CUR.pedantic_hinting )
   2830         CUR.error = TT_Err_Invalid_Reference;
   2831       return FAILURE;
   2832     }
   2833 
   2834     p1 = CUR.zp1.cur + aIdx2;
   2835     p2 = CUR.zp2.cur + aIdx1;
   2836 
   2837     A = p1->x - p2->x;
   2838     B = p1->y - p2->y;
   2839 
   2840     if ( ( aOpc & 1 ) != 0 )
   2841     {
   2842       C =  B;   /* counter clockwise rotation */
   2843       B =  A;
   2844       A = -C;
   2845     }
   2846 
   2847     NORMalize( A, B, Vec );
   2848 
   2849     return SUCCESS;
   2850   }
   2851 
   2852 
   2853   /* When not using the big switch statements, the interpreter uses a */
   2854   /* call table defined later below in this source.  Each opcode must */
   2855   /* thus have a corresponding function, even trivial ones.           */
   2856   /*                                                                  */
   2857   /* They are all defined there.                                      */
   2858 
   2859 #define DO_SVTCA                            \
   2860   {                                         \
   2861     FT_Short  A, B;                         \
   2862                                             \
   2863                                             \
   2864     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
   2865     B = A ^ (FT_Short)0x4000;               \
   2866                                             \
   2867     CUR.GS.freeVector.x = A;                \
   2868     CUR.GS.projVector.x = A;                \
   2869     CUR.GS.dualVector.x = A;                \
   2870                                             \
   2871     CUR.GS.freeVector.y = B;                \
   2872     CUR.GS.projVector.y = B;                \
   2873     CUR.GS.dualVector.y = B;                \
   2874                                             \
   2875     COMPUTE_Funcs();                        \
   2876   }
   2877 
   2878 
   2879 #define DO_SPVTCA                           \
   2880   {                                         \
   2881     FT_Short  A, B;                         \
   2882                                             \
   2883                                             \
   2884     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
   2885     B = A ^ (FT_Short)0x4000;               \
   2886                                             \
   2887     CUR.GS.projVector.x = A;                \
   2888     CUR.GS.dualVector.x = A;                \
   2889                                             \
   2890     CUR.GS.projVector.y = B;                \
   2891     CUR.GS.dualVector.y = B;                \
   2892                                             \
   2893     GUESS_VECTOR( freeVector );             \
   2894                                             \
   2895     COMPUTE_Funcs();                        \
   2896   }
   2897 
   2898 
   2899 #define DO_SFVTCA                           \
   2900   {                                         \
   2901     FT_Short  A, B;                         \
   2902                                             \
   2903                                             \
   2904     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
   2905     B = A ^ (FT_Short)0x4000;               \
   2906                                             \
   2907     CUR.GS.freeVector.x = A;                \
   2908     CUR.GS.freeVector.y = B;                \
   2909                                             \
   2910     GUESS_VECTOR( projVector );             \
   2911                                             \
   2912     COMPUTE_Funcs();                        \
   2913   }
   2914 
   2915 
   2916 #define DO_SPVTL                                      \
   2917     if ( INS_SxVTL( (FT_UShort)args[1],               \
   2918                     (FT_UShort)args[0],               \
   2919                     CUR.opcode,                       \
   2920                     &CUR.GS.projVector ) == SUCCESS ) \
   2921     {                                                 \
   2922       CUR.GS.dualVector = CUR.GS.projVector;          \
   2923       GUESS_VECTOR( freeVector );                     \
   2924       COMPUTE_Funcs();                                \
   2925     }
   2926 
   2927 
   2928 #define DO_SFVTL                                      \
   2929     if ( INS_SxVTL( (FT_UShort)args[1],               \
   2930                     (FT_UShort)args[0],               \
   2931                     CUR.opcode,                       \
   2932                     &CUR.GS.freeVector ) == SUCCESS ) \
   2933     {                                                 \
   2934       GUESS_VECTOR( projVector );                     \
   2935       COMPUTE_Funcs();                                \
   2936     }
   2937 
   2938 
   2939 #define DO_SFVTPV                          \
   2940     GUESS_VECTOR( projVector );            \
   2941     CUR.GS.freeVector = CUR.GS.projVector; \
   2942     COMPUTE_Funcs();
   2943 
   2944 
   2945 #define DO_SPVFS                                \
   2946   {                                             \
   2947     FT_Short  S;                                \
   2948     FT_Long   X, Y;                             \
   2949                                                 \
   2950                                                 \
   2951     /* Only use low 16bits, then sign extend */ \
   2952     S = (FT_Short)args[1];                      \
   2953     Y = (FT_Long)S;                             \
   2954     S = (FT_Short)args[0];                      \
   2955     X = (FT_Long)S;                             \
   2956                                                 \
   2957     NORMalize( X, Y, &CUR.GS.projVector );      \
   2958                                                 \
   2959     CUR.GS.dualVector = CUR.GS.projVector;      \
   2960     GUESS_VECTOR( freeVector );                 \
   2961     COMPUTE_Funcs();                            \
   2962   }
   2963 
   2964 
   2965 #define DO_SFVFS                                \
   2966   {                                             \
   2967     FT_Short  S;                                \
   2968     FT_Long   X, Y;                             \
   2969                                                 \
   2970                                                 \
   2971     /* Only use low 16bits, then sign extend */ \
   2972     S = (FT_Short)args[1];                      \
   2973     Y = (FT_Long)S;                             \
   2974     S = (FT_Short)args[0];                      \
   2975     X = S;                                      \
   2976                                                 \
   2977     NORMalize( X, Y, &CUR.GS.freeVector );      \
   2978     GUESS_VECTOR( projVector );                 \
   2979     COMPUTE_Funcs();                            \
   2980   }
   2981 
   2982 
   2983 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   2984 #define DO_GPV                                   \
   2985     if ( CUR.face->unpatented_hinting )          \
   2986     {                                            \
   2987       args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
   2988       args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
   2989     }                                            \
   2990     else                                         \
   2991     {                                            \
   2992       args[0] = CUR.GS.projVector.x;             \
   2993       args[1] = CUR.GS.projVector.y;             \
   2994     }
   2995 #else
   2996 #define DO_GPV                                   \
   2997     args[0] = CUR.GS.projVector.x;               \
   2998     args[1] = CUR.GS.projVector.y;
   2999 #endif
   3000 
   3001 
   3002 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   3003 #define DO_GFV                                   \
   3004     if ( CUR.face->unpatented_hinting )          \
   3005     {                                            \
   3006       args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
   3007       args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
   3008     }                                            \
   3009     else                                         \
   3010     {                                            \
   3011       args[0] = CUR.GS.freeVector.x;             \
   3012       args[1] = CUR.GS.freeVector.y;             \
   3013     }
   3014 #else
   3015 #define DO_GFV                                   \
   3016     args[0] = CUR.GS.freeVector.x;               \
   3017     args[1] = CUR.GS.freeVector.y;
   3018 #endif
   3019 
   3020 
   3021 #define DO_SRP0                      \
   3022     CUR.GS.rp0 = (FT_UShort)args[0];
   3023 
   3024 
   3025 #define DO_SRP1                      \
   3026     CUR.GS.rp1 = (FT_UShort)args[0];
   3027 
   3028 
   3029 #define DO_SRP2                      \
   3030     CUR.GS.rp2 = (FT_UShort)args[0];
   3031 
   3032 
   3033 #define DO_RTHG                                         \
   3034     CUR.GS.round_state = TT_Round_To_Half_Grid;         \
   3035     CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
   3036 
   3037 
   3038 #define DO_RTG                                     \
   3039     CUR.GS.round_state = TT_Round_To_Grid;         \
   3040     CUR.func_round = (TT_Round_Func)Round_To_Grid;
   3041 
   3042 
   3043 #define DO_RTDG                                           \
   3044     CUR.GS.round_state = TT_Round_To_Double_Grid;         \
   3045     CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
   3046 
   3047 
   3048 #define DO_RUTG                                       \
   3049     CUR.GS.round_state = TT_Round_Up_To_Grid;         \
   3050     CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
   3051 
   3052 
   3053 #define DO_RDTG                                         \
   3054     CUR.GS.round_state = TT_Round_Down_To_Grid;         \
   3055     CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
   3056 
   3057 
   3058 #define DO_ROFF                                 \
   3059     CUR.GS.round_state = TT_Round_Off;          \
   3060     CUR.func_round = (TT_Round_Func)Round_None;
   3061 
   3062 
   3063 #define DO_SROUND                                \
   3064     SET_SuperRound( 0x4000, args[0] );           \
   3065     CUR.GS.round_state = TT_Round_Super;         \
   3066     CUR.func_round = (TT_Round_Func)Round_Super;
   3067 
   3068 
   3069 #define DO_S45ROUND                                 \
   3070     SET_SuperRound( 0x2D41, args[0] );              \
   3071     CUR.GS.round_state = TT_Round_Super_45;         \
   3072     CUR.func_round = (TT_Round_Func)Round_Super_45;
   3073 
   3074 
   3075 #define DO_SLOOP                       \
   3076     if ( args[0] < 0 )                 \
   3077       CUR.error = TT_Err_Bad_Argument; \
   3078     else                               \
   3079       CUR.GS.loop = args[0];
   3080 
   3081 
   3082 #define DO_SMD                         \
   3083     CUR.GS.minimum_distance = args[0];
   3084 
   3085 
   3086 #define DO_SCVTCI                                     \
   3087     CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
   3088 
   3089 
   3090 #define DO_SSWCI                                     \
   3091     CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
   3092 
   3093 
   3094     /* XXX: UNDOCUMENTED! or bug in the Windows engine?   */
   3095     /*                                                    */
   3096     /*      It seems that the value that is read here is  */
   3097     /*      expressed in 16.16 format rather than in font */
   3098     /*      units.                                        */
   3099     /*                                                    */
   3100 #define DO_SSW                                                 \
   3101     CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
   3102 
   3103 
   3104 #define DO_FLIPON            \
   3105     CUR.GS.auto_flip = TRUE;
   3106 
   3107 
   3108 #define DO_FLIPOFF            \
   3109     CUR.GS.auto_flip = FALSE;
   3110 
   3111 
   3112 #define DO_SDB                             \
   3113     CUR.GS.delta_base = (FT_Short)args[0];
   3114 
   3115 
   3116 #define DO_SDS                              \
   3117     CUR.GS.delta_shift = (FT_Short)args[0];
   3118 
   3119 
   3120 #define DO_MD  /* nothing */
   3121 
   3122 
   3123 #define DO_MPPEM              \
   3124     args[0] = CURRENT_Ppem();
   3125 
   3126 
   3127   /* Note: The pointSize should be irrelevant in a given font program; */
   3128   /*       we thus decide to return only the ppem.                     */
   3129 #if 0
   3130 
   3131 #define DO_MPS                       \
   3132     args[0] = CUR.metrics.pointSize;
   3133 
   3134 #else
   3135 
   3136 #define DO_MPS                \
   3137     args[0] = CURRENT_Ppem();
   3138 
   3139 #endif /* 0 */
   3140 
   3141 
   3142 #define DO_DUP         \
   3143     args[1] = args[0];
   3144 
   3145 
   3146 #define DO_CLEAR     \
   3147     CUR.new_top = 0;
   3148 
   3149 
   3150 #define DO_SWAP        \
   3151   {                    \
   3152     FT_Long  L;        \
   3153                        \
   3154                        \
   3155     L       = args[0]; \
   3156     args[0] = args[1]; \
   3157     args[1] = L;       \
   3158   }
   3159 
   3160 
   3161 #define DO_DEPTH       \
   3162     args[0] = CUR.top;
   3163 
   3164 
   3165 #define DO_CINDEX                           \
   3166   {                                         \
   3167     FT_Long  L;                             \
   3168                                             \
   3169                                             \
   3170     L = args[0];                            \
   3171                                             \
   3172     if ( L <= 0 || L > CUR.args )           \
   3173       CUR.error = TT_Err_Invalid_Reference; \
   3174     else                                    \
   3175       args[0] = CUR.stack[CUR.args - L];    \
   3176   }
   3177 
   3178 
   3179 #define DO_JROT                          \
   3180     if ( args[1] != 0 )                  \
   3181     {                                    \
   3182       CUR.IP      += args[0];            \
   3183       if ( CUR.IP < 0 )                  \
   3184         CUR.error = TT_Err_Bad_Argument; \
   3185       CUR.step_ins = FALSE;              \
   3186     }
   3187 
   3188 
   3189 #define DO_JMPR                        \
   3190     CUR.IP      += args[0];            \
   3191     if ( CUR.IP < 0 )                  \
   3192       CUR.error = TT_Err_Bad_Argument; \
   3193     CUR.step_ins = FALSE;
   3194 
   3195 
   3196 #define DO_JROF                          \
   3197     if ( args[1] == 0 )                  \
   3198     {                                    \
   3199       CUR.IP      += args[0];            \
   3200       if ( CUR.IP < 0 )                  \
   3201         CUR.error = TT_Err_Bad_Argument; \
   3202       CUR.step_ins = FALSE;              \
   3203     }
   3204 
   3205 
   3206 #define DO_LT                        \
   3207     args[0] = ( args[0] < args[1] );
   3208 
   3209 
   3210 #define DO_LTEQ                       \
   3211     args[0] = ( args[0] <= args[1] );
   3212 
   3213 
   3214 #define DO_GT                        \
   3215     args[0] = ( args[0] > args[1] );
   3216 
   3217 
   3218 #define DO_GTEQ                       \
   3219     args[0] = ( args[0] >= args[1] );
   3220 
   3221 
   3222 #define DO_EQ                         \
   3223     args[0] = ( args[0] == args[1] );
   3224 
   3225 
   3226 #define DO_NEQ                        \
   3227     args[0] = ( args[0] != args[1] );
   3228 
   3229 
   3230 #define DO_ODD                                                  \
   3231     args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
   3232 
   3233 
   3234 #define DO_EVEN                                                \
   3235     args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
   3236 
   3237 
   3238 #define DO_AND                        \
   3239     args[0] = ( args[0] && args[1] );
   3240 
   3241 
   3242 #define DO_OR                         \
   3243     args[0] = ( args[0] || args[1] );
   3244 
   3245 
   3246 #define DO_NOT          \
   3247     args[0] = !args[0];
   3248 
   3249 
   3250 #define DO_ADD          \
   3251     args[0] += args[1];
   3252 
   3253 
   3254 #define DO_SUB          \
   3255     args[0] -= args[1];
   3256 
   3257 
   3258 #define DO_DIV                                               \
   3259     if ( args[1] == 0 )                                      \
   3260       CUR.error = TT_Err_Divide_By_Zero;                     \
   3261     else                                                     \
   3262       args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
   3263 
   3264 
   3265 #define DO_MUL                                    \
   3266     args[0] = TT_MULDIV( args[0], args[1], 64L );
   3267 
   3268 
   3269 #define DO_ABS                   \
   3270     args[0] = FT_ABS( args[0] );
   3271 
   3272 
   3273 #define DO_NEG          \
   3274     args[0] = -args[0];
   3275 
   3276 
   3277 #define DO_FLOOR    \
   3278     args[0] = FT_PIX_FLOOR( args[0] );
   3279 
   3280 
   3281 #define DO_CEILING                    \
   3282     args[0] = FT_PIX_CEIL( args[0] );
   3283 
   3284 
   3285 #define DO_RS                           \
   3286    {                                    \
   3287      FT_ULong  I = (FT_ULong)args[0];   \
   3288                                         \
   3289                                         \
   3290      if ( BOUNDSL( I, CUR.storeSize ) ) \
   3291      {                                  \
   3292        if ( CUR.pedantic_hinting )      \
   3293        {                                \
   3294          ARRAY_BOUND_ERROR;             \
   3295        }                                \
   3296        else                             \
   3297          args[0] = 0;                   \
   3298      }                                  \
   3299      else                               \
   3300        args[0] = CUR.storage[I];        \
   3301    }
   3302 
   3303 
   3304 #define DO_WS                           \
   3305    {                                    \
   3306      FT_ULong  I = (FT_ULong)args[0];   \
   3307                                         \
   3308                                         \
   3309      if ( BOUNDSL( I, CUR.storeSize ) ) \
   3310      {                                  \
   3311        if ( CUR.pedantic_hinting )      \
   3312        {                                \
   3313          ARRAY_BOUND_ERROR;             \
   3314        }                                \
   3315      }                                  \
   3316      else                               \
   3317        CUR.storage[I] = args[1];        \
   3318    }
   3319 
   3320 
   3321 #define DO_RCVT                          \
   3322    {                                     \
   3323      FT_ULong  I = (FT_ULong)args[0];    \
   3324                                          \
   3325                                          \
   3326      if ( BOUNDSL( I, CUR.cvtSize ) )    \
   3327      {                                   \
   3328        if ( CUR.pedantic_hinting )       \
   3329        {                                 \
   3330          ARRAY_BOUND_ERROR;              \
   3331        }                                 \
   3332        else                              \
   3333          args[0] = 0;                    \
   3334      }                                   \
   3335      else                                \
   3336        args[0] = CUR_Func_read_cvt( I ); \
   3337    }
   3338 
   3339 
   3340 #define DO_WCVTP                         \
   3341    {                                     \
   3342      FT_ULong  I = (FT_ULong)args[0];    \
   3343                                          \
   3344                                          \
   3345      if ( BOUNDSL( I, CUR.cvtSize ) )    \
   3346      {                                   \
   3347        if ( CUR.pedantic_hinting )       \
   3348        {                                 \
   3349          ARRAY_BOUND_ERROR;              \
   3350        }                                 \
   3351      }                                   \
   3352      else                                \
   3353        CUR_Func_write_cvt( I, args[1] ); \
   3354    }
   3355 
   3356 
   3357 #define DO_WCVTF                                                \
   3358    {                                                            \
   3359      FT_ULong  I = (FT_ULong)args[0];                           \
   3360                                                                 \
   3361                                                                 \
   3362      if ( BOUNDSL( I, CUR.cvtSize ) )                           \
   3363      {                                                          \
   3364        if ( CUR.pedantic_hinting )                              \
   3365        {                                                        \
   3366          ARRAY_BOUND_ERROR;                                     \
   3367        }                                                        \
   3368      }                                                          \
   3369      else                                                       \
   3370        CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
   3371    }
   3372 
   3373 
   3374 #define DO_DEBUG                     \
   3375     CUR.error = TT_Err_Debug_OpCode;
   3376 
   3377 
   3378 #define DO_ROUND                                                   \
   3379     args[0] = CUR_Func_round(                                      \
   3380                 args[0],                                           \
   3381                 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
   3382 
   3383 
   3384 #define DO_NROUND                                                            \
   3385     args[0] = ROUND_None( args[0],                                           \
   3386                           CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
   3387 
   3388 
   3389 #define DO_MAX               \
   3390     if ( args[1] > args[0] ) \
   3391       args[0] = args[1];
   3392 
   3393 
   3394 #define DO_MIN               \
   3395     if ( args[1] < args[0] ) \
   3396       args[0] = args[1];
   3397 
   3398 
   3399 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
   3400 
   3401 
   3402 #undef  ARRAY_BOUND_ERROR
   3403 #define ARRAY_BOUND_ERROR                   \
   3404     {                                       \
   3405       CUR.error = TT_Err_Invalid_Reference; \
   3406       return;                               \
   3407     }
   3408 
   3409 
   3410   /*************************************************************************/
   3411   /*                                                                       */
   3412   /* SVTCA[a]:     Set (F and P) Vectors to Coordinate Axis                */
   3413   /* Opcode range: 0x00-0x01                                               */
   3414   /* Stack:        -->                                                     */
   3415   /*                                                                       */
   3416   static void
   3417   Ins_SVTCA( INS_ARG )
   3418   {
   3419     DO_SVTCA
   3420   }
   3421 
   3422 
   3423   /*************************************************************************/
   3424   /*                                                                       */
   3425   /* SPVTCA[a]:    Set PVector to Coordinate Axis                          */
   3426   /* Opcode range: 0x02-0x03                                               */
   3427   /* Stack:        -->                                                     */
   3428   /*                                                                       */
   3429   static void
   3430   Ins_SPVTCA( INS_ARG )
   3431   {
   3432     DO_SPVTCA
   3433   }
   3434 
   3435 
   3436   /*************************************************************************/
   3437   /*                                                                       */
   3438   /* SFVTCA[a]:    Set FVector to Coordinate Axis                          */
   3439   /* Opcode range: 0x04-0x05                                               */
   3440   /* Stack:        -->                                                     */
   3441   /*                                                                       */
   3442   static void
   3443   Ins_SFVTCA( INS_ARG )
   3444   {
   3445     DO_SFVTCA
   3446   }
   3447 
   3448 
   3449   /*************************************************************************/
   3450   /*                                                                       */
   3451   /* SPVTL[a]:     Set PVector To Line                                     */
   3452   /* Opcode range: 0x06-0x07                                               */
   3453   /* Stack:        uint32 uint32 -->                                       */
   3454   /*                                                                       */
   3455   static void
   3456   Ins_SPVTL( INS_ARG )
   3457   {
   3458     DO_SPVTL
   3459   }
   3460 
   3461 
   3462   /*************************************************************************/
   3463   /*                                                                       */
   3464   /* SFVTL[a]:     Set FVector To Line                                     */
   3465   /* Opcode range: 0x08-0x09                                               */
   3466   /* Stack:        uint32 uint32 -->                                       */
   3467   /*                                                                       */
   3468   static void
   3469   Ins_SFVTL( INS_ARG )
   3470   {
   3471     DO_SFVTL
   3472   }
   3473 
   3474 
   3475   /*************************************************************************/
   3476   /*                                                                       */
   3477   /* SFVTPV[]:     Set FVector To PVector                                  */
   3478   /* Opcode range: 0x0E                                                    */
   3479   /* Stack:        -->                                                     */
   3480   /*                                                                       */
   3481   static void
   3482   Ins_SFVTPV( INS_ARG )
   3483   {
   3484     DO_SFVTPV
   3485   }
   3486 
   3487 
   3488   /*************************************************************************/
   3489   /*                                                                       */
   3490   /* SPVFS[]:      Set PVector From Stack                                  */
   3491   /* Opcode range: 0x0A                                                    */
   3492   /* Stack:        f2.14 f2.14 -->                                         */
   3493   /*                                                                       */
   3494   static void
   3495   Ins_SPVFS( INS_ARG )
   3496   {
   3497     DO_SPVFS
   3498   }
   3499 
   3500 
   3501   /*************************************************************************/
   3502   /*                                                                       */
   3503   /* SFVFS[]:      Set FVector From Stack                                  */
   3504   /* Opcode range: 0x0B                                                    */
   3505   /* Stack:        f2.14 f2.14 -->                                         */
   3506   /*                                                                       */
   3507   static void
   3508   Ins_SFVFS( INS_ARG )
   3509   {
   3510     DO_SFVFS
   3511   }
   3512 
   3513 
   3514   /*************************************************************************/
   3515   /*                                                                       */
   3516   /* GPV[]:        Get Projection Vector                                   */
   3517   /* Opcode range: 0x0C                                                    */
   3518   /* Stack:        ef2.14 --> ef2.14                                       */
   3519   /*                                                                       */
   3520   static void
   3521   Ins_GPV( INS_ARG )
   3522   {
   3523     DO_GPV
   3524   }
   3525 
   3526 
   3527   /*************************************************************************/
   3528   /* GFV[]:        Get Freedom Vector                                      */
   3529   /* Opcode range: 0x0D                                                    */
   3530   /* Stack:        ef2.14 --> ef2.14                                       */
   3531   /*                                                                       */
   3532   static void
   3533   Ins_GFV( INS_ARG )
   3534   {
   3535     DO_GFV
   3536   }
   3537 
   3538 
   3539   /*************************************************************************/
   3540   /*                                                                       */
   3541   /* SRP0[]:       Set Reference Point 0                                   */
   3542   /* Opcode range: 0x10                                                    */
   3543   /* Stack:        uint32 -->                                              */
   3544   /*                                                                       */
   3545   static void
   3546   Ins_SRP0( INS_ARG )
   3547   {
   3548     DO_SRP0
   3549   }
   3550 
   3551 
   3552   /*************************************************************************/
   3553   /*                                                                       */
   3554   /* SRP1[]:       Set Reference Point 1                                   */
   3555   /* Opcode range: 0x11                                                    */
   3556   /* Stack:        uint32 -->                                              */
   3557   /*                                                                       */
   3558   static void
   3559   Ins_SRP1( INS_ARG )
   3560   {
   3561     DO_SRP1
   3562   }
   3563 
   3564 
   3565   /*************************************************************************/
   3566   /*                                                                       */
   3567   /* SRP2[]:       Set Reference Point 2                                   */
   3568   /* Opcode range: 0x12                                                    */
   3569   /* Stack:        uint32 -->                                              */
   3570   /*                                                                       */
   3571   static void
   3572   Ins_SRP2( INS_ARG )
   3573   {
   3574     DO_SRP2
   3575   }
   3576 
   3577 
   3578   /*************************************************************************/
   3579   /*                                                                       */
   3580   /* RTHG[]:       Round To Half Grid                                      */
   3581   /* Opcode range: 0x19                                                    */
   3582   /* Stack:        -->                                                     */
   3583   /*                                                                       */
   3584   static void
   3585   Ins_RTHG( INS_ARG )
   3586   {
   3587     DO_RTHG
   3588   }
   3589 
   3590 
   3591   /*************************************************************************/
   3592   /*                                                                       */
   3593   /* RTG[]:        Round To Grid                                           */
   3594   /* Opcode range: 0x18                                                    */
   3595   /* Stack:        -->                                                     */
   3596   /*                                                                       */
   3597   static void
   3598   Ins_RTG( INS_ARG )
   3599   {
   3600     DO_RTG
   3601   }
   3602 
   3603 
   3604   /*************************************************************************/
   3605   /* RTDG[]:       Round To Double Grid                                    */
   3606   /* Opcode range: 0x3D                                                    */
   3607   /* Stack:        -->                                                     */
   3608   /*                                                                       */
   3609   static void
   3610   Ins_RTDG( INS_ARG )
   3611   {
   3612     DO_RTDG
   3613   }
   3614 
   3615 
   3616   /*************************************************************************/
   3617   /* RUTG[]:       Round Up To Grid                                        */
   3618   /* Opcode range: 0x7C                                                    */
   3619   /* Stack:        -->                                                     */
   3620   /*                                                                       */
   3621   static void
   3622   Ins_RUTG( INS_ARG )
   3623   {
   3624     DO_RUTG
   3625   }
   3626 
   3627 
   3628   /*************************************************************************/
   3629   /*                                                                       */
   3630   /* RDTG[]:       Round Down To Grid                                      */
   3631   /* Opcode range: 0x7D                                                    */
   3632   /* Stack:        -->                                                     */
   3633   /*                                                                       */
   3634   static void
   3635   Ins_RDTG( INS_ARG )
   3636   {
   3637     DO_RDTG
   3638   }
   3639 
   3640 
   3641   /*************************************************************************/
   3642   /*                                                                       */
   3643   /* ROFF[]:       Round OFF                                               */
   3644   /* Opcode range: 0x7A                                                    */
   3645   /* Stack:        -->                                                     */
   3646   /*                                                                       */
   3647   static void
   3648   Ins_ROFF( INS_ARG )
   3649   {
   3650     DO_ROFF
   3651   }
   3652 
   3653 
   3654   /*************************************************************************/
   3655   /*                                                                       */
   3656   /* SROUND[]:     Super ROUND                                             */
   3657   /* Opcode range: 0x76                                                    */
   3658   /* Stack:        Eint8 -->                                               */
   3659   /*                                                                       */
   3660   static void
   3661   Ins_SROUND( INS_ARG )
   3662   {
   3663     DO_SROUND
   3664   }
   3665 
   3666 
   3667   /*************************************************************************/
   3668   /*                                                                       */
   3669   /* S45ROUND[]:   Super ROUND 45 degrees                                  */
   3670   /* Opcode range: 0x77                                                    */
   3671   /* Stack:        uint32 -->                                              */
   3672   /*                                                                       */
   3673   static void
   3674   Ins_S45ROUND( INS_ARG )
   3675   {
   3676     DO_S45ROUND
   3677   }
   3678 
   3679 
   3680   /*************************************************************************/
   3681   /*                                                                       */
   3682   /* SLOOP[]:      Set LOOP variable                                       */
   3683   /* Opcode range: 0x17                                                    */
   3684   /* Stack:        int32? -->                                              */
   3685   /*                                                                       */
   3686   static void
   3687   Ins_SLOOP( INS_ARG )
   3688   {
   3689     DO_SLOOP
   3690   }
   3691 
   3692 
   3693   /*************************************************************************/
   3694   /*                                                                       */
   3695   /* SMD[]:        Set Minimum Distance                                    */
   3696   /* Opcode range: 0x1A                                                    */
   3697   /* Stack:        f26.6 -->                                               */
   3698   /*                                                                       */
   3699   static void
   3700   Ins_SMD( INS_ARG )
   3701   {
   3702     DO_SMD
   3703   }
   3704 
   3705 
   3706   /*************************************************************************/
   3707   /*                                                                       */
   3708   /* SCVTCI[]:     Set Control Value Table Cut In                          */
   3709   /* Opcode range: 0x1D                                                    */
   3710   /* Stack:        f26.6 -->                                               */
   3711   /*                                                                       */
   3712   static void
   3713   Ins_SCVTCI( INS_ARG )
   3714   {
   3715     DO_SCVTCI
   3716   }
   3717 
   3718 
   3719   /*************************************************************************/
   3720   /*                                                                       */
   3721   /* SSWCI[]:      Set Single Width Cut In                                 */
   3722   /* Opcode range: 0x1E                                                    */
   3723   /* Stack:        f26.6 -->                                               */
   3724   /*                                                                       */
   3725   static void
   3726   Ins_SSWCI( INS_ARG )
   3727   {
   3728     DO_SSWCI
   3729   }
   3730 
   3731 
   3732   /*************************************************************************/
   3733   /*                                                                       */
   3734   /* SSW[]:        Set Single Width                                        */
   3735   /* Opcode range: 0x1F                                                    */
   3736   /* Stack:        int32? -->                                              */
   3737   /*                                                                       */
   3738   static void
   3739   Ins_SSW( INS_ARG )
   3740   {
   3741     DO_SSW
   3742   }
   3743 
   3744 
   3745   /*************************************************************************/
   3746   /*                                                                       */
   3747   /* FLIPON[]:     Set auto-FLIP to ON                                     */
   3748   /* Opcode range: 0x4D                                                    */
   3749   /* Stack:        -->                                                     */
   3750   /*                                                                       */
   3751   static void
   3752   Ins_FLIPON( INS_ARG )
   3753   {
   3754     DO_FLIPON
   3755   }
   3756 
   3757 
   3758   /*************************************************************************/
   3759   /*                                                                       */
   3760   /* FLIPOFF[]:    Set auto-FLIP to OFF                                    */
   3761   /* Opcode range: 0x4E                                                    */
   3762   /* Stack: -->                                                            */
   3763   /*                                                                       */
   3764   static void
   3765   Ins_FLIPOFF( INS_ARG )
   3766   {
   3767     DO_FLIPOFF
   3768   }
   3769 
   3770 
   3771   /*************************************************************************/
   3772   /*                                                                       */
   3773   /* SANGW[]:      Set ANGle Weight                                        */
   3774   /* Opcode range: 0x7E                                                    */
   3775   /* Stack:        uint32 -->                                              */
   3776   /*                                                                       */
   3777   static void
   3778   Ins_SANGW( INS_ARG )
   3779   {
   3780     /* instruction not supported anymore */
   3781   }
   3782 
   3783 
   3784   /*************************************************************************/
   3785   /*                                                                       */
   3786   /* SDB[]:        Set Delta Base                                          */
   3787   /* Opcode range: 0x5E                                                    */
   3788   /* Stack:        uint32 -->                                              */
   3789   /*                                                                       */
   3790   static void
   3791   Ins_SDB( INS_ARG )
   3792   {
   3793     DO_SDB
   3794   }
   3795 
   3796 
   3797   /*************************************************************************/
   3798   /*                                                                       */
   3799   /* SDS[]:        Set Delta Shift                                         */
   3800   /* Opcode range: 0x5F                                                    */
   3801   /* Stack:        uint32 -->                                              */
   3802   /*                                                                       */
   3803   static void
   3804   Ins_SDS( INS_ARG )
   3805   {
   3806     DO_SDS
   3807   }
   3808 
   3809 
   3810   /*************************************************************************/
   3811   /*                                                                       */
   3812   /* MPPEM[]:      Measure Pixel Per EM                                    */
   3813   /* Opcode range: 0x4B                                                    */
   3814   /* Stack:        --> Euint16                                             */
   3815   /*                                                                       */
   3816   static void
   3817   Ins_MPPEM( INS_ARG )
   3818   {
   3819     DO_MPPEM
   3820   }
   3821 
   3822 
   3823   /*************************************************************************/
   3824   /*                                                                       */
   3825   /* MPS[]:        Measure Point Size                                      */
   3826   /* Opcode range: 0x4C                                                    */
   3827   /* Stack:        --> Euint16                                             */
   3828   /*                                                                       */
   3829   static void
   3830   Ins_MPS( INS_ARG )
   3831   {
   3832     DO_MPS
   3833   }
   3834 
   3835 
   3836   /*************************************************************************/
   3837   /*                                                                       */
   3838   /* DUP[]:        DUPlicate the top stack's element                       */
   3839   /* Opcode range: 0x20                                                    */
   3840   /* Stack:        StkElt --> StkElt StkElt                                */
   3841   /*                                                                       */
   3842   static void
   3843   Ins_DUP( INS_ARG )
   3844   {
   3845     DO_DUP
   3846   }
   3847 
   3848 
   3849   /*************************************************************************/
   3850   /*                                                                       */
   3851   /* POP[]:        POP the stack's top element                             */
   3852   /* Opcode range: 0x21                                                    */
   3853   /* Stack:        StkElt -->                                              */
   3854   /*                                                                       */
   3855   static void
   3856   Ins_POP( INS_ARG )
   3857   {
   3858     /* nothing to do */
   3859   }
   3860 
   3861 
   3862   /*************************************************************************/
   3863   /*                                                                       */
   3864   /* CLEAR[]:      CLEAR the entire stack                                  */
   3865   /* Opcode range: 0x22                                                    */
   3866   /* Stack:        StkElt... -->                                           */
   3867   /*                                                                       */
   3868   static void
   3869   Ins_CLEAR( INS_ARG )
   3870   {
   3871     DO_CLEAR
   3872   }
   3873 
   3874 
   3875   /*************************************************************************/
   3876   /*                                                                       */
   3877   /* SWAP[]:       SWAP the stack's top two elements                       */
   3878   /* Opcode range: 0x23                                                    */
   3879   /* Stack:        2 * StkElt --> 2 * StkElt                               */
   3880   /*                                                                       */
   3881   static void
   3882   Ins_SWAP( INS_ARG )
   3883   {
   3884     DO_SWAP
   3885   }
   3886 
   3887 
   3888   /*************************************************************************/
   3889   /*                                                                       */
   3890   /* DEPTH[]:      return the stack DEPTH                                  */
   3891   /* Opcode range: 0x24                                                    */
   3892   /* Stack:        --> uint32                                              */
   3893   /*                                                                       */
   3894   static void
   3895   Ins_DEPTH( INS_ARG )
   3896   {
   3897     DO_DEPTH
   3898   }
   3899 
   3900 
   3901   /*************************************************************************/
   3902   /*                                                                       */
   3903   /* CINDEX[]:     Copy INDEXed element                                    */
   3904   /* Opcode range: 0x25                                                    */
   3905   /* Stack:        int32 --> StkElt                                        */
   3906   /*                                                                       */
   3907   static void
   3908   Ins_CINDEX( INS_ARG )
   3909   {
   3910     DO_CINDEX
   3911   }
   3912 
   3913 
   3914   /*************************************************************************/
   3915   /*                                                                       */
   3916   /* EIF[]:        End IF                                                  */
   3917   /* Opcode range: 0x59                                                    */
   3918   /* Stack:        -->                                                     */
   3919   /*                                                                       */
   3920   static void
   3921   Ins_EIF( INS_ARG )
   3922   {
   3923     /* nothing to do */
   3924   }
   3925 
   3926 
   3927   /*************************************************************************/
   3928   /*                                                                       */
   3929   /* JROT[]:       Jump Relative On True                                   */
   3930   /* Opcode range: 0x78                                                    */
   3931   /* Stack:        StkElt int32 -->                                        */
   3932   /*                                                                       */
   3933   static void
   3934   Ins_JROT( INS_ARG )
   3935   {
   3936     DO_JROT
   3937   }
   3938 
   3939 
   3940   /*************************************************************************/
   3941   /*                                                                       */
   3942   /* JMPR[]:       JuMP Relative                                           */
   3943   /* Opcode range: 0x1C                                                    */
   3944   /* Stack:        int32 -->                                               */
   3945   /*                                                                       */
   3946   static void
   3947   Ins_JMPR( INS_ARG )
   3948   {
   3949     DO_JMPR
   3950   }
   3951 
   3952 
   3953   /*************************************************************************/
   3954   /*                                                                       */
   3955   /* JROF[]:       Jump Relative On False                                  */
   3956   /* Opcode range: 0x79                                                    */
   3957   /* Stack:        StkElt int32 -->                                        */
   3958   /*                                                                       */
   3959   static void
   3960   Ins_JROF( INS_ARG )
   3961   {
   3962     DO_JROF
   3963   }
   3964 
   3965 
   3966   /*************************************************************************/
   3967   /*                                                                       */
   3968   /* LT[]:         Less Than                                               */
   3969   /* Opcode range: 0x50                                                    */
   3970   /* Stack:        int32? int32? --> bool                                  */
   3971   /*                                                                       */
   3972   static void
   3973   Ins_LT( INS_ARG )
   3974   {
   3975     DO_LT
   3976   }
   3977 
   3978 
   3979   /*************************************************************************/
   3980   /*                                                                       */
   3981   /* LTEQ[]:       Less Than or EQual                                      */
   3982   /* Opcode range: 0x51                                                    */
   3983   /* Stack:        int32? int32? --> bool                                  */
   3984   /*                                                                       */
   3985   static void
   3986   Ins_LTEQ( INS_ARG )
   3987   {
   3988     DO_LTEQ
   3989   }
   3990 
   3991 
   3992   /*************************************************************************/
   3993   /*                                                                       */
   3994   /* GT[]:         Greater Than                                            */
   3995   /* Opcode range: 0x52                                                    */
   3996   /* Stack:        int32? int32? --> bool                                  */
   3997   /*                                                                       */
   3998   static void
   3999   Ins_GT( INS_ARG )
   4000   {
   4001     DO_GT
   4002   }
   4003 
   4004 
   4005   /*************************************************************************/
   4006   /*                                                                       */
   4007   /* GTEQ[]:       Greater Than or EQual                                   */
   4008   /* Opcode range: 0x53                                                    */
   4009   /* Stack:        int32? int32? --> bool                                  */
   4010   /*                                                                       */
   4011   static void
   4012   Ins_GTEQ( INS_ARG )
   4013   {
   4014     DO_GTEQ
   4015   }
   4016 
   4017 
   4018   /*************************************************************************/
   4019   /*                                                                       */
   4020   /* EQ[]:         EQual                                                   */
   4021   /* Opcode range: 0x54                                                    */
   4022   /* Stack:        StkElt StkElt --> bool                                  */
   4023   /*                                                                       */
   4024   static void
   4025   Ins_EQ( INS_ARG )
   4026   {
   4027     DO_EQ
   4028   }
   4029 
   4030 
   4031   /*************************************************************************/
   4032   /*                                                                       */
   4033   /* NEQ[]:        Not EQual                                               */
   4034   /* Opcode range: 0x55                                                    */
   4035   /* Stack:        StkElt StkElt --> bool                                  */
   4036   /*                                                                       */
   4037   static void
   4038   Ins_NEQ( INS_ARG )
   4039   {
   4040     DO_NEQ
   4041   }
   4042 
   4043 
   4044   /*************************************************************************/
   4045   /*                                                                       */
   4046   /* ODD[]:        Is ODD                                                  */
   4047   /* Opcode range: 0x56                                                    */
   4048   /* Stack:        f26.6 --> bool                                          */
   4049   /*                                                                       */
   4050   static void
   4051   Ins_ODD( INS_ARG )
   4052   {
   4053     DO_ODD
   4054   }
   4055 
   4056 
   4057   /*************************************************************************/
   4058   /*                                                                       */
   4059   /* EVEN[]:       Is EVEN                                                 */
   4060   /* Opcode range: 0x57                                                    */
   4061   /* Stack:        f26.6 --> bool                                          */
   4062   /*                                                                       */
   4063   static void
   4064   Ins_EVEN( INS_ARG )
   4065   {
   4066     DO_EVEN
   4067   }
   4068 
   4069 
   4070   /*************************************************************************/
   4071   /*                                                                       */
   4072   /* AND[]:        logical AND                                             */
   4073   /* Opcode range: 0x5A                                                    */
   4074   /* Stack:        uint32 uint32 --> uint32                                */
   4075   /*                                                                       */
   4076   static void
   4077   Ins_AND( INS_ARG )
   4078   {
   4079     DO_AND
   4080   }
   4081 
   4082 
   4083   /*************************************************************************/
   4084   /*                                                                       */
   4085   /* OR[]:         logical OR                                              */
   4086   /* Opcode range: 0x5B                                                    */
   4087   /* Stack:        uint32 uint32 --> uint32                                */
   4088   /*                                                                       */
   4089   static void
   4090   Ins_OR( INS_ARG )
   4091   {
   4092     DO_OR
   4093   }
   4094 
   4095 
   4096   /*************************************************************************/
   4097   /*                                                                       */
   4098   /* NOT[]:        logical NOT                                             */
   4099   /* Opcode range: 0x5C                                                    */
   4100   /* Stack:        StkElt --> uint32                                       */
   4101   /*                                                                       */
   4102   static void
   4103   Ins_NOT( INS_ARG )
   4104   {
   4105     DO_NOT
   4106   }
   4107 
   4108 
   4109   /*************************************************************************/
   4110   /*                                                                       */
   4111   /* ADD[]:        ADD                                                     */
   4112   /* Opcode range: 0x60                                                    */
   4113   /* Stack:        f26.6 f26.6 --> f26.6                                   */
   4114   /*                                                                       */
   4115   static void
   4116   Ins_ADD( INS_ARG )
   4117   {
   4118     DO_ADD
   4119   }
   4120 
   4121 
   4122   /*************************************************************************/
   4123   /*                                                                       */
   4124   /* SUB[]:        SUBtract                                                */
   4125   /* Opcode range: 0x61                                                    */
   4126   /* Stack:        f26.6 f26.6 --> f26.6                                   */
   4127   /*                                                                       */
   4128   static void
   4129   Ins_SUB( INS_ARG )
   4130   {
   4131     DO_SUB
   4132   }
   4133 
   4134 
   4135   /*************************************************************************/
   4136   /*                                                                       */
   4137   /* DIV[]:        DIVide                                                  */
   4138   /* Opcode range: 0x62                                                    */
   4139   /* Stack:        f26.6 f26.6 --> f26.6                                   */
   4140   /*                                                                       */
   4141   static void
   4142   Ins_DIV( INS_ARG )
   4143   {
   4144     DO_DIV
   4145   }
   4146 
   4147 
   4148   /*************************************************************************/
   4149   /*                                                                       */
   4150   /* MUL[]:        MULtiply                                                */
   4151   /* Opcode range: 0x63                                                    */
   4152   /* Stack:        f26.6 f26.6 --> f26.6                                   */
   4153   /*                                                                       */
   4154   static void
   4155   Ins_MUL( INS_ARG )
   4156   {
   4157     DO_MUL
   4158   }
   4159 
   4160 
   4161   /*************************************************************************/
   4162   /*                                                                       */
   4163   /* ABS[]:        ABSolute value                                          */
   4164   /* Opcode range: 0x64                                                    */
   4165   /* Stack:        f26.6 --> f26.6                                         */
   4166   /*                                                                       */
   4167   static void
   4168   Ins_ABS( INS_ARG )
   4169   {
   4170     DO_ABS
   4171   }
   4172 
   4173 
   4174   /*************************************************************************/
   4175   /*                                                                       */
   4176   /* NEG[]:        NEGate                                                  */
   4177   /* Opcode range: 0x65                                                    */
   4178   /* Stack: f26.6 --> f26.6                                                */
   4179   /*                                                                       */
   4180   static void
   4181   Ins_NEG( INS_ARG )
   4182   {
   4183     DO_NEG
   4184   }
   4185 
   4186 
   4187   /*************************************************************************/
   4188   /*                                                                       */
   4189   /* FLOOR[]:      FLOOR                                                   */
   4190   /* Opcode range: 0x66                                                    */
   4191   /* Stack:        f26.6 --> f26.6                                         */
   4192   /*                                                                       */
   4193   static void
   4194   Ins_FLOOR( INS_ARG )
   4195   {
   4196     DO_FLOOR
   4197   }
   4198 
   4199 
   4200   /*************************************************************************/
   4201   /*                                                                       */
   4202   /* CEILING[]:    CEILING                                                 */
   4203   /* Opcode range: 0x67                                                    */
   4204   /* Stack:        f26.6 --> f26.6                                         */
   4205   /*                                                                       */
   4206   static void
   4207   Ins_CEILING( INS_ARG )
   4208   {
   4209     DO_CEILING
   4210   }
   4211 
   4212 
   4213   /*************************************************************************/
   4214   /*                                                                       */
   4215   /* RS[]:         Read Store                                              */
   4216   /* Opcode range: 0x43                                                    */
   4217   /* Stack:        uint32 --> uint32                                       */
   4218   /*                                                                       */
   4219   static void
   4220   Ins_RS( INS_ARG )
   4221   {
   4222     DO_RS
   4223   }
   4224 
   4225 
   4226   /*************************************************************************/
   4227   /*                                                                       */
   4228   /* WS[]:         Write Store                                             */
   4229   /* Opcode range: 0x42                                                    */
   4230   /* Stack:        uint32 uint32 -->                                       */
   4231   /*                                                                       */
   4232   static void
   4233   Ins_WS( INS_ARG )
   4234   {
   4235     DO_WS
   4236   }
   4237 
   4238 
   4239   /*************************************************************************/
   4240   /*                                                                       */
   4241   /* WCVTP[]:      Write CVT in Pixel units                                */
   4242   /* Opcode range: 0x44                                                    */
   4243   /* Stack:        f26.6 uint32 -->                                        */
   4244   /*                                                                       */
   4245   static void
   4246   Ins_WCVTP( INS_ARG )
   4247   {
   4248     DO_WCVTP
   4249   }
   4250 
   4251 
   4252   /*************************************************************************/
   4253   /*                                                                       */
   4254   /* WCVTF[]:      Write CVT in Funits                                     */
   4255   /* Opcode range: 0x70                                                    */
   4256   /* Stack:        uint32 uint32 -->                                       */
   4257   /*                                                                       */
   4258   static void
   4259   Ins_WCVTF( INS_ARG )
   4260   {
   4261     DO_WCVTF
   4262   }
   4263 
   4264 
   4265   /*************************************************************************/
   4266   /*                                                                       */
   4267   /* RCVT[]:       Read CVT                                                */
   4268   /* Opcode range: 0x45                                                    */
   4269   /* Stack:        uint32 --> f26.6                                        */
   4270   /*                                                                       */
   4271   static void
   4272   Ins_RCVT( INS_ARG )
   4273   {
   4274     DO_RCVT
   4275   }
   4276 
   4277 
   4278   /*************************************************************************/
   4279   /*                                                                       */
   4280   /* AA[]:         Adjust Angle                                            */
   4281   /* Opcode range: 0x7F                                                    */
   4282   /* Stack:        uint32 -->                                              */
   4283   /*                                                                       */
   4284   static void
   4285   Ins_AA( INS_ARG )
   4286   {
   4287     /* intentionally no longer supported */
   4288   }
   4289 
   4290 
   4291   /*************************************************************************/
   4292   /*                                                                       */
   4293   /* DEBUG[]:      DEBUG.  Unsupported.                                    */
   4294   /* Opcode range: 0x4F                                                    */
   4295   /* Stack:        uint32 -->                                              */
   4296   /*                                                                       */
   4297   /* Note: The original instruction pops a value from the stack.           */
   4298   /*                                                                       */
   4299   static void
   4300   Ins_DEBUG( INS_ARG )
   4301   {
   4302     DO_DEBUG
   4303   }
   4304 
   4305 
   4306   /*************************************************************************/
   4307   /*                                                                       */
   4308   /* ROUND[ab]:    ROUND value                                             */
   4309   /* Opcode range: 0x68-0x6B                                               */
   4310   /* Stack:        f26.6 --> f26.6                                         */
   4311   /*                                                                       */
   4312   static void
   4313   Ins_ROUND( INS_ARG )
   4314   {
   4315     DO_ROUND
   4316   }
   4317 
   4318 
   4319   /*************************************************************************/
   4320   /*                                                                       */
   4321   /* NROUND[ab]:   No ROUNDing of value                                    */
   4322   /* Opcode range: 0x6C-0x6F                                               */
   4323   /* Stack:        f26.6 --> f26.6                                         */
   4324   /*                                                                       */
   4325   static void
   4326   Ins_NROUND( INS_ARG )
   4327   {
   4328     DO_NROUND
   4329   }
   4330 
   4331 
   4332   /*************************************************************************/
   4333   /*                                                                       */
   4334   /* MAX[]:        MAXimum                                                 */
   4335   /* Opcode range: 0x68                                                    */
   4336   /* Stack:        int32? int32? --> int32                                 */
   4337   /*                                                                       */
   4338   static void
   4339   Ins_MAX( INS_ARG )
   4340   {
   4341     DO_MAX
   4342   }
   4343 
   4344 
   4345   /*************************************************************************/
   4346   /*                                                                       */
   4347   /* MIN[]:        MINimum                                                 */
   4348   /* Opcode range: 0x69                                                    */
   4349   /* Stack:        int32? int32? --> int32                                 */
   4350   /*                                                                       */
   4351   static void
   4352   Ins_MIN( INS_ARG )
   4353   {
   4354     DO_MIN
   4355   }
   4356 
   4357 
   4358 #endif  /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
   4359 
   4360 
   4361   /*************************************************************************/
   4362   /*                                                                       */
   4363   /* The following functions are called as is within the switch statement. */
   4364   /*                                                                       */
   4365   /*************************************************************************/
   4366 
   4367 
   4368   /*************************************************************************/
   4369   /*                                                                       */
   4370   /* MINDEX[]:     Move INDEXed element                                    */
   4371   /* Opcode range: 0x26                                                    */
   4372   /* Stack:        int32? --> StkElt                                       */
   4373   /*                                                                       */
   4374   static void
   4375   Ins_MINDEX( INS_ARG )
   4376   {
   4377     FT_Long  L, K;
   4378 
   4379 
   4380     L = args[0];
   4381 
   4382     if ( L <= 0 || L > CUR.args )
   4383     {
   4384       CUR.error = TT_Err_Invalid_Reference;
   4385       return;
   4386     }
   4387 
   4388     K = CUR.stack[CUR.args - L];
   4389 
   4390     FT_ARRAY_MOVE( &CUR.stack[CUR.args - L    ],
   4391                    &CUR.stack[CUR.args - L + 1],
   4392                    ( L - 1 ) );
   4393 
   4394     CUR.stack[CUR.args - 1] = K;
   4395   }
   4396 
   4397 
   4398   /*************************************************************************/
   4399   /*                                                                       */
   4400   /* ROLL[]:       ROLL top three elements                                 */
   4401   /* Opcode range: 0x8A                                                    */
   4402   /* Stack:        3 * StkElt --> 3 * StkElt                               */
   4403   /*                                                                       */
   4404   static void
   4405   Ins_ROLL( INS_ARG )
   4406   {
   4407     FT_Long  A, B, C;
   4408 
   4409     FT_UNUSED_EXEC;
   4410 
   4411 
   4412     A = args[2];
   4413     B = args[1];
   4414     C = args[0];
   4415 
   4416     args[2] = C;
   4417     args[1] = A;
   4418     args[0] = B;
   4419   }
   4420 
   4421 
   4422   /*************************************************************************/
   4423   /*                                                                       */
   4424   /* MANAGING THE FLOW OF CONTROL                                          */
   4425   /*                                                                       */
   4426   /*   Instructions appear in the specification's order.                   */
   4427   /*                                                                       */
   4428   /*************************************************************************/
   4429 
   4430 
   4431   static FT_Bool
   4432   SkipCode( EXEC_OP )
   4433   {
   4434     CUR.IP += CUR.length;
   4435 
   4436     if ( CUR.IP < CUR.codeSize )
   4437     {
   4438       CUR.opcode = CUR.code[CUR.IP];
   4439 
   4440       CUR.length = opcode_length[CUR.opcode];
   4441       if ( CUR.length < 0 )
   4442       {
   4443         if ( CUR.IP + 1 > CUR.codeSize )
   4444           goto Fail_Overflow;
   4445         CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
   4446       }
   4447 
   4448       if ( CUR.IP + CUR.length <= CUR.codeSize )
   4449         return SUCCESS;
   4450     }
   4451 
   4452   Fail_Overflow:
   4453     CUR.error = TT_Err_Code_Overflow;
   4454     return FAILURE;
   4455   }
   4456 
   4457 
   4458   /*************************************************************************/
   4459   /*                                                                       */
   4460   /* IF[]:         IF test                                                 */
   4461   /* Opcode range: 0x58                                                    */
   4462   /* Stack:        StkElt -->                                              */
   4463   /*                                                                       */
   4464   static void
   4465   Ins_IF( INS_ARG )
   4466   {
   4467     FT_Int   nIfs;
   4468     FT_Bool  Out;
   4469 
   4470 
   4471     if ( args[0] != 0 )
   4472       return;
   4473 
   4474     nIfs = 1;
   4475     Out = 0;
   4476 
   4477     do
   4478     {
   4479       if ( SKIP_Code() == FAILURE )
   4480         return;
   4481 
   4482       switch ( CUR.opcode )
   4483       {
   4484       case 0x58:      /* IF */
   4485         nIfs++;
   4486         break;
   4487 
   4488       case 0x1B:      /* ELSE */
   4489         Out = FT_BOOL( nIfs == 1 );
   4490         break;
   4491 
   4492       case 0x59:      /* EIF */
   4493         nIfs--;
   4494         Out = FT_BOOL( nIfs == 0 );
   4495         break;
   4496       }
   4497     } while ( Out == 0 );
   4498   }
   4499 
   4500 
   4501   /*************************************************************************/
   4502   /*                                                                       */
   4503   /* ELSE[]:       ELSE                                                    */
   4504   /* Opcode range: 0x1B                                                    */
   4505   /* Stack:        -->                                                     */
   4506   /*                                                                       */
   4507   static void
   4508   Ins_ELSE( INS_ARG )
   4509   {
   4510     FT_Int  nIfs;
   4511 
   4512     FT_UNUSED_ARG;
   4513 
   4514 
   4515     nIfs = 1;
   4516 
   4517     do
   4518     {
   4519       if ( SKIP_Code() == FAILURE )
   4520         return;
   4521 
   4522       switch ( CUR.opcode )
   4523       {
   4524       case 0x58:    /* IF */
   4525         nIfs++;
   4526         break;
   4527 
   4528       case 0x59:    /* EIF */
   4529         nIfs--;
   4530         break;
   4531       }
   4532     } while ( nIfs != 0 );
   4533   }
   4534 
   4535 
   4536   /*************************************************************************/
   4537   /*                                                                       */
   4538   /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS                         */
   4539   /*                                                                       */
   4540   /*   Instructions appear in the specification's order.                   */
   4541   /*                                                                       */
   4542   /*************************************************************************/
   4543 
   4544 
   4545   /*************************************************************************/
   4546   /*                                                                       */
   4547   /* FDEF[]:       Function DEFinition                                     */
   4548   /* Opcode range: 0x2C                                                    */
   4549   /* Stack:        uint32 -->                                              */
   4550   /*                                                                       */
   4551   static void
   4552   Ins_FDEF( INS_ARG )
   4553   {
   4554     FT_ULong       n;
   4555     TT_DefRecord*  rec;
   4556     TT_DefRecord*  limit;
   4557 
   4558 
   4559     /* some font programs are broken enough to redefine functions! */
   4560     /* We will then parse the current table.                       */
   4561 
   4562     rec   = CUR.FDefs;
   4563     limit = rec + CUR.numFDefs;
   4564     n     = args[0];
   4565 
   4566     for ( ; rec < limit; rec++ )
   4567     {
   4568       if ( rec->opc == n )
   4569         break;
   4570     }
   4571 
   4572     if ( rec == limit )
   4573     {
   4574       /* check that there is enough room for new functions */
   4575       if ( CUR.numFDefs >= CUR.maxFDefs )
   4576       {
   4577         CUR.error = TT_Err_Too_Many_Function_Defs;
   4578         return;
   4579       }
   4580       CUR.numFDefs++;
   4581     }
   4582 
   4583     /* Although FDEF takes unsigned 32-bit integer,  */
   4584     /* func # must be within unsigned 16-bit integer */
   4585     if ( n > 0xFFFFU )
   4586     {
   4587       CUR.error = TT_Err_Too_Many_Function_Defs;
   4588       return;
   4589     }
   4590 
   4591     rec->range  = CUR.curRange;
   4592     rec->opc    = (FT_UInt16)n;
   4593     rec->start  = CUR.IP + 1;
   4594     rec->active = TRUE;
   4595 
   4596     if ( n > CUR.maxFunc )
   4597       CUR.maxFunc = (FT_UInt16)n;
   4598 
   4599     /* Now skip the whole function definition. */
   4600     /* We don't allow nested IDEFS & FDEFs.    */
   4601 
   4602     while ( SKIP_Code() == SUCCESS )
   4603     {
   4604       switch ( CUR.opcode )
   4605       {
   4606       case 0x89:    /* IDEF */
   4607       case 0x2C:    /* FDEF */
   4608         CUR.error = TT_Err_Nested_DEFS;
   4609         return;
   4610 
   4611       case 0x2D:   /* ENDF */
   4612         return;
   4613       }
   4614     }
   4615   }
   4616 
   4617 
   4618   /*************************************************************************/
   4619   /*                                                                       */
   4620   /* ENDF[]:       END Function definition                                 */
   4621   /* Opcode range: 0x2D                                                    */
   4622   /* Stack:        -->                                                     */
   4623   /*                                                                       */
   4624   static void
   4625   Ins_ENDF( INS_ARG )
   4626   {
   4627     TT_CallRec*  pRec;
   4628 
   4629     FT_UNUSED_ARG;
   4630 
   4631 
   4632     if ( CUR.callTop <= 0 )     /* We encountered an ENDF without a call */
   4633     {
   4634       CUR.error = TT_Err_ENDF_In_Exec_Stream;
   4635       return;
   4636     }
   4637 
   4638     CUR.callTop--;
   4639 
   4640     pRec = &CUR.callStack[CUR.callTop];
   4641 
   4642     pRec->Cur_Count--;
   4643 
   4644     CUR.step_ins = FALSE;
   4645 
   4646     if ( pRec->Cur_Count > 0 )
   4647     {
   4648       CUR.callTop++;
   4649       CUR.IP = pRec->Cur_Restart;
   4650     }
   4651     else
   4652       /* Loop through the current function */
   4653       INS_Goto_CodeRange( pRec->Caller_Range,
   4654                           pRec->Caller_IP );
   4655 
   4656     /* Exit the current call frame.                      */
   4657 
   4658     /* NOTE: If the last instruction of a program is a   */
   4659     /*       CALL or LOOPCALL, the return address is     */
   4660     /*       always out of the code range.  This is a    */
   4661     /*       valid address, and it is why we do not test */
   4662     /*       the result of Ins_Goto_CodeRange() here!    */
   4663   }
   4664 
   4665 
   4666   /*************************************************************************/
   4667   /*                                                                       */
   4668   /* CALL[]:       CALL function                                           */
   4669   /* Opcode range: 0x2B                                                    */
   4670   /* Stack:        uint32? -->                                             */
   4671   /*                                                                       */
   4672   static void
   4673   Ins_CALL( INS_ARG )
   4674   {
   4675     FT_ULong       F;
   4676     TT_CallRec*    pCrec;
   4677     TT_DefRecord*  def;
   4678 
   4679 
   4680     /* first of all, check the index */
   4681 
   4682     F = args[0];
   4683     if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
   4684       goto Fail;
   4685 
   4686     /* Except for some old Apple fonts, all functions in a TrueType */
   4687     /* font are defined in increasing order, starting from 0.  This */
   4688     /* means that we normally have                                  */
   4689     /*                                                              */
   4690     /*    CUR.maxFunc+1 == CUR.numFDefs                             */
   4691     /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
   4692     /*                                                              */
   4693     /* If this isn't true, we need to look up the function table.   */
   4694 
   4695     def = CUR.FDefs + F;
   4696     if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
   4697     {
   4698       /* look up the FDefs table */
   4699       TT_DefRecord*  limit;
   4700 
   4701 
   4702       def   = CUR.FDefs;
   4703       limit = def + CUR.numFDefs;
   4704 
   4705       while ( def < limit && def->opc != F )
   4706         def++;
   4707 
   4708       if ( def == limit )
   4709         goto Fail;
   4710     }
   4711 
   4712     /* check that the function is active */
   4713     if ( !def->active )
   4714       goto Fail;
   4715 
   4716     /* check the call stack */
   4717     if ( CUR.callTop >= CUR.callSize )
   4718     {
   4719       CUR.error = TT_Err_Stack_Overflow;
   4720       return;
   4721     }
   4722 
   4723     pCrec = CUR.callStack + CUR.callTop;
   4724 
   4725     pCrec->Caller_Range = CUR.curRange;
   4726     pCrec->Caller_IP    = CUR.IP + 1;
   4727     pCrec->Cur_Count    = 1;
   4728     pCrec->Cur_Restart  = def->start;
   4729 
   4730     CUR.callTop++;
   4731 
   4732     INS_Goto_CodeRange( def->range,
   4733                         def->start );
   4734 
   4735     CUR.step_ins = FALSE;
   4736     return;
   4737 
   4738   Fail:
   4739     CUR.error = TT_Err_Invalid_Reference;
   4740   }
   4741 
   4742 
   4743   /*************************************************************************/
   4744   /*                                                                       */
   4745   /* LOOPCALL[]:   LOOP and CALL function                                  */
   4746   /* Opcode range: 0x2A                                                    */
   4747   /* Stack:        uint32? Eint16? -->                                     */
   4748   /*                                                                       */
   4749   static void
   4750   Ins_LOOPCALL( INS_ARG )
   4751   {
   4752     FT_ULong       F;
   4753     TT_CallRec*    pCrec;
   4754     TT_DefRecord*  def;
   4755 
   4756 
   4757     /* first of all, check the index */
   4758     F = args[1];
   4759     if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
   4760       goto Fail;
   4761 
   4762     /* Except for some old Apple fonts, all functions in a TrueType */
   4763     /* font are defined in increasing order, starting from 0.  This */
   4764     /* means that we normally have                                  */
   4765     /*                                                              */
   4766     /*    CUR.maxFunc+1 == CUR.numFDefs                             */
   4767     /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
   4768     /*                                                              */
   4769     /* If this isn't true, we need to look up the function table.   */
   4770 
   4771     def = CUR.FDefs + F;
   4772     if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
   4773     {
   4774       /* look up the FDefs table */
   4775       TT_DefRecord*  limit;
   4776 
   4777 
   4778       def   = CUR.FDefs;
   4779       limit = def + CUR.numFDefs;
   4780 
   4781       while ( def < limit && def->opc != F )
   4782         def++;
   4783 
   4784       if ( def == limit )
   4785         goto Fail;
   4786     }
   4787 
   4788     /* check that the function is active */
   4789     if ( !def->active )
   4790       goto Fail;
   4791 
   4792     /* check stack */
   4793     if ( CUR.callTop >= CUR.callSize )
   4794     {
   4795       CUR.error = TT_Err_Stack_Overflow;
   4796       return;
   4797     }
   4798 
   4799     if ( args[0] > 0 )
   4800     {
   4801       pCrec = CUR.callStack + CUR.callTop;
   4802 
   4803       pCrec->Caller_Range = CUR.curRange;
   4804       pCrec->Caller_IP    = CUR.IP + 1;
   4805       pCrec->Cur_Count    = (FT_Int)args[0];
   4806       pCrec->Cur_Restart  = def->start;
   4807 
   4808       CUR.callTop++;
   4809 
   4810       INS_Goto_CodeRange( def->range, def->start );
   4811 
   4812       CUR.step_ins = FALSE;
   4813     }
   4814     return;
   4815 
   4816   Fail:
   4817     CUR.error = TT_Err_Invalid_Reference;
   4818   }
   4819 
   4820 
   4821   /*************************************************************************/
   4822   /*                                                                       */
   4823   /* IDEF[]:       Instruction DEFinition                                  */
   4824   /* Opcode range: 0x89                                                    */
   4825   /* Stack:        Eint8 -->                                               */
   4826   /*                                                                       */
   4827   static void
   4828   Ins_IDEF( INS_ARG )
   4829   {
   4830     TT_DefRecord*  def;
   4831     TT_DefRecord*  limit;
   4832 
   4833 
   4834     /*  First of all, look for the same function in our table */
   4835 
   4836     def   = CUR.IDefs;
   4837     limit = def + CUR.numIDefs;
   4838 
   4839     for ( ; def < limit; def++ )
   4840       if ( def->opc == (FT_ULong)args[0] )
   4841         break;
   4842 
   4843     if ( def == limit )
   4844     {
   4845       /* check that there is enough room for a new instruction */
   4846       if ( CUR.numIDefs >= CUR.maxIDefs )
   4847       {
   4848         CUR.error = TT_Err_Too_Many_Instruction_Defs;
   4849         return;
   4850       }
   4851       CUR.numIDefs++;
   4852     }
   4853 
   4854     /* opcode must be unsigned 8-bit integer */
   4855     if ( 0 > args[0] || args[0] > 0x00FF )
   4856     {
   4857       CUR.error = TT_Err_Too_Many_Instruction_Defs;
   4858       return;
   4859     }
   4860 
   4861     def->opc    = (FT_Byte)args[0];
   4862     def->start  = CUR.IP + 1;
   4863     def->range  = CUR.curRange;
   4864     def->active = TRUE;
   4865 
   4866     if ( (FT_ULong)args[0] > CUR.maxIns )
   4867       CUR.maxIns = (FT_Byte)args[0];
   4868 
   4869     /* Now skip the whole function definition. */
   4870     /* We don't allow nested IDEFs & FDEFs.    */
   4871 
   4872     while ( SKIP_Code() == SUCCESS )
   4873     {
   4874       switch ( CUR.opcode )
   4875       {
   4876       case 0x89:   /* IDEF */
   4877       case 0x2C:   /* FDEF */
   4878         CUR.error = TT_Err_Nested_DEFS;
   4879         return;
   4880       case 0x2D:   /* ENDF */
   4881         return;
   4882       }
   4883     }
   4884   }
   4885 
   4886 
   4887   /*************************************************************************/
   4888   /*                                                                       */
   4889   /* PUSHING DATA ONTO THE INTERPRETER STACK                               */
   4890   /*                                                                       */
   4891   /*   Instructions appear in the specification's order.                   */
   4892   /*                                                                       */
   4893   /*************************************************************************/
   4894 
   4895 
   4896   /*************************************************************************/
   4897   /*                                                                       */
   4898   /* NPUSHB[]:     PUSH N Bytes                                            */
   4899   /* Opcode range: 0x40                                                    */
   4900   /* Stack:        --> uint32...                                           */
   4901   /*                                                                       */
   4902   static void
   4903   Ins_NPUSHB( INS_ARG )
   4904   {
   4905     FT_UShort  L, K;
   4906 
   4907 
   4908     L = (FT_UShort)CUR.code[CUR.IP + 1];
   4909 
   4910     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
   4911     {
   4912       CUR.error = TT_Err_Stack_Overflow;
   4913       return;
   4914     }
   4915 
   4916     for ( K = 1; K <= L; K++ )
   4917       args[K - 1] = CUR.code[CUR.IP + K + 1];
   4918 
   4919     CUR.new_top += L;
   4920   }
   4921 
   4922 
   4923   /*************************************************************************/
   4924   /*                                                                       */
   4925   /* NPUSHW[]:     PUSH N Words                                            */
   4926   /* Opcode range: 0x41                                                    */
   4927   /* Stack:        --> int32...                                            */
   4928   /*                                                                       */
   4929   static void
   4930   Ins_NPUSHW( INS_ARG )
   4931   {
   4932     FT_UShort  L, K;
   4933 
   4934 
   4935     L = (FT_UShort)CUR.code[CUR.IP + 1];
   4936 
   4937     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
   4938     {
   4939       CUR.error = TT_Err_Stack_Overflow;
   4940       return;
   4941     }
   4942 
   4943     CUR.IP += 2;
   4944 
   4945     for ( K = 0; K < L; K++ )
   4946       args[K] = GET_ShortIns();
   4947 
   4948     CUR.step_ins = FALSE;
   4949     CUR.new_top += L;
   4950   }
   4951 
   4952 
   4953   /*************************************************************************/
   4954   /*                                                                       */
   4955   /* PUSHB[abc]:   PUSH Bytes                                              */
   4956   /* Opcode range: 0xB0-0xB7                                               */
   4957   /* Stack:        --> uint32...                                           */
   4958   /*                                                                       */
   4959   static void
   4960   Ins_PUSHB( INS_ARG )
   4961   {
   4962     FT_UShort  L, K;
   4963 
   4964 
   4965     L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
   4966 
   4967     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
   4968     {
   4969       CUR.error = TT_Err_Stack_Overflow;
   4970       return;
   4971     }
   4972 
   4973     for ( K = 1; K <= L; K++ )
   4974       args[K - 1] = CUR.code[CUR.IP + K];
   4975   }
   4976 
   4977 
   4978   /*************************************************************************/
   4979   /*                                                                       */
   4980   /* PUSHW[abc]:   PUSH Words                                              */
   4981   /* Opcode range: 0xB8-0xBF                                               */
   4982   /* Stack:        --> int32...                                            */
   4983   /*                                                                       */
   4984   static void
   4985   Ins_PUSHW( INS_ARG )
   4986   {
   4987     FT_UShort  L, K;
   4988 
   4989 
   4990     L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
   4991 
   4992     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
   4993     {
   4994       CUR.error = TT_Err_Stack_Overflow;
   4995       return;
   4996     }
   4997 
   4998     CUR.IP++;
   4999 
   5000     for ( K = 0; K < L; K++ )
   5001       args[K] = GET_ShortIns();
   5002 
   5003     CUR.step_ins = FALSE;
   5004   }
   5005 
   5006 
   5007   /*************************************************************************/
   5008   /*                                                                       */
   5009   /* MANAGING THE GRAPHICS STATE                                           */
   5010   /*                                                                       */
   5011   /*  Instructions appear in the specs' order.                             */
   5012   /*                                                                       */
   5013   /*************************************************************************/
   5014 
   5015 
   5016   /*************************************************************************/
   5017   /*                                                                       */
   5018   /* GC[a]:        Get Coordinate projected onto                           */
   5019   /* Opcode range: 0x46-0x47                                               */
   5020   /* Stack:        uint32 --> f26.6                                        */
   5021   /*                                                                       */
   5022   /* BULLSHIT: Measures from the original glyph must be taken along the    */
   5023   /*           dual projection vector!                                     */
   5024   /*                                                                       */
   5025   static void
   5026   Ins_GC( INS_ARG )
   5027   {
   5028     FT_ULong    L;
   5029     FT_F26Dot6  R;
   5030 
   5031 
   5032     L = (FT_ULong)args[0];
   5033 
   5034     if ( BOUNDSL( L, CUR.zp2.n_points ) )
   5035     {
   5036       if ( CUR.pedantic_hinting )
   5037       {
   5038         CUR.error = TT_Err_Invalid_Reference;
   5039         return;
   5040       }
   5041       else
   5042         R = 0;
   5043     }
   5044     else
   5045     {
   5046       if ( CUR.opcode & 1 )
   5047         R = CUR_fast_dualproj( &CUR.zp2.org[L] );
   5048       else
   5049         R = CUR_fast_project( &CUR.zp2.cur[L] );
   5050     }
   5051 
   5052     args[0] = R;
   5053   }
   5054 
   5055 
   5056   /*************************************************************************/
   5057   /*                                                                       */
   5058   /* SCFS[]:       Set Coordinate From Stack                               */
   5059   /* Opcode range: 0x48                                                    */
   5060   /* Stack:        f26.6 uint32 -->                                        */
   5061   /*                                                                       */
   5062   /* Formula:                                                              */
   5063   /*                                                                       */
   5064   /*   OA := OA + ( value - OA.p )/( f.p ) * f                             */
   5065   /*                                                                       */
   5066   static void
   5067   Ins_SCFS( INS_ARG )
   5068   {
   5069     FT_Long    K;
   5070     FT_UShort  L;
   5071 
   5072 
   5073     L = (FT_UShort)args[0];
   5074 
   5075     if ( BOUNDS( L, CUR.zp2.n_points ) )
   5076     {
   5077       if ( CUR.pedantic_hinting )
   5078         CUR.error = TT_Err_Invalid_Reference;
   5079       return;
   5080     }
   5081 
   5082     K = CUR_fast_project( &CUR.zp2.cur[L] );
   5083 
   5084     CUR_Func_move( &CUR.zp2, L, args[1] - K );
   5085 
   5086     /* not part of the specs, but here for safety */
   5087 
   5088     if ( CUR.GS.gep2 == 0 )
   5089       CUR.zp2.org[L] = CUR.zp2.cur[L];
   5090   }
   5091 
   5092 
   5093   /*************************************************************************/
   5094   /*                                                                       */
   5095   /* MD[a]:        Measure Distance                                        */
   5096   /* Opcode range: 0x49-0x4A                                               */
   5097   /* Stack:        uint32 uint32 --> f26.6                                 */
   5098   /*                                                                       */
   5099   /* BULLSHIT: Measure taken in the original glyph must be along the dual  */
   5100   /*           projection vector.                                          */
   5101   /*                                                                       */
   5102   /* Second BULLSHIT: Flag attributes are inverted!                        */
   5103   /*                  0 => measure distance in original outline            */
   5104   /*                  1 => measure distance in grid-fitted outline         */
   5105   /*                                                                       */
   5106   /* Third one: `zp0 - zp1', and not `zp2 - zp1!                           */
   5107   /*                                                                       */
   5108   static void
   5109   Ins_MD( INS_ARG )
   5110   {
   5111     FT_UShort   K, L;
   5112     FT_F26Dot6  D;
   5113 
   5114 
   5115     K = (FT_UShort)args[1];
   5116     L = (FT_UShort)args[0];
   5117 
   5118     if ( BOUNDS( L, CUR.zp0.n_points ) ||
   5119          BOUNDS( K, CUR.zp1.n_points ) )
   5120     {
   5121       if ( CUR.pedantic_hinting )
   5122       {
   5123         CUR.error = TT_Err_Invalid_Reference;
   5124         return;
   5125       }
   5126       D = 0;
   5127     }
   5128     else
   5129     {
   5130       if ( CUR.opcode & 1 )
   5131         D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
   5132       else
   5133       {
   5134         FT_Vector*  vec1 = CUR.zp0.orus + L;
   5135         FT_Vector*  vec2 = CUR.zp1.orus + K;
   5136 
   5137 
   5138         if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
   5139         {
   5140           /* this should be faster */
   5141           D = CUR_Func_dualproj( vec1, vec2 );
   5142           D = TT_MULFIX( D, CUR.metrics.x_scale );
   5143         }
   5144         else
   5145         {
   5146           FT_Vector  vec;
   5147 
   5148 
   5149           vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
   5150           vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
   5151 
   5152           D = CUR_fast_dualproj( &vec );
   5153         }
   5154       }
   5155     }
   5156 
   5157     args[0] = D;
   5158   }
   5159 
   5160 
   5161   /*************************************************************************/
   5162   /*                                                                       */
   5163   /* SDPVTL[a]:    Set Dual PVector to Line                                */
   5164   /* Opcode range: 0x86-0x87                                               */
   5165   /* Stack:        uint32 uint32 -->                                       */
   5166   /*                                                                       */
   5167   static void
   5168   Ins_SDPVTL( INS_ARG )
   5169   {
   5170     FT_Long    A, B, C;
   5171     FT_UShort  p1, p2;   /* was FT_Int in pas type ERROR */
   5172 
   5173 
   5174     p1 = (FT_UShort)args[1];
   5175     p2 = (FT_UShort)args[0];
   5176 
   5177     if ( BOUNDS( p2, CUR.zp1.n_points ) ||
   5178          BOUNDS( p1, CUR.zp2.n_points ) )
   5179     {
   5180       if ( CUR.pedantic_hinting )
   5181         CUR.error = TT_Err_Invalid_Reference;
   5182       return;
   5183     }
   5184 
   5185     {
   5186       FT_Vector* v1 = CUR.zp1.org + p2;
   5187       FT_Vector* v2 = CUR.zp2.org + p1;
   5188 
   5189 
   5190       A = v1->x - v2->x;
   5191       B = v1->y - v2->y;
   5192     }
   5193 
   5194     if ( ( CUR.opcode & 1 ) != 0 )
   5195     {
   5196       C =  B;   /* counter clockwise rotation */
   5197       B =  A;
   5198       A = -C;
   5199     }
   5200 
   5201     NORMalize( A, B, &CUR.GS.dualVector );
   5202 
   5203     {
   5204       FT_Vector*  v1 = CUR.zp1.cur + p2;
   5205       FT_Vector*  v2 = CUR.zp2.cur + p1;
   5206 
   5207 
   5208       A = v1->x - v2->x;
   5209       B = v1->y - v2->y;
   5210     }
   5211 
   5212     if ( ( CUR.opcode & 1 ) != 0 )
   5213     {
   5214       C =  B;   /* counter clockwise rotation */
   5215       B =  A;
   5216       A = -C;
   5217     }
   5218 
   5219     NORMalize( A, B, &CUR.GS.projVector );
   5220 
   5221     GUESS_VECTOR( freeVector );
   5222 
   5223     COMPUTE_Funcs();
   5224   }
   5225 
   5226 
   5227   /*************************************************************************/
   5228   /*                                                                       */
   5229   /* SZP0[]:       Set Zone Pointer 0                                      */
   5230   /* Opcode range: 0x13                                                    */
   5231   /* Stack:        uint32 -->                                              */
   5232   /*                                                                       */
   5233   static void
   5234   Ins_SZP0( INS_ARG )
   5235   {
   5236     switch ( (FT_Int)args[0] )
   5237     {
   5238     case 0:
   5239       CUR.zp0 = CUR.twilight;
   5240       break;
   5241 
   5242     case 1:
   5243       CUR.zp0 = CUR.pts;
   5244       break;
   5245 
   5246     default:
   5247       if ( CUR.pedantic_hinting )
   5248         CUR.error = TT_Err_Invalid_Reference;
   5249       return;
   5250     }
   5251 
   5252     CUR.GS.gep0 = (FT_UShort)args[0];
   5253   }
   5254 
   5255 
   5256   /*************************************************************************/
   5257   /*                                                                       */
   5258   /* SZP1[]:       Set Zone Pointer 1                                      */
   5259   /* Opcode range: 0x14                                                    */
   5260   /* Stack:        uint32 -->                                              */
   5261   /*                                                                       */
   5262   static void
   5263   Ins_SZP1( INS_ARG )
   5264   {
   5265     switch ( (FT_Int)args[0] )
   5266     {
   5267     case 0:
   5268       CUR.zp1 = CUR.twilight;
   5269       break;
   5270 
   5271     case 1:
   5272       CUR.zp1 = CUR.pts;
   5273       break;
   5274 
   5275     default:
   5276       if ( CUR.pedantic_hinting )
   5277         CUR.error = TT_Err_Invalid_Reference;
   5278       return;
   5279     }
   5280 
   5281     CUR.GS.gep1 = (FT_UShort)args[0];
   5282   }
   5283 
   5284 
   5285   /*************************************************************************/
   5286   /*                                                                       */
   5287   /* SZP2[]:       Set Zone Pointer 2                                      */
   5288   /* Opcode range: 0x15                                                    */
   5289   /* Stack:        uint32 -->                                              */
   5290   /*                                                                       */
   5291   static void
   5292   Ins_SZP2( INS_ARG )
   5293   {
   5294     switch ( (FT_Int)args[0] )
   5295     {
   5296     case 0:
   5297       CUR.zp2 = CUR.twilight;
   5298       break;
   5299 
   5300     case 1:
   5301       CUR.zp2 = CUR.pts;
   5302       break;
   5303 
   5304     default:
   5305       if ( CUR.pedantic_hinting )
   5306         CUR.error = TT_Err_Invalid_Reference;
   5307       return;
   5308     }
   5309 
   5310     CUR.GS.gep2 = (FT_UShort)args[0];
   5311   }
   5312 
   5313 
   5314   /*************************************************************************/
   5315   /*                                                                       */
   5316   /* SZPS[]:       Set Zone PointerS                                       */
   5317   /* Opcode range: 0x16                                                    */
   5318   /* Stack:        uint32 -->                                              */
   5319   /*                                                                       */
   5320   static void
   5321   Ins_SZPS( INS_ARG )
   5322   {
   5323     switch ( (FT_Int)args[0] )
   5324     {
   5325     case 0:
   5326       CUR.zp0 = CUR.twilight;
   5327       break;
   5328 
   5329     case 1:
   5330       CUR.zp0 = CUR.pts;
   5331       break;
   5332 
   5333     default:
   5334       if ( CUR.pedantic_hinting )
   5335         CUR.error = TT_Err_Invalid_Reference;
   5336       return;
   5337     }
   5338 
   5339     CUR.zp1 = CUR.zp0;
   5340     CUR.zp2 = CUR.zp0;
   5341 
   5342     CUR.GS.gep0 = (FT_UShort)args[0];
   5343     CUR.GS.gep1 = (FT_UShort)args[0];
   5344     CUR.GS.gep2 = (FT_UShort)args[0];
   5345   }
   5346 
   5347 
   5348   /*************************************************************************/
   5349   /*                                                                       */
   5350   /* INSTCTRL[]:   INSTruction ConTRoL                                     */
   5351   /* Opcode range: 0x8e                                                    */
   5352   /* Stack:        int32 int32 -->                                         */
   5353   /*                                                                       */
   5354   static void
   5355   Ins_INSTCTRL( INS_ARG )
   5356   {
   5357     FT_Long  K, L;
   5358 
   5359 
   5360     K = args[1];
   5361     L = args[0];
   5362 
   5363     if ( K < 1 || K > 2 )
   5364     {
   5365       if ( CUR.pedantic_hinting )
   5366         CUR.error = TT_Err_Invalid_Reference;
   5367       return;
   5368     }
   5369 
   5370     if ( L != 0 )
   5371         L = K;
   5372 
   5373     CUR.GS.instruct_control = FT_BOOL(
   5374       ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
   5375   }
   5376 
   5377 
   5378   /*************************************************************************/
   5379   /*                                                                       */
   5380   /* SCANCTRL[]:   SCAN ConTRoL                                            */
   5381   /* Opcode range: 0x85                                                    */
   5382   /* Stack:        uint32? -->                                             */
   5383   /*                                                                       */
   5384   static void
   5385   Ins_SCANCTRL( INS_ARG )
   5386   {
   5387     FT_Int  A;
   5388 
   5389 
   5390     /* Get Threshold */
   5391     A = (FT_Int)( args[0] & 0xFF );
   5392 
   5393     if ( A == 0xFF )
   5394     {
   5395       CUR.GS.scan_control = TRUE;
   5396       return;
   5397     }
   5398     else if ( A == 0 )
   5399     {
   5400       CUR.GS.scan_control = FALSE;
   5401       return;
   5402     }
   5403 
   5404     if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
   5405       CUR.GS.scan_control = TRUE;
   5406 
   5407     if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
   5408       CUR.GS.scan_control = TRUE;
   5409 
   5410     if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
   5411       CUR.GS.scan_control = TRUE;
   5412 
   5413     if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
   5414       CUR.GS.scan_control = FALSE;
   5415 
   5416     if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
   5417       CUR.GS.scan_control = FALSE;
   5418 
   5419     if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
   5420       CUR.GS.scan_control = FALSE;
   5421   }
   5422 
   5423 
   5424   /*************************************************************************/
   5425   /*                                                                       */
   5426   /* SCANTYPE[]:   SCAN TYPE                                               */
   5427   /* Opcode range: 0x8D                                                    */
   5428   /* Stack:        uint32? -->                                             */
   5429   /*                                                                       */
   5430   static void
   5431   Ins_SCANTYPE( INS_ARG )
   5432   {
   5433     if ( args[0] >= 0 )
   5434       CUR.GS.scan_type = (FT_Int)args[0];
   5435   }
   5436 
   5437 
   5438   /*************************************************************************/
   5439   /*                                                                       */
   5440   /* MANAGING OUTLINES                                                     */
   5441   /*                                                                       */
   5442   /*   Instructions appear in the specification's order.                   */
   5443   /*                                                                       */
   5444   /*************************************************************************/
   5445 
   5446 
   5447   /*************************************************************************/
   5448   /*                                                                       */
   5449   /* FLIPPT[]:     FLIP PoinT                                              */
   5450   /* Opcode range: 0x80                                                    */
   5451   /* Stack:        uint32... -->                                           */
   5452   /*                                                                       */
   5453   static void
   5454   Ins_FLIPPT( INS_ARG )
   5455   {
   5456     FT_UShort  point;
   5457 
   5458     FT_UNUSED_ARG;
   5459 
   5460 
   5461     if ( CUR.top < CUR.GS.loop )
   5462     {
   5463       CUR.error = TT_Err_Too_Few_Arguments;
   5464       return;
   5465     }
   5466 
   5467     while ( CUR.GS.loop > 0 )
   5468     {
   5469       CUR.args--;
   5470 
   5471       point = (FT_UShort)CUR.stack[CUR.args];
   5472 
   5473       if ( BOUNDS( point, CUR.pts.n_points ) )
   5474       {
   5475         if ( CUR.pedantic_hinting )
   5476         {
   5477           CUR.error = TT_Err_Invalid_Reference;
   5478           return;
   5479         }
   5480       }
   5481       else
   5482         CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
   5483 
   5484       CUR.GS.loop--;
   5485     }
   5486 
   5487     CUR.GS.loop = 1;
   5488     CUR.new_top = CUR.args;
   5489   }
   5490 
   5491 
   5492   /*************************************************************************/
   5493   /*                                                                       */
   5494   /* FLIPRGON[]:   FLIP RanGe ON                                           */
   5495   /* Opcode range: 0x81                                                    */
   5496   /* Stack:        uint32 uint32 -->                                       */
   5497   /*                                                                       */
   5498   static void
   5499   Ins_FLIPRGON( INS_ARG )
   5500   {
   5501     FT_UShort  I, K, L;
   5502 
   5503 
   5504     K = (FT_UShort)args[1];
   5505     L = (FT_UShort)args[0];
   5506 
   5507     if ( BOUNDS( K, CUR.pts.n_points ) ||
   5508          BOUNDS( L, CUR.pts.n_points ) )
   5509     {
   5510       if ( CUR.pedantic_hinting )
   5511         CUR.error = TT_Err_Invalid_Reference;
   5512       return;
   5513     }
   5514 
   5515     for ( I = L; I <= K; I++ )
   5516       CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
   5517   }
   5518 
   5519 
   5520   /*************************************************************************/
   5521   /*                                                                       */
   5522   /* FLIPRGOFF:    FLIP RanGe OFF                                          */
   5523   /* Opcode range: 0x82                                                    */
   5524   /* Stack:        uint32 uint32 -->                                       */
   5525   /*                                                                       */
   5526   static void
   5527   Ins_FLIPRGOFF( INS_ARG )
   5528   {
   5529     FT_UShort  I, K, L;
   5530 
   5531 
   5532     K = (FT_UShort)args[1];
   5533     L = (FT_UShort)args[0];
   5534 
   5535     if ( BOUNDS( K, CUR.pts.n_points ) ||
   5536          BOUNDS( L, CUR.pts.n_points ) )
   5537     {
   5538       if ( CUR.pedantic_hinting )
   5539         CUR.error = TT_Err_Invalid_Reference;
   5540       return;
   5541     }
   5542 
   5543     for ( I = L; I <= K; I++ )
   5544       CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
   5545   }
   5546 
   5547 
   5548   static FT_Bool
   5549   Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6*   x,
   5550                                        FT_F26Dot6*   y,
   5551                                        TT_GlyphZone  zone,
   5552                                        FT_UShort*    refp )
   5553   {
   5554     TT_GlyphZoneRec  zp;
   5555     FT_UShort        p;
   5556     FT_F26Dot6       d;
   5557 
   5558 
   5559     if ( CUR.opcode & 1 )
   5560     {
   5561       zp = CUR.zp0;
   5562       p  = CUR.GS.rp1;
   5563     }
   5564     else
   5565     {
   5566       zp = CUR.zp1;
   5567       p  = CUR.GS.rp2;
   5568     }
   5569 
   5570     if ( BOUNDS( p, zp.n_points ) )
   5571     {
   5572       if ( CUR.pedantic_hinting )
   5573         CUR.error = TT_Err_Invalid_Reference;
   5574       *refp = 0;
   5575       return FAILURE;
   5576     }
   5577 
   5578     *zone = zp;
   5579     *refp = p;
   5580 
   5581     d = CUR_Func_project( zp.cur + p, zp.org + p );
   5582 
   5583 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   5584     if ( CUR.face->unpatented_hinting )
   5585     {
   5586       if ( CUR.GS.both_x_axis )
   5587       {
   5588         *x = d;
   5589         *y = 0;
   5590       }
   5591       else
   5592       {
   5593         *x = 0;
   5594         *y = d;
   5595       }
   5596     }
   5597     else
   5598 #endif
   5599     {
   5600       *x = TT_MULDIV( d,
   5601                       (FT_Long)CUR.GS.freeVector.x * 0x10000L,
   5602                       CUR.F_dot_P );
   5603       *y = TT_MULDIV( d,
   5604                       (FT_Long)CUR.GS.freeVector.y * 0x10000L,
   5605                       CUR.F_dot_P );
   5606     }
   5607 
   5608     return SUCCESS;
   5609   }
   5610 
   5611 
   5612   static void
   5613   Move_Zp2_Point( EXEC_OP_ FT_UShort   point,
   5614                            FT_F26Dot6  dx,
   5615                            FT_F26Dot6  dy,
   5616                            FT_Bool     touch )
   5617   {
   5618 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   5619     if ( CUR.face->unpatented_hinting )
   5620     {
   5621       if ( CUR.GS.both_x_axis )
   5622       {
   5623         CUR.zp2.cur[point].x += dx;
   5624         if ( touch )
   5625           CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
   5626       }
   5627       else
   5628       {
   5629         CUR.zp2.cur[point].y += dy;
   5630         if ( touch )
   5631           CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
   5632       }
   5633       return;
   5634     }
   5635 #endif
   5636 
   5637     if ( CUR.GS.freeVector.x != 0 )
   5638     {
   5639       CUR.zp2.cur[point].x += dx;
   5640       if ( touch )
   5641         CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
   5642     }
   5643 
   5644     if ( CUR.GS.freeVector.y != 0 )
   5645     {
   5646       CUR.zp2.cur[point].y += dy;
   5647       if ( touch )
   5648         CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
   5649     }
   5650   }
   5651 
   5652 
   5653   /*************************************************************************/
   5654   /*                                                                       */
   5655   /* SHP[a]:       SHift Point by the last point                           */
   5656   /* Opcode range: 0x32-0x33                                               */
   5657   /* Stack:        uint32... -->                                           */
   5658   /*                                                                       */
   5659   static void
   5660   Ins_SHP( INS_ARG )
   5661   {
   5662     TT_GlyphZoneRec  zp;
   5663     FT_UShort        refp;
   5664 
   5665     FT_F26Dot6       dx,
   5666                      dy;
   5667     FT_UShort        point;
   5668 
   5669     FT_UNUSED_ARG;
   5670 
   5671 
   5672     if ( CUR.top < CUR.GS.loop )
   5673     {
   5674       CUR.error = TT_Err_Invalid_Reference;
   5675       return;
   5676     }
   5677 
   5678     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
   5679       return;
   5680 
   5681     while ( CUR.GS.loop > 0 )
   5682     {
   5683       CUR.args--;
   5684       point = (FT_UShort)CUR.stack[CUR.args];
   5685 
   5686       if ( BOUNDS( point, CUR.zp2.n_points ) )
   5687       {
   5688         if ( CUR.pedantic_hinting )
   5689         {
   5690           CUR.error = TT_Err_Invalid_Reference;
   5691           return;
   5692         }
   5693       }
   5694       else
   5695         /* XXX: UNDOCUMENTED! SHP touches the points */
   5696         MOVE_Zp2_Point( point, dx, dy, TRUE );
   5697 
   5698       CUR.GS.loop--;
   5699     }
   5700 
   5701     CUR.GS.loop = 1;
   5702     CUR.new_top = CUR.args;
   5703   }
   5704 
   5705 
   5706   /*************************************************************************/
   5707   /*                                                                       */
   5708   /* SHC[a]:       SHift Contour                                           */
   5709   /* Opcode range: 0x34-35                                                 */
   5710   /* Stack:        uint32 -->                                              */
   5711   /*                                                                       */
   5712   static void
   5713   Ins_SHC( INS_ARG )
   5714   {
   5715     TT_GlyphZoneRec zp;
   5716     FT_UShort       refp;
   5717     FT_F26Dot6      dx,
   5718                     dy;
   5719 
   5720     FT_Short        contour;
   5721     FT_UShort       first_point, last_point, i;
   5722 
   5723 
   5724     contour = (FT_UShort)args[0];
   5725 
   5726     if ( BOUNDS( contour, CUR.pts.n_contours ) )
   5727     {
   5728       if ( CUR.pedantic_hinting )
   5729         CUR.error = TT_Err_Invalid_Reference;
   5730       return;
   5731     }
   5732 
   5733     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
   5734       return;
   5735 
   5736     if ( contour == 0 )
   5737       first_point = 0;
   5738     else
   5739       first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
   5740                                  CUR.pts.first_point );
   5741 
   5742     last_point = (FT_UShort)( CUR.pts.contours[contour] -
   5743                               CUR.pts.first_point );
   5744 
   5745     /* XXX: this is probably wrong... at least it prevents memory */
   5746     /*      corruption when zp2 is the twilight zone              */
   5747     if ( BOUNDS( last_point, CUR.zp2.n_points ) )
   5748     {
   5749       if ( CUR.zp2.n_points > 0 )
   5750         last_point = (FT_UShort)(CUR.zp2.n_points - 1);
   5751       else
   5752         last_point = 0;
   5753     }
   5754 
   5755     /* XXX: UNDOCUMENTED! SHC touches the points */
   5756     for ( i = first_point; i <= last_point; i++ )
   5757     {
   5758       if ( zp.cur != CUR.zp2.cur || refp != i )
   5759         MOVE_Zp2_Point( i, dx, dy, TRUE );
   5760     }
   5761   }
   5762 
   5763 
   5764   /*************************************************************************/
   5765   /*                                                                       */
   5766   /* SHZ[a]:       SHift Zone                                              */
   5767   /* Opcode range: 0x36-37                                                 */
   5768   /* Stack:        uint32 -->                                              */
   5769   /*                                                                       */
   5770   static void
   5771   Ins_SHZ( INS_ARG )
   5772   {
   5773     TT_GlyphZoneRec  zp;
   5774     FT_UShort        refp;
   5775     FT_F26Dot6       dx,
   5776                      dy;
   5777 
   5778     FT_UShort        last_point, i;
   5779 
   5780 
   5781     if ( BOUNDS( args[0], 2 ) )
   5782     {
   5783       if ( CUR.pedantic_hinting )
   5784         CUR.error = TT_Err_Invalid_Reference;
   5785       return;
   5786     }
   5787 
   5788     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
   5789       return;
   5790 
   5791     /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.  */
   5792     /*      Twilight zone has no contours, so use `n_points'.   */
   5793     /*      Normal zone's `n_points' includes phantoms, so must */
   5794     /*      use end of last contour.                            */
   5795     if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
   5796       last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
   5797     else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
   5798       last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
   5799     else
   5800       last_point = 0;
   5801 
   5802     /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
   5803     for ( i = 0; i <= last_point; i++ )
   5804     {
   5805       if ( zp.cur != CUR.zp2.cur || refp != i )
   5806         MOVE_Zp2_Point( i, dx, dy, FALSE );
   5807     }
   5808   }
   5809 
   5810 
   5811   /*************************************************************************/
   5812   /*                                                                       */
   5813   /* SHPIX[]:      SHift points by a PIXel amount                          */
   5814   /* Opcode range: 0x38                                                    */
   5815   /* Stack:        f26.6 uint32... -->                                     */
   5816   /*                                                                       */
   5817   static void
   5818   Ins_SHPIX( INS_ARG )
   5819   {
   5820     FT_F26Dot6  dx, dy;
   5821     FT_UShort   point;
   5822 
   5823 
   5824     if ( CUR.top < CUR.GS.loop + 1 )
   5825     {
   5826       CUR.error = TT_Err_Invalid_Reference;
   5827       return;
   5828     }
   5829 
   5830 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   5831     if ( CUR.face->unpatented_hinting )
   5832     {
   5833       if ( CUR.GS.both_x_axis )
   5834       {
   5835         dx = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
   5836         dy = 0;
   5837       }
   5838       else
   5839       {
   5840         dx = 0;
   5841         dy = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
   5842       }
   5843     }
   5844     else
   5845 #endif
   5846     {
   5847       dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
   5848       dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
   5849     }
   5850 
   5851     while ( CUR.GS.loop > 0 )
   5852     {
   5853       CUR.args--;
   5854 
   5855       point = (FT_UShort)CUR.stack[CUR.args];
   5856 
   5857       if ( BOUNDS( point, CUR.zp2.n_points ) )
   5858       {
   5859         if ( CUR.pedantic_hinting )
   5860         {
   5861           CUR.error = TT_Err_Invalid_Reference;
   5862           return;
   5863         }
   5864       }
   5865       else
   5866         MOVE_Zp2_Point( point, dx, dy, TRUE );
   5867 
   5868       CUR.GS.loop--;
   5869     }
   5870 
   5871     CUR.GS.loop = 1;
   5872     CUR.new_top = CUR.args;
   5873   }
   5874 
   5875 
   5876   /*************************************************************************/
   5877   /*                                                                       */
   5878   /* MSIRP[a]:     Move Stack Indirect Relative Position                   */
   5879   /* Opcode range: 0x3A-0x3B                                               */
   5880   /* Stack:        f26.6 uint32 -->                                        */
   5881   /*                                                                       */
   5882   static void
   5883   Ins_MSIRP( INS_ARG )
   5884   {
   5885     FT_UShort   point;
   5886     FT_F26Dot6  distance;
   5887 
   5888 
   5889     point = (FT_UShort)args[0];
   5890 
   5891     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
   5892          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
   5893     {
   5894       if ( CUR.pedantic_hinting )
   5895         CUR.error = TT_Err_Invalid_Reference;
   5896       return;
   5897     }
   5898 
   5899     /* XXX: UNDOCUMENTED! behaviour */
   5900     if ( CUR.GS.gep1 == 0 )   /* if the point that is to be moved */
   5901                               /* is in twilight zone              */
   5902     {
   5903       CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
   5904       CUR_Func_move_orig( &CUR.zp1, point, args[1] );
   5905       CUR.zp1.cur[point] = CUR.zp1.org[point];
   5906     }
   5907 
   5908     distance = CUR_Func_project( CUR.zp1.cur + point,
   5909                                  CUR.zp0.cur + CUR.GS.rp0 );
   5910 
   5911     CUR_Func_move( &CUR.zp1, point, args[1] - distance );
   5912 
   5913     CUR.GS.rp1 = CUR.GS.rp0;
   5914     CUR.GS.rp2 = point;
   5915 
   5916     if ( ( CUR.opcode & 1 ) != 0 )
   5917       CUR.GS.rp0 = point;
   5918   }
   5919 
   5920 
   5921   /*************************************************************************/
   5922   /*                                                                       */
   5923   /* MDAP[a]:      Move Direct Absolute Point                              */
   5924   /* Opcode range: 0x2E-0x2F                                               */
   5925   /* Stack:        uint32 -->                                              */
   5926   /*                                                                       */
   5927   static void
   5928   Ins_MDAP( INS_ARG )
   5929   {
   5930     FT_UShort   point;
   5931     FT_F26Dot6  cur_dist,
   5932                 distance;
   5933 
   5934 
   5935     point = (FT_UShort)args[0];
   5936 
   5937     if ( BOUNDS( point, CUR.zp0.n_points ) )
   5938     {
   5939       if ( CUR.pedantic_hinting )
   5940         CUR.error = TT_Err_Invalid_Reference;
   5941       return;
   5942     }
   5943 
   5944     /* XXX: Is there some undocumented feature while in the */
   5945     /*      twilight zone? ?                                */
   5946     if ( ( CUR.opcode & 1 ) != 0 )
   5947     {
   5948       cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
   5949       distance = CUR_Func_round( cur_dist,
   5950                                  CUR.tt_metrics.compensations[0] ) - cur_dist;
   5951     }
   5952     else
   5953       distance = 0;
   5954 
   5955     CUR_Func_move( &CUR.zp0, point, distance );
   5956 
   5957     CUR.GS.rp0 = point;
   5958     CUR.GS.rp1 = point;
   5959   }
   5960 
   5961 
   5962   /*************************************************************************/
   5963   /*                                                                       */
   5964   /* MIAP[a]:      Move Indirect Absolute Point                            */
   5965   /* Opcode range: 0x3E-0x3F                                               */
   5966   /* Stack:        uint32 uint32 -->                                       */
   5967   /*                                                                       */
   5968   static void
   5969   Ins_MIAP( INS_ARG )
   5970   {
   5971     FT_ULong    cvtEntry;
   5972     FT_UShort   point;
   5973     FT_F26Dot6  distance,
   5974                 org_dist;
   5975 
   5976 
   5977     cvtEntry = (FT_ULong)args[1];
   5978     point    = (FT_UShort)args[0];
   5979 
   5980     if ( BOUNDS( point,     CUR.zp0.n_points ) ||
   5981          BOUNDSL( cvtEntry, CUR.cvtSize )      )
   5982     {
   5983       if ( CUR.pedantic_hinting )
   5984         CUR.error = TT_Err_Invalid_Reference;
   5985       return;
   5986     }
   5987 
   5988     /* XXX: UNDOCUMENTED!                                */
   5989     /*                                                   */
   5990     /* The behaviour of an MIAP instruction is quite     */
   5991     /* different when used in the twilight zone.         */
   5992     /*                                                   */
   5993     /* First, no control value cut-in test is performed  */
   5994     /* as it would fail anyway.  Second, the original    */
   5995     /* point, i.e. (org_x,org_y) of zp0.point, is set    */
   5996     /* to the absolute, unrounded distance found in      */
   5997     /* the CVT.                                          */
   5998     /*                                                   */
   5999     /* This is used in the CVT programs of the Microsoft */
   6000     /* fonts Arial, Times, etc., in order to re-adjust   */
   6001     /* some key font heights.  It allows the use of the  */
   6002     /* IP instruction in the twilight zone, which        */
   6003     /* otherwise would be `illegal' according to the     */
   6004     /* specification.                                    */
   6005     /*                                                   */
   6006     /* We implement it with a special sequence for the   */
   6007     /* twilight zone.  This is a bad hack, but it seems  */
   6008     /* to work.                                          */
   6009 
   6010     distance = CUR_Func_read_cvt( cvtEntry );
   6011 
   6012     if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
   6013     {
   6014       CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.x );
   6015       CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.y ),
   6016       CUR.zp0.cur[point]   = CUR.zp0.org[point];
   6017     }
   6018 
   6019     org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
   6020 
   6021     if ( ( CUR.opcode & 1 ) != 0 )   /* rounding and control cutin flag */
   6022     {
   6023       if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
   6024         distance = org_dist;
   6025 
   6026       distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
   6027     }
   6028 
   6029     CUR_Func_move( &CUR.zp0, point, distance - org_dist );
   6030 
   6031     CUR.GS.rp0 = point;
   6032     CUR.GS.rp1 = point;
   6033   }
   6034 
   6035 
   6036   /*************************************************************************/
   6037   /*                                                                       */
   6038   /* MDRP[abcde]:  Move Direct Relative Point                              */
   6039   /* Opcode range: 0xC0-0xDF                                               */
   6040   /* Stack:        uint32 -->                                              */
   6041   /*                                                                       */
   6042   static void
   6043   Ins_MDRP( INS_ARG )
   6044   {
   6045     FT_UShort   point;
   6046     FT_F26Dot6  org_dist, distance;
   6047 
   6048 
   6049     point = (FT_UShort)args[0];
   6050 
   6051     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
   6052          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
   6053     {
   6054       if ( CUR.pedantic_hinting )
   6055         CUR.error = TT_Err_Invalid_Reference;
   6056       return;
   6057     }
   6058 
   6059     /* XXX: Is there some undocumented feature while in the */
   6060     /*      twilight zone?                                  */
   6061 
   6062     /* XXX: UNDOCUMENTED: twilight zone special case */
   6063 
   6064     if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
   6065     {
   6066       FT_Vector*  vec1 = &CUR.zp1.org[point];
   6067       FT_Vector*  vec2 = &CUR.zp0.org[CUR.GS.rp0];
   6068 
   6069 
   6070       org_dist = CUR_Func_dualproj( vec1, vec2 );
   6071     }
   6072     else
   6073     {
   6074       FT_Vector*  vec1 = &CUR.zp1.orus[point];
   6075       FT_Vector*  vec2 = &CUR.zp0.orus[CUR.GS.rp0];
   6076 
   6077 
   6078       if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
   6079       {
   6080         /* this should be faster */
   6081         org_dist = CUR_Func_dualproj( vec1, vec2 );
   6082         org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
   6083       }
   6084       else
   6085       {
   6086         FT_Vector  vec;
   6087 
   6088 
   6089         vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
   6090         vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
   6091 
   6092         org_dist = CUR_fast_dualproj( &vec );
   6093       }
   6094     }
   6095 
   6096     /* single width cut-in test */
   6097 
   6098     if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
   6099          CUR.GS.single_width_cutin )
   6100     {
   6101       if ( org_dist >= 0 )
   6102         org_dist = CUR.GS.single_width_value;
   6103       else
   6104         org_dist = -CUR.GS.single_width_value;
   6105     }
   6106 
   6107     /* round flag */
   6108 
   6109     if ( ( CUR.opcode & 4 ) != 0 )
   6110       distance = CUR_Func_round(
   6111                    org_dist,
   6112                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
   6113     else
   6114       distance = ROUND_None(
   6115                    org_dist,
   6116                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
   6117 
   6118     /* minimum distance flag */
   6119 
   6120     if ( ( CUR.opcode & 8 ) != 0 )
   6121     {
   6122       if ( org_dist >= 0 )
   6123       {
   6124         if ( distance < CUR.GS.minimum_distance )
   6125           distance = CUR.GS.minimum_distance;
   6126       }
   6127       else
   6128       {
   6129         if ( distance > -CUR.GS.minimum_distance )
   6130           distance = -CUR.GS.minimum_distance;
   6131       }
   6132     }
   6133 
   6134     /* now move the point */
   6135 
   6136     org_dist = CUR_Func_project( CUR.zp1.cur + point,
   6137                                  CUR.zp0.cur + CUR.GS.rp0 );
   6138 
   6139     CUR_Func_move( &CUR.zp1, point, distance - org_dist );
   6140 
   6141     CUR.GS.rp1 = CUR.GS.rp0;
   6142     CUR.GS.rp2 = point;
   6143 
   6144     if ( ( CUR.opcode & 16 ) != 0 )
   6145       CUR.GS.rp0 = point;
   6146   }
   6147 
   6148 
   6149   /*************************************************************************/
   6150   /*                                                                       */
   6151   /* MIRP[abcde]:  Move Indirect Relative Point                            */
   6152   /* Opcode range: 0xE0-0xFF                                               */
   6153   /* Stack:        int32? uint32 -->                                       */
   6154   /*                                                                       */
   6155   static void
   6156   Ins_MIRP( INS_ARG )
   6157   {
   6158     FT_UShort   point;
   6159     FT_ULong    cvtEntry;
   6160 
   6161     FT_F26Dot6  cvt_dist,
   6162                 distance,
   6163                 cur_dist,
   6164                 org_dist;
   6165 
   6166 
   6167     point    = (FT_UShort)args[0];
   6168     cvtEntry = (FT_ULong)( args[1] + 1 );
   6169 
   6170     /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
   6171 
   6172     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
   6173          BOUNDSL( cvtEntry,  CUR.cvtSize + 1 )  ||
   6174          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
   6175     {
   6176       if ( CUR.pedantic_hinting )
   6177         CUR.error = TT_Err_Invalid_Reference;
   6178       return;
   6179     }
   6180 
   6181     if ( !cvtEntry )
   6182       cvt_dist = 0;
   6183     else
   6184       cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
   6185 
   6186     /* single width test */
   6187 
   6188     if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
   6189          CUR.GS.single_width_cutin )
   6190     {
   6191       if ( cvt_dist >= 0 )
   6192         cvt_dist =  CUR.GS.single_width_value;
   6193       else
   6194         cvt_dist = -CUR.GS.single_width_value;
   6195     }
   6196 
   6197     /* XXX: UNDOCUMENTED! -- twilight zone */
   6198 
   6199     if ( CUR.GS.gep1 == 0 )
   6200     {
   6201       CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
   6202                              TT_MulFix14( (FT_UInt32)cvt_dist,
   6203                                           CUR.GS.freeVector.x );
   6204 
   6205       CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
   6206                              TT_MulFix14( (FT_UInt32)cvt_dist,
   6207                                           CUR.GS.freeVector.y );
   6208 
   6209       CUR.zp1.cur[point] = CUR.zp0.cur[point];
   6210     }
   6211 
   6212     org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
   6213                                   &CUR.zp0.org[CUR.GS.rp0] );
   6214     cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
   6215                                   &CUR.zp0.cur[CUR.GS.rp0] );
   6216 
   6217     /* auto-flip test */
   6218 
   6219     if ( CUR.GS.auto_flip )
   6220     {
   6221       if ( ( org_dist ^ cvt_dist ) < 0 )
   6222         cvt_dist = -cvt_dist;
   6223     }
   6224 
   6225     /* control value cutin and round */
   6226 
   6227     if ( ( CUR.opcode & 4 ) != 0 )
   6228     {
   6229       /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
   6230       /*      refer to the same zone.                                  */
   6231 
   6232       if ( CUR.GS.gep0 == CUR.GS.gep1 )
   6233         if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
   6234           cvt_dist = org_dist;
   6235 
   6236       distance = CUR_Func_round(
   6237                    cvt_dist,
   6238                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
   6239     }
   6240     else
   6241       distance = ROUND_None(
   6242                    cvt_dist,
   6243                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
   6244 
   6245     /* minimum distance test */
   6246 
   6247     if ( ( CUR.opcode & 8 ) != 0 )
   6248     {
   6249       if ( org_dist >= 0 )
   6250       {
   6251         if ( distance < CUR.GS.minimum_distance )
   6252           distance = CUR.GS.minimum_distance;
   6253       }
   6254       else
   6255       {
   6256         if ( distance > -CUR.GS.minimum_distance )
   6257           distance = -CUR.GS.minimum_distance;
   6258       }
   6259     }
   6260 
   6261     CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
   6262 
   6263     CUR.GS.rp1 = CUR.GS.rp0;
   6264 
   6265     if ( ( CUR.opcode & 16 ) != 0 )
   6266       CUR.GS.rp0 = point;
   6267 
   6268     /* XXX: UNDOCUMENTED! */
   6269     CUR.GS.rp2 = point;
   6270   }
   6271 
   6272 
   6273   /*************************************************************************/
   6274   /*                                                                       */
   6275   /* ALIGNRP[]:    ALIGN Relative Point                                    */
   6276   /* Opcode range: 0x3C                                                    */
   6277   /* Stack:        uint32 uint32... -->                                    */
   6278   /*                                                                       */
   6279   static void
   6280   Ins_ALIGNRP( INS_ARG )
   6281   {
   6282     FT_UShort   point;
   6283     FT_F26Dot6  distance;
   6284 
   6285     FT_UNUSED_ARG;
   6286 
   6287 
   6288     if ( CUR.top < CUR.GS.loop ||
   6289          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
   6290     {
   6291       if ( CUR.pedantic_hinting )
   6292         CUR.error = TT_Err_Invalid_Reference;
   6293       return;
   6294     }
   6295 
   6296     while ( CUR.GS.loop > 0 )
   6297     {
   6298       CUR.args--;
   6299 
   6300       point = (FT_UShort)CUR.stack[CUR.args];
   6301 
   6302       if ( BOUNDS( point, CUR.zp1.n_points ) )
   6303       {
   6304         if ( CUR.pedantic_hinting )
   6305         {
   6306           CUR.error = TT_Err_Invalid_Reference;
   6307           return;
   6308         }
   6309       }
   6310       else
   6311       {
   6312         distance = CUR_Func_project( CUR.zp1.cur + point,
   6313                                      CUR.zp0.cur + CUR.GS.rp0 );
   6314 
   6315         CUR_Func_move( &CUR.zp1, point, -distance );
   6316       }
   6317 
   6318       CUR.GS.loop--;
   6319     }
   6320 
   6321     CUR.GS.loop = 1;
   6322     CUR.new_top = CUR.args;
   6323   }
   6324 
   6325 
   6326   /*************************************************************************/
   6327   /*                                                                       */
   6328   /* ISECT[]:      moves point to InterSECTion                             */
   6329   /* Opcode range: 0x0F                                                    */
   6330   /* Stack:        5 * uint32 -->                                          */
   6331   /*                                                                       */
   6332   static void
   6333   Ins_ISECT( INS_ARG )
   6334   {
   6335     FT_UShort   point,
   6336                 a0, a1,
   6337                 b0, b1;
   6338 
   6339     FT_F26Dot6  discriminant;
   6340 
   6341     FT_F26Dot6  dx,  dy,
   6342                 dax, day,
   6343                 dbx, dby;
   6344 
   6345     FT_F26Dot6  val;
   6346 
   6347     FT_Vector   R;
   6348 
   6349 
   6350     point = (FT_UShort)args[0];
   6351 
   6352     a0 = (FT_UShort)args[1];
   6353     a1 = (FT_UShort)args[2];
   6354     b0 = (FT_UShort)args[3];
   6355     b1 = (FT_UShort)args[4];
   6356 
   6357     if ( BOUNDS( b0, CUR.zp0.n_points )  ||
   6358          BOUNDS( b1, CUR.zp0.n_points )  ||
   6359          BOUNDS( a0, CUR.zp1.n_points )  ||
   6360          BOUNDS( a1, CUR.zp1.n_points )  ||
   6361          BOUNDS( point, CUR.zp2.n_points ) )
   6362     {
   6363       if ( CUR.pedantic_hinting )
   6364         CUR.error = TT_Err_Invalid_Reference;
   6365       return;
   6366     }
   6367 
   6368     dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
   6369     dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
   6370 
   6371     dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
   6372     day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
   6373 
   6374     dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
   6375     dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
   6376 
   6377     CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
   6378 
   6379     discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
   6380                    TT_MULDIV( day, dbx, 0x40 );
   6381 
   6382     if ( FT_ABS( discriminant ) >= 0x40 )
   6383     {
   6384       val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
   6385 
   6386       R.x = TT_MULDIV( val, dax, discriminant );
   6387       R.y = TT_MULDIV( val, day, discriminant );
   6388 
   6389       CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
   6390       CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
   6391     }
   6392     else
   6393     {
   6394       /* else, take the middle of the middles of A and B */
   6395 
   6396       CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
   6397                                CUR.zp1.cur[a1].x +
   6398                                CUR.zp0.cur[b0].x +
   6399                                CUR.zp0.cur[b1].x ) / 4;
   6400       CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
   6401                                CUR.zp1.cur[a1].y +
   6402                                CUR.zp0.cur[b0].y +
   6403                                CUR.zp0.cur[b1].y ) / 4;
   6404     }
   6405   }
   6406 
   6407 
   6408   /*************************************************************************/
   6409   /*                                                                       */
   6410   /* ALIGNPTS[]:   ALIGN PoinTS                                            */
   6411   /* Opcode range: 0x27                                                    */
   6412   /* Stack:        uint32 uint32 -->                                       */
   6413   /*                                                                       */
   6414   static void
   6415   Ins_ALIGNPTS( INS_ARG )
   6416   {
   6417     FT_UShort   p1, p2;
   6418     FT_F26Dot6  distance;
   6419 
   6420 
   6421     p1 = (FT_UShort)args[0];
   6422     p2 = (FT_UShort)args[1];
   6423 
   6424     if ( BOUNDS( p1, CUR.zp1.n_points ) ||
   6425          BOUNDS( p2, CUR.zp0.n_points ) )
   6426     {
   6427       if ( CUR.pedantic_hinting )
   6428         CUR.error = TT_Err_Invalid_Reference;
   6429       return;
   6430     }
   6431 
   6432     distance = CUR_Func_project( CUR.zp0.cur + p2,
   6433                                  CUR.zp1.cur + p1 ) / 2;
   6434 
   6435     CUR_Func_move( &CUR.zp1, p1, distance );
   6436     CUR_Func_move( &CUR.zp0, p2, -distance );
   6437   }
   6438 
   6439 
   6440   /*************************************************************************/
   6441   /*                                                                       */
   6442   /* IP[]:         Interpolate Point                                       */
   6443   /* Opcode range: 0x39                                                    */
   6444   /* Stack:        uint32... -->                                           */
   6445   /*                                                                       */
   6446 
   6447   /* SOMETIMES, DUMBER CODE IS BETTER CODE */
   6448 
   6449   static void
   6450   Ins_IP( INS_ARG )
   6451   {
   6452     FT_F26Dot6  old_range, cur_range;
   6453     FT_Vector*  orus_base;
   6454     FT_Vector*  cur_base;
   6455     FT_Int      twilight;
   6456 
   6457     FT_UNUSED_ARG;
   6458 
   6459 
   6460     if ( CUR.top < CUR.GS.loop )
   6461     {
   6462       CUR.error = TT_Err_Invalid_Reference;
   6463       return;
   6464     }
   6465 
   6466     /*
   6467      * We need to deal in a special way with the twilight zone.
   6468      * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
   6469      * for every n.
   6470      */
   6471     twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
   6472 
   6473     if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
   6474     {
   6475       if ( CUR.pedantic_hinting )
   6476         CUR.error = TT_Err_Invalid_Reference;
   6477       return;
   6478     }
   6479 
   6480     if ( twilight )
   6481       orus_base = &CUR.zp0.org[CUR.GS.rp1];
   6482     else
   6483       orus_base = &CUR.zp0.orus[CUR.GS.rp1];
   6484 
   6485     cur_base = &CUR.zp0.cur[CUR.GS.rp1];
   6486 
   6487     /* XXX: There are some glyphs in some braindead but popular */
   6488     /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
   6489     /*      calling IP[] with bad values of rp[12].             */
   6490     /*      Do something sane when this odd thing happens.      */
   6491     if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
   6492          BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
   6493     {
   6494       old_range = 0;
   6495       cur_range = 0;
   6496     }
   6497     else
   6498     {
   6499       if ( twilight )
   6500         old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
   6501                                        orus_base );
   6502       else
   6503         old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
   6504                                        orus_base );
   6505 
   6506       cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
   6507     }
   6508 
   6509     for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
   6510     {
   6511       FT_UInt     point = (FT_UInt)CUR.stack[--CUR.args];
   6512       FT_F26Dot6  org_dist, cur_dist, new_dist;
   6513 
   6514 
   6515       /* check point bounds */
   6516       if ( BOUNDS( point, CUR.zp2.n_points ) )
   6517       {
   6518         if ( CUR.pedantic_hinting )
   6519         {
   6520           CUR.error = TT_Err_Invalid_Reference;
   6521           return;
   6522         }
   6523         continue;
   6524       }
   6525 
   6526       if ( twilight )
   6527         org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
   6528       else
   6529         org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
   6530 
   6531       cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
   6532 
   6533       if ( org_dist )
   6534         new_dist = ( old_range != 0 )
   6535                      ? TT_MULDIV( org_dist, cur_range, old_range )
   6536                      : cur_dist;
   6537       else
   6538         new_dist = 0;
   6539 
   6540       CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
   6541     }
   6542     CUR.GS.loop = 1;
   6543     CUR.new_top = CUR.args;
   6544   }
   6545 
   6546 
   6547   /*************************************************************************/
   6548   /*                                                                       */
   6549   /* UTP[a]:       UnTouch Point                                           */
   6550   /* Opcode range: 0x29                                                    */
   6551   /* Stack:        uint32 -->                                              */
   6552   /*                                                                       */
   6553   static void
   6554   Ins_UTP( INS_ARG )
   6555   {
   6556     FT_UShort  point;
   6557     FT_Byte    mask;
   6558 
   6559 
   6560     point = (FT_UShort)args[0];
   6561 
   6562     if ( BOUNDS( point, CUR.zp0.n_points ) )
   6563     {
   6564       if ( CUR.pedantic_hinting )
   6565         CUR.error = TT_Err_Invalid_Reference;
   6566       return;
   6567     }
   6568 
   6569     mask = 0xFF;
   6570 
   6571     if ( CUR.GS.freeVector.x != 0 )
   6572       mask &= ~FT_CURVE_TAG_TOUCH_X;
   6573 
   6574     if ( CUR.GS.freeVector.y != 0 )
   6575       mask &= ~FT_CURVE_TAG_TOUCH_Y;
   6576 
   6577     CUR.zp0.tags[point] &= mask;
   6578   }
   6579 
   6580 
   6581   /* Local variables for Ins_IUP: */
   6582   typedef struct  IUP_WorkerRec_
   6583   {
   6584     FT_Vector*  orgs;   /* original and current coordinate */
   6585     FT_Vector*  curs;   /* arrays                          */
   6586     FT_Vector*  orus;
   6587     FT_UInt     max_points;
   6588 
   6589   } IUP_WorkerRec, *IUP_Worker;
   6590 
   6591 
   6592   static void
   6593   _iup_worker_shift( IUP_Worker  worker,
   6594                      FT_UInt     p1,
   6595                      FT_UInt     p2,
   6596                      FT_UInt     p )
   6597   {
   6598     FT_UInt     i;
   6599     FT_F26Dot6  dx;
   6600 
   6601 
   6602     dx = worker->curs[p].x - worker->orgs[p].x;
   6603     if ( dx != 0 )
   6604     {
   6605       for ( i = p1; i < p; i++ )
   6606         worker->curs[i].x += dx;
   6607 
   6608       for ( i = p + 1; i <= p2; i++ )
   6609         worker->curs[i].x += dx;
   6610     }
   6611   }
   6612 
   6613 
   6614   static void
   6615   _iup_worker_interpolate( IUP_Worker  worker,
   6616                            FT_UInt     p1,
   6617                            FT_UInt     p2,
   6618                            FT_UInt     ref1,
   6619                            FT_UInt     ref2 )
   6620   {
   6621     FT_UInt     i;
   6622     FT_F26Dot6  orus1, orus2, org1, org2, delta1, delta2;
   6623 
   6624 
   6625     if ( p1 > p2 )
   6626       return;
   6627 
   6628     if ( BOUNDS( ref1, worker->max_points ) ||
   6629          BOUNDS( ref2, worker->max_points ) )
   6630       return;
   6631 
   6632     orus1 = worker->orus[ref1].x;
   6633     orus2 = worker->orus[ref2].x;
   6634 
   6635     if ( orus1 > orus2 )
   6636     {
   6637       FT_F26Dot6  tmp_o;
   6638       FT_UInt     tmp_r;
   6639 
   6640 
   6641       tmp_o = orus1;
   6642       orus1 = orus2;
   6643       orus2 = tmp_o;
   6644 
   6645       tmp_r = ref1;
   6646       ref1  = ref2;
   6647       ref2  = tmp_r;
   6648     }
   6649 
   6650     org1   = worker->orgs[ref1].x;
   6651     org2   = worker->orgs[ref2].x;
   6652     delta1 = worker->curs[ref1].x - org1;
   6653     delta2 = worker->curs[ref2].x - org2;
   6654 
   6655     if ( orus1 == orus2 )
   6656     {
   6657       /* simple shift of untouched points */
   6658       for ( i = p1; i <= p2; i++ )
   6659       {
   6660         FT_F26Dot6  x = worker->orgs[i].x;
   6661 
   6662 
   6663         if ( x <= org1 )
   6664           x += delta1;
   6665         else
   6666           x += delta2;
   6667 
   6668         worker->curs[i].x = x;
   6669       }
   6670     }
   6671     else
   6672     {
   6673       FT_Fixed  scale       = 0;
   6674       FT_Bool   scale_valid = 0;
   6675 
   6676 
   6677       /* interpolation */
   6678       for ( i = p1; i <= p2; i++ )
   6679       {
   6680         FT_F26Dot6  x = worker->orgs[i].x;
   6681 
   6682 
   6683         if ( x <= org1 )
   6684           x += delta1;
   6685 
   6686         else if ( x >= org2 )
   6687           x += delta2;
   6688 
   6689         else
   6690         {
   6691           if ( !scale_valid )
   6692           {
   6693             scale_valid = 1;
   6694             scale       = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
   6695                                      0x10000L, orus2 - orus1 );
   6696           }
   6697 
   6698           x = ( org1 + delta1 ) +
   6699               TT_MULFIX( worker->orus[i].x - orus1, scale );
   6700         }
   6701         worker->curs[i].x = x;
   6702       }
   6703     }
   6704   }
   6705 
   6706 
   6707   /*************************************************************************/
   6708   /*                                                                       */
   6709   /* IUP[a]:       Interpolate Untouched Points                            */
   6710   /* Opcode range: 0x30-0x31                                               */
   6711   /* Stack:        -->                                                     */
   6712   /*                                                                       */
   6713   static void
   6714   Ins_IUP( INS_ARG )
   6715   {
   6716     IUP_WorkerRec  V;
   6717     FT_Byte        mask;
   6718 
   6719     FT_UInt   first_point;   /* first point of contour        */
   6720     FT_UInt   end_point;     /* end point (last+1) of contour */
   6721 
   6722     FT_UInt   first_touched; /* first touched point in contour   */
   6723     FT_UInt   cur_touched;   /* current touched point in contour */
   6724 
   6725     FT_UInt   point;         /* current point   */
   6726     FT_Short  contour;       /* current contour */
   6727 
   6728     FT_UNUSED_ARG;
   6729 
   6730 
   6731     /* ignore empty outlines */
   6732     if ( CUR.pts.n_contours == 0 )
   6733       return;
   6734 
   6735     if ( CUR.opcode & 1 )
   6736     {
   6737       mask   = FT_CURVE_TAG_TOUCH_X;
   6738       V.orgs = CUR.pts.org;
   6739       V.curs = CUR.pts.cur;
   6740       V.orus = CUR.pts.orus;
   6741     }
   6742     else
   6743     {
   6744       mask   = FT_CURVE_TAG_TOUCH_Y;
   6745       V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
   6746       V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
   6747       V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
   6748     }
   6749     V.max_points = CUR.pts.n_points;
   6750 
   6751     contour = 0;
   6752     point   = 0;
   6753 
   6754     do
   6755     {
   6756       end_point   = CUR.pts.contours[contour] - CUR.pts.first_point;
   6757       first_point = point;
   6758 
   6759       if ( BOUNDS ( end_point, CUR.pts.n_points ) )
   6760         end_point = CUR.pts.n_points - 1;
   6761 
   6762       while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
   6763         point++;
   6764 
   6765       if ( point <= end_point )
   6766       {
   6767         first_touched = point;
   6768         cur_touched   = point;
   6769 
   6770         point++;
   6771 
   6772         while ( point <= end_point )
   6773         {
   6774           if ( ( CUR.pts.tags[point] & mask ) != 0 )
   6775           {
   6776             if ( point > 0 )
   6777               _iup_worker_interpolate( &V,
   6778                                        cur_touched + 1,
   6779                                        point - 1,
   6780                                        cur_touched,
   6781                                        point );
   6782             cur_touched = point;
   6783           }
   6784 
   6785           point++;
   6786         }
   6787 
   6788         if ( cur_touched == first_touched )
   6789           _iup_worker_shift( &V, first_point, end_point, cur_touched );
   6790         else
   6791         {
   6792           _iup_worker_interpolate( &V,
   6793                                    (FT_UShort)( cur_touched + 1 ),
   6794                                    end_point,
   6795                                    cur_touched,
   6796                                    first_touched );
   6797 
   6798           if ( first_touched > 0 )
   6799             _iup_worker_interpolate( &V,
   6800                                      first_point,
   6801                                      first_touched - 1,
   6802                                      cur_touched,
   6803                                      first_touched );
   6804         }
   6805       }
   6806       contour++;
   6807     } while ( contour < CUR.pts.n_contours );
   6808   }
   6809 
   6810 
   6811   /*************************************************************************/
   6812   /*                                                                       */
   6813   /* DELTAPn[]:    DELTA exceptions P1, P2, P3                             */
   6814   /* Opcode range: 0x5D,0x71,0x72                                          */
   6815   /* Stack:        uint32 (2 * uint32)... -->                              */
   6816   /*                                                                       */
   6817   static void
   6818   Ins_DELTAP( INS_ARG )
   6819   {
   6820     FT_ULong   k, nump;
   6821     FT_UShort  A;
   6822     FT_ULong   C;
   6823     FT_Long    B;
   6824 
   6825 
   6826 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   6827     /* Delta hinting is covered by US Patent 5159668. */
   6828     if ( CUR.face->unpatented_hinting )
   6829     {
   6830       FT_Long  n = args[0] * 2;
   6831 
   6832 
   6833       if ( CUR.args < n )
   6834       {
   6835         CUR.error = TT_Err_Too_Few_Arguments;
   6836         return;
   6837       }
   6838 
   6839       CUR.args -= n;
   6840       CUR.new_top = CUR.args;
   6841       return;
   6842     }
   6843 #endif
   6844 
   6845     nump = (FT_ULong)args[0];   /* some points theoretically may occur more
   6846                                    than once, thus UShort isn't enough */
   6847 
   6848     for ( k = 1; k <= nump; k++ )
   6849     {
   6850       if ( CUR.args < 2 )
   6851       {
   6852         CUR.error = TT_Err_Too_Few_Arguments;
   6853         return;
   6854       }
   6855 
   6856       CUR.args -= 2;
   6857 
   6858       A = (FT_UShort)CUR.stack[CUR.args + 1];
   6859       B = CUR.stack[CUR.args];
   6860 
   6861       /* XXX: Because some popular fonts contain some invalid DeltaP */
   6862       /*      instructions, we simply ignore them when the stacked   */
   6863       /*      point reference is off limit, rather than returning an */
   6864       /*      error.  As a delta instruction doesn't change a glyph  */
   6865       /*      in great ways, this shouldn't be a problem.            */
   6866 
   6867       if ( !BOUNDS( A, CUR.zp0.n_points ) )
   6868       {
   6869         C = ( (FT_ULong)B & 0xF0 ) >> 4;
   6870 
   6871         switch ( CUR.opcode )
   6872         {
   6873         case 0x5D:
   6874           break;
   6875 
   6876         case 0x71:
   6877           C += 16;
   6878           break;
   6879 
   6880         case 0x72:
   6881           C += 32;
   6882           break;
   6883         }
   6884 
   6885         C += CUR.GS.delta_base;
   6886 
   6887         if ( CURRENT_Ppem() == (FT_Long)C )
   6888         {
   6889           B = ( (FT_ULong)B & 0xF ) - 8;
   6890           if ( B >= 0 )
   6891             B++;
   6892           B = B * 64 / ( 1L << CUR.GS.delta_shift );
   6893 
   6894           CUR_Func_move( &CUR.zp0, A, B );
   6895         }
   6896       }
   6897       else
   6898         if ( CUR.pedantic_hinting )
   6899           CUR.error = TT_Err_Invalid_Reference;
   6900     }
   6901 
   6902     CUR.new_top = CUR.args;
   6903   }
   6904 
   6905 
   6906   /*************************************************************************/
   6907   /*                                                                       */
   6908   /* DELTACn[]:    DELTA exceptions C1, C2, C3                             */
   6909   /* Opcode range: 0x73,0x74,0x75                                          */
   6910   /* Stack:        uint32 (2 * uint32)... -->                              */
   6911   /*                                                                       */
   6912   static void
   6913   Ins_DELTAC( INS_ARG )
   6914   {
   6915     FT_ULong  nump, k;
   6916     FT_ULong  A, C;
   6917     FT_Long   B;
   6918 
   6919 
   6920 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
   6921     /* Delta hinting is covered by US Patent 5159668. */
   6922     if ( CUR.face->unpatented_hinting )
   6923     {
   6924       FT_Long  n = args[0] * 2;
   6925 
   6926 
   6927       if ( CUR.args < n )
   6928       {
   6929         CUR.error = TT_Err_Too_Few_Arguments;
   6930         return;
   6931       }
   6932 
   6933       CUR.args -= n;
   6934       CUR.new_top = CUR.args;
   6935       return;
   6936     }
   6937 #endif
   6938 
   6939     nump = (FT_ULong)args[0];
   6940 
   6941     for ( k = 1; k <= nump; k++ )
   6942     {
   6943       if ( CUR.args < 2 )
   6944       {
   6945         CUR.error = TT_Err_Too_Few_Arguments;
   6946         return;
   6947       }
   6948 
   6949       CUR.args -= 2;
   6950 
   6951       A = (FT_ULong)CUR.stack[CUR.args + 1];
   6952       B = CUR.stack[CUR.args];
   6953 
   6954       if ( BOUNDSL( A, CUR.cvtSize ) )
   6955       {
   6956         if ( CUR.pedantic_hinting )
   6957         {
   6958           CUR.error = TT_Err_Invalid_Reference;
   6959           return;
   6960         }
   6961       }
   6962       else
   6963       {
   6964         C = ( (FT_ULong)B & 0xF0 ) >> 4;
   6965 
   6966         switch ( CUR.opcode )
   6967         {
   6968         case 0x73:
   6969           break;
   6970 
   6971         case 0x74:
   6972           C += 16;
   6973           break;
   6974 
   6975         case 0x75:
   6976           C += 32;
   6977           break;
   6978         }
   6979 
   6980         C += CUR.GS.delta_base;
   6981 
   6982         if ( CURRENT_Ppem() == (FT_Long)C )
   6983         {
   6984           B = ( (FT_ULong)B & 0xF ) - 8;
   6985           if ( B >= 0 )
   6986             B++;
   6987           B = B * 64 / ( 1L << CUR.GS.delta_shift );
   6988 
   6989           CUR_Func_move_cvt( A, B );
   6990         }
   6991       }
   6992     }
   6993 
   6994     CUR.new_top = CUR.args;
   6995   }
   6996 
   6997 
   6998   /*************************************************************************/
   6999   /*                                                                       */
   7000   /* MISC. INSTRUCTIONS                                                    */
   7001   /*                                                                       */
   7002   /*************************************************************************/
   7003 
   7004 
   7005   /*************************************************************************/
   7006   /*                                                                       */
   7007   /* GETINFO[]:    GET INFOrmation                                         */
   7008   /* Opcode range: 0x88                                                    */
   7009   /* Stack:        uint32 --> uint32                                       */
   7010   /*                                                                       */
   7011   static void
   7012   Ins_GETINFO( INS_ARG )
   7013   {
   7014     FT_Long  K;
   7015 
   7016 
   7017     K = 0;
   7018 
   7019     /* We return MS rasterizer version 1.7 for the font scaler. */
   7020     if ( ( args[0] & 1 ) != 0 )
   7021       K = 35;
   7022 
   7023     /* Has the glyph been rotated? */
   7024     if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
   7025       K |= 0x80;
   7026 
   7027     /* Has the glyph been stretched? */
   7028     if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
   7029       K |= 1 << 8;
   7030 
   7031     /* Are we hinting for grayscale? */
   7032     if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
   7033       K |= 1 << 12;
   7034 
   7035     args[0] = K;
   7036   }
   7037 
   7038 
   7039   static void
   7040   Ins_UNKNOWN( INS_ARG )
   7041   {
   7042     TT_DefRecord*  def   = CUR.IDefs;
   7043     TT_DefRecord*  limit = def + CUR.numIDefs;
   7044 
   7045     FT_UNUSED_ARG;
   7046 
   7047 
   7048     for ( ; def < limit; def++ )
   7049     {
   7050       if ( (FT_Byte)def->opc == CUR.opcode && def->active )
   7051       {
   7052         TT_CallRec*  call;
   7053 
   7054 
   7055         if ( CUR.callTop >= CUR.callSize )
   7056         {
   7057           CUR.error = TT_Err_Stack_Overflow;
   7058           return;
   7059         }
   7060 
   7061         call = CUR.callStack + CUR.callTop++;
   7062 
   7063         call->Caller_Range = CUR.curRange;
   7064         call->Caller_IP    = CUR.IP + 1;
   7065         call->Cur_Count    = 1;
   7066         call->Cur_Restart  = def->start;
   7067 
   7068         INS_Goto_CodeRange( def->range, def->start );
   7069 
   7070         CUR.step_ins = FALSE;
   7071         return;
   7072       }
   7073     }
   7074 
   7075     CUR.error = TT_Err_Invalid_Opcode;
   7076   }
   7077 
   7078 
   7079 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
   7080 
   7081 
   7082   static
   7083   TInstruction_Function  Instruct_Dispatch[256] =
   7084   {
   7085     /* Opcodes are gathered in groups of 16. */
   7086     /* Please keep the spaces as they are.   */
   7087 
   7088     /*  SVTCA  y  */  Ins_SVTCA,
   7089     /*  SVTCA  x  */  Ins_SVTCA,
   7090     /*  SPvTCA y  */  Ins_SPVTCA,
   7091     /*  SPvTCA x  */  Ins_SPVTCA,
   7092     /*  SFvTCA y  */  Ins_SFVTCA,
   7093     /*  SFvTCA x  */  Ins_SFVTCA,
   7094     /*  SPvTL //  */  Ins_SPVTL,
   7095     /*  SPvTL +   */  Ins_SPVTL,
   7096     /*  SFvTL //  */  Ins_SFVTL,
   7097     /*  SFvTL +   */  Ins_SFVTL,
   7098     /*  SPvFS     */  Ins_SPVFS,
   7099     /*  SFvFS     */  Ins_SFVFS,
   7100     /*  GPV       */  Ins_GPV,
   7101     /*  GFV       */  Ins_GFV,
   7102     /*  SFvTPv    */  Ins_SFVTPV,
   7103     /*  ISECT     */  Ins_ISECT,
   7104 
   7105     /*  SRP0      */  Ins_SRP0,
   7106     /*  SRP1      */  Ins_SRP1,
   7107     /*  SRP2      */  Ins_SRP2,
   7108     /*  SZP0      */  Ins_SZP0,
   7109     /*  SZP1      */  Ins_SZP1,
   7110     /*  SZP2      */  Ins_SZP2,
   7111     /*  SZPS      */  Ins_SZPS,
   7112     /*  SLOOP     */  Ins_SLOOP,
   7113     /*  RTG       */  Ins_RTG,
   7114     /*  RTHG      */  Ins_RTHG,
   7115     /*  SMD       */  Ins_SMD,
   7116     /*  ELSE      */  Ins_ELSE,
   7117     /*  JMPR      */  Ins_JMPR,
   7118     /*  SCvTCi    */  Ins_SCVTCI,
   7119     /*  SSwCi     */  Ins_SSWCI,
   7120     /*  SSW       */  Ins_SSW,
   7121 
   7122     /*  DUP       */  Ins_DUP,
   7123     /*  POP       */  Ins_POP,
   7124     /*  CLEAR     */  Ins_CLEAR,
   7125     /*  SWAP      */  Ins_SWAP,
   7126     /*  DEPTH     */  Ins_DEPTH,
   7127     /*  CINDEX    */  Ins_CINDEX,
   7128     /*  MINDEX    */  Ins_MINDEX,
   7129     /*  AlignPTS  */  Ins_ALIGNPTS,
   7130     /*  INS_0x28  */  Ins_UNKNOWN,
   7131     /*  UTP       */  Ins_UTP,
   7132     /*  LOOPCALL  */  Ins_LOOPCALL,
   7133     /*  CALL      */  Ins_CALL,
   7134     /*  FDEF      */  Ins_FDEF,
   7135     /*  ENDF      */  Ins_ENDF,
   7136     /*  MDAP[0]   */  Ins_MDAP,
   7137     /*  MDAP[1]   */  Ins_MDAP,
   7138 
   7139     /*  IUP[0]    */  Ins_IUP,
   7140     /*  IUP[1]    */  Ins_IUP,
   7141     /*  SHP[0]    */  Ins_SHP,
   7142     /*  SHP[1]    */  Ins_SHP,
   7143     /*  SHC[0]    */  Ins_SHC,
   7144     /*  SHC[1]    */  Ins_SHC,
   7145     /*  SHZ[0]    */  Ins_SHZ,
   7146     /*  SHZ[1]    */  Ins_SHZ,
   7147     /*  SHPIX     */  Ins_SHPIX,
   7148     /*  IP        */  Ins_IP,
   7149     /*  MSIRP[0]  */  Ins_MSIRP,
   7150     /*  MSIRP[1]  */  Ins_MSIRP,
   7151     /*  AlignRP   */  Ins_ALIGNRP,
   7152     /*  RTDG      */  Ins_RTDG,
   7153     /*  MIAP[0]   */  Ins_MIAP,
   7154     /*  MIAP[1]   */  Ins_MIAP,
   7155 
   7156     /*  NPushB    */  Ins_NPUSHB,
   7157     /*  NPushW    */  Ins_NPUSHW,
   7158     /*  WS        */  Ins_WS,
   7159     /*  RS        */  Ins_RS,
   7160     /*  WCvtP     */  Ins_WCVTP,
   7161     /*  RCvt      */  Ins_RCVT,
   7162     /*  GC[0]     */  Ins_GC,
   7163     /*  GC[1]     */  Ins_GC,
   7164     /*  SCFS      */  Ins_SCFS,
   7165     /*  MD[0]     */  Ins_MD,
   7166     /*  MD[1]     */  Ins_MD,
   7167     /*  MPPEM     */  Ins_MPPEM,
   7168     /*  MPS       */  Ins_MPS,
   7169     /*  FlipON    */  Ins_FLIPON,
   7170     /*  FlipOFF   */  Ins_FLIPOFF,
   7171     /*  DEBUG     */  Ins_DEBUG,
   7172 
   7173     /*  LT        */  Ins_LT,
   7174     /*  LTEQ      */  Ins_LTEQ,
   7175     /*  GT        */  Ins_GT,
   7176     /*  GTEQ      */  Ins_GTEQ,
   7177     /*  EQ        */  Ins_EQ,
   7178     /*  NEQ       */  Ins_NEQ,
   7179     /*  ODD       */  Ins_ODD,
   7180     /*  EVEN      */  Ins_EVEN,
   7181     /*  IF        */  Ins_IF,
   7182     /*  EIF       */  Ins_EIF,
   7183     /*  AND       */  Ins_AND,
   7184     /*  OR        */  Ins_OR,
   7185     /*  NOT       */  Ins_NOT,
   7186     /*  DeltaP1   */  Ins_DELTAP,
   7187     /*  SDB       */  Ins_SDB,
   7188     /*  SDS       */  Ins_SDS,
   7189 
   7190     /*  ADD       */  Ins_ADD,
   7191     /*  SUB       */  Ins_SUB,
   7192     /*  DIV       */  Ins_DIV,
   7193     /*  MUL       */  Ins_MUL,
   7194     /*  ABS       */  Ins_ABS,
   7195     /*  NEG       */  Ins_NEG,
   7196     /*  FLOOR     */  Ins_FLOOR,
   7197     /*  CEILING   */  Ins_CEILING,
   7198     /*  ROUND[0]  */  Ins_ROUND,
   7199     /*  ROUND[1]  */  Ins_ROUND,
   7200     /*  ROUND[2]  */  Ins_ROUND,
   7201     /*  ROUND[3]  */  Ins_ROUND,
   7202     /*  NROUND[0] */  Ins_NROUND,
   7203     /*  NROUND[1] */  Ins_NROUND,
   7204     /*  NROUND[2] */  Ins_NROUND,
   7205     /*  NROUND[3] */  Ins_NROUND,
   7206 
   7207     /*  WCvtF     */  Ins_WCVTF,
   7208     /*  DeltaP2   */  Ins_DELTAP,
   7209     /*  DeltaP3   */  Ins_DELTAP,
   7210     /*  DeltaCn[0] */ Ins_DELTAC,
   7211     /*  DeltaCn[1] */ Ins_DELTAC,
   7212     /*  DeltaCn[2] */ Ins_DELTAC,
   7213     /*  SROUND    */  Ins_SROUND,
   7214     /*  S45Round  */  Ins_S45ROUND,
   7215     /*  JROT      */  Ins_JROT,
   7216     /*  JROF      */  Ins_JROF,
   7217     /*  ROFF      */  Ins_ROFF,
   7218     /*  INS_0x7B  */  Ins_UNKNOWN,
   7219     /*  RUTG      */  Ins_RUTG,
   7220     /*  RDTG      */  Ins_RDTG,
   7221     /*  SANGW     */  Ins_SANGW,
   7222     /*  AA        */  Ins_AA,
   7223 
   7224     /*  FlipPT    */  Ins_FLIPPT,
   7225     /*  FlipRgON  */  Ins_FLIPRGON,
   7226     /*  FlipRgOFF */  Ins_FLIPRGOFF,
   7227     /*  INS_0x83  */  Ins_UNKNOWN,
   7228     /*  INS_0x84  */  Ins_UNKNOWN,
   7229     /*  ScanCTRL  */  Ins_SCANCTRL,
   7230     /*  SDPVTL[0] */  Ins_SDPVTL,
   7231     /*  SDPVTL[1] */  Ins_SDPVTL,
   7232     /*  GetINFO   */  Ins_GETINFO,
   7233     /*  IDEF      */  Ins_IDEF,
   7234     /*  ROLL      */  Ins_ROLL,
   7235     /*  MAX       */  Ins_MAX,
   7236     /*  MIN       */  Ins_MIN,
   7237     /*  ScanTYPE  */  Ins_SCANTYPE,
   7238     /*  InstCTRL  */  Ins_INSTCTRL,
   7239     /*  INS_0x8F  */  Ins_UNKNOWN,
   7240 
   7241     /*  INS_0x90  */   Ins_UNKNOWN,
   7242     /*  INS_0x91  */   Ins_UNKNOWN,
   7243     /*  INS_0x92  */   Ins_UNKNOWN,
   7244     /*  INS_0x93  */   Ins_UNKNOWN,
   7245     /*  INS_0x94  */   Ins_UNKNOWN,
   7246     /*  INS_0x95  */   Ins_UNKNOWN,
   7247     /*  INS_0x96  */   Ins_UNKNOWN,
   7248     /*  INS_0x97  */   Ins_UNKNOWN,
   7249     /*  INS_0x98  */   Ins_UNKNOWN,
   7250     /*  INS_0x99  */   Ins_UNKNOWN,
   7251     /*  INS_0x9A  */   Ins_UNKNOWN,
   7252     /*  INS_0x9B  */   Ins_UNKNOWN,
   7253     /*  INS_0x9C  */   Ins_UNKNOWN,
   7254     /*  INS_0x9D  */   Ins_UNKNOWN,
   7255     /*  INS_0x9E  */   Ins_UNKNOWN,
   7256     /*  INS_0x9F  */   Ins_UNKNOWN,
   7257 
   7258     /*  INS_0xA0  */   Ins_UNKNOWN,
   7259     /*  INS_0xA1  */   Ins_UNKNOWN,
   7260     /*  INS_0xA2  */   Ins_UNKNOWN,
   7261     /*  INS_0xA3  */   Ins_UNKNOWN,
   7262     /*  INS_0xA4  */   Ins_UNKNOWN,
   7263     /*  INS_0xA5  */   Ins_UNKNOWN,
   7264     /*  INS_0xA6  */   Ins_UNKNOWN,
   7265     /*  INS_0xA7  */   Ins_UNKNOWN,
   7266     /*  INS_0xA8  */   Ins_UNKNOWN,
   7267     /*  INS_0xA9  */   Ins_UNKNOWN,
   7268     /*  INS_0xAA  */   Ins_UNKNOWN,
   7269     /*  INS_0xAB  */   Ins_UNKNOWN,
   7270     /*  INS_0xAC  */   Ins_UNKNOWN,
   7271     /*  INS_0xAD  */   Ins_UNKNOWN,
   7272     /*  INS_0xAE  */   Ins_UNKNOWN,
   7273     /*  INS_0xAF  */   Ins_UNKNOWN,
   7274 
   7275     /*  PushB[0]  */  Ins_PUSHB,
   7276     /*  PushB[1]  */  Ins_PUSHB,
   7277     /*  PushB[2]  */  Ins_PUSHB,
   7278     /*  PushB[3]  */  Ins_PUSHB,
   7279     /*  PushB[4]  */  Ins_PUSHB,
   7280     /*  PushB[5]  */  Ins_PUSHB,
   7281     /*  PushB[6]  */  Ins_PUSHB,
   7282     /*  PushB[7]  */  Ins_PUSHB,
   7283     /*  PushW[0]  */  Ins_PUSHW,
   7284     /*  PushW[1]  */  Ins_PUSHW,
   7285     /*  PushW[2]  */  Ins_PUSHW,
   7286     /*  PushW[3]  */  Ins_PUSHW,
   7287     /*  PushW[4]  */  Ins_PUSHW,
   7288     /*  PushW[5]  */  Ins_PUSHW,
   7289     /*  PushW[6]  */  Ins_PUSHW,
   7290     /*  PushW[7]  */  Ins_PUSHW,
   7291 
   7292     /*  MDRP[00]  */  Ins_MDRP,
   7293     /*  MDRP[01]  */  Ins_MDRP,
   7294     /*  MDRP[02]  */  Ins_MDRP,
   7295     /*  MDRP[03]  */  Ins_MDRP,
   7296     /*  MDRP[04]  */  Ins_MDRP,
   7297     /*  MDRP[05]  */  Ins_MDRP,
   7298     /*  MDRP[06]  */  Ins_MDRP,
   7299     /*  MDRP[07]  */  Ins_MDRP,
   7300     /*  MDRP[08]  */  Ins_MDRP,
   7301     /*  MDRP[09]  */  Ins_MDRP,
   7302     /*  MDRP[10]  */  Ins_MDRP,
   7303     /*  MDRP[11]  */  Ins_MDRP,
   7304     /*  MDRP[12]  */  Ins_MDRP,
   7305     /*  MDRP[13]  */  Ins_MDRP,
   7306     /*  MDRP[14]  */  Ins_MDRP,
   7307     /*  MDRP[15]  */  Ins_MDRP,
   7308 
   7309     /*  MDRP[16]  */  Ins_MDRP,
   7310     /*  MDRP[17]  */  Ins_MDRP,
   7311     /*  MDRP[18]  */  Ins_MDRP,
   7312     /*  MDRP[19]  */  Ins_MDRP,
   7313     /*  MDRP[20]  */  Ins_MDRP,
   7314     /*  MDRP[21]  */  Ins_MDRP,
   7315     /*  MDRP[22]  */  Ins_MDRP,
   7316     /*  MDRP[23]  */  Ins_MDRP,
   7317     /*  MDRP[24]  */  Ins_MDRP,
   7318     /*  MDRP[25]  */  Ins_MDRP,
   7319     /*  MDRP[26]  */  Ins_MDRP,
   7320     /*  MDRP[27]  */  Ins_MDRP,
   7321     /*  MDRP[28]  */  Ins_MDRP,
   7322     /*  MDRP[29]  */  Ins_MDRP,
   7323     /*  MDRP[30]  */  Ins_MDRP,
   7324     /*  MDRP[31]  */  Ins_MDRP,
   7325 
   7326     /*  MIRP[00]  */  Ins_MIRP,
   7327     /*  MIRP[01]  */  Ins_MIRP,
   7328     /*  MIRP[02]  */  Ins_MIRP,
   7329     /*  MIRP[03]  */  Ins_MIRP,
   7330     /*  MIRP[04]  */  Ins_MIRP,
   7331     /*  MIRP[05]  */  Ins_MIRP,
   7332     /*  MIRP[06]  */  Ins_MIRP,
   7333     /*  MIRP[07]  */  Ins_MIRP,
   7334     /*  MIRP[08]  */  Ins_MIRP,
   7335     /*  MIRP[09]  */  Ins_MIRP,
   7336     /*  MIRP[10]  */  Ins_MIRP,
   7337     /*  MIRP[11]  */  Ins_MIRP,
   7338     /*  MIRP[12]  */  Ins_MIRP,
   7339     /*  MIRP[13]  */  Ins_MIRP,
   7340     /*  MIRP[14]  */  Ins_MIRP,
   7341     /*  MIRP[15]  */  Ins_MIRP,
   7342 
   7343     /*  MIRP[16]  */  Ins_MIRP,
   7344     /*  MIRP[17]  */  Ins_MIRP,
   7345     /*  MIRP[18]  */  Ins_MIRP,
   7346     /*  MIRP[19]  */  Ins_MIRP,
   7347     /*  MIRP[20]  */  Ins_MIRP,
   7348     /*  MIRP[21]  */  Ins_MIRP,
   7349     /*  MIRP[22]  */  Ins_MIRP,
   7350     /*  MIRP[23]  */  Ins_MIRP,
   7351     /*  MIRP[24]  */  Ins_MIRP,
   7352     /*  MIRP[25]  */  Ins_MIRP,
   7353     /*  MIRP[26]  */  Ins_MIRP,
   7354     /*  MIRP[27]  */  Ins_MIRP,
   7355     /*  MIRP[28]  */  Ins_MIRP,
   7356     /*  MIRP[29]  */  Ins_MIRP,
   7357     /*  MIRP[30]  */  Ins_MIRP,
   7358     /*  MIRP[31]  */  Ins_MIRP
   7359   };
   7360 
   7361 
   7362 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
   7363 
   7364 
   7365   /*************************************************************************/
   7366   /*                                                                       */
   7367   /* RUN                                                                   */
   7368   /*                                                                       */
   7369   /*  This function executes a run of opcodes.  It will exit in the        */
   7370   /*  following cases:                                                     */
   7371   /*                                                                       */
   7372   /*  - Errors (in which case it returns FALSE).                           */
   7373   /*                                                                       */
   7374   /*  - Reaching the end of the main code range (returns TRUE).            */
   7375   /*    Reaching the end of a code range within a function call is an      */
   7376   /*    error.                                                             */
   7377   /*                                                                       */
   7378   /*  - After executing one single opcode, if the flag `Instruction_Trap'  */
   7379   /*    is set to TRUE (returns TRUE).                                     */
   7380   /*                                                                       */
   7381   /*  On exit with TRUE, test IP < CodeSize to know whether it comes from  */
   7382   /*  an instruction trap or a normal termination.                         */
   7383   /*                                                                       */
   7384   /*                                                                       */
   7385   /*  Note: The documented DEBUG opcode pops a value from the stack.  This */
   7386   /*        behaviour is unsupported; here a DEBUG opcode is always an     */
   7387   /*        error.                                                         */
   7388   /*                                                                       */
   7389   /*                                                                       */
   7390   /* THIS IS THE INTERPRETER'S MAIN LOOP.                                  */
   7391   /*                                                                       */
   7392   /*  Instructions appear in the specification's order.                    */
   7393   /*                                                                       */
   7394   /*************************************************************************/
   7395 
   7396 
   7397   /* documentation is in ttinterp.h */
   7398 
   7399   FT_EXPORT_DEF( FT_Error )
   7400   TT_RunIns( TT_ExecContext  exc )
   7401   {
   7402     FT_Long  ins_counter = 0;  /* executed instructions counter */
   7403 
   7404 
   7405 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
   7406     cur = *exc;
   7407 #endif
   7408 
   7409     /* set CVT functions */
   7410     CUR.tt_metrics.ratio = 0;
   7411     if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
   7412     {
   7413       /* non-square pixels, use the stretched routines */
   7414       CUR.func_read_cvt  = Read_CVT_Stretched;
   7415       CUR.func_write_cvt = Write_CVT_Stretched;
   7416       CUR.func_move_cvt  = Move_CVT_Stretched;
   7417     }
   7418     else
   7419     {
   7420       /* square pixels, use normal routines */
   7421       CUR.func_read_cvt  = Read_CVT;
   7422       CUR.func_write_cvt = Write_CVT;
   7423       CUR.func_move_cvt  = Move_CVT;
   7424     }
   7425 
   7426     COMPUTE_Funcs();
   7427     COMPUTE_Round( (FT_Byte)exc->GS.round_state );
   7428 
   7429     do
   7430     {
   7431       CUR.opcode = CUR.code[CUR.IP];
   7432 
   7433       FT_TRACE7(( "  " ));
   7434       FT_TRACE7(( opcode_name[CUR.opcode] ));
   7435       FT_TRACE7(( "\n" ));
   7436 
   7437       if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
   7438       {
   7439         if ( CUR.IP + 1 > CUR.codeSize )
   7440           goto LErrorCodeOverflow_;
   7441 
   7442         CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
   7443       }
   7444 
   7445       if ( CUR.IP + CUR.length > CUR.codeSize )
   7446         goto LErrorCodeOverflow_;
   7447 
   7448       /* First, let's check for empty stack and overflow */
   7449       CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
   7450 
   7451       /* `args' is the top of the stack once arguments have been popped. */
   7452       /* One can also interpret it as the index of the last argument.    */
   7453       if ( CUR.args < 0 )
   7454       {
   7455         CUR.error = TT_Err_Too_Few_Arguments;
   7456         goto LErrorLabel_;
   7457       }
   7458 
   7459       CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
   7460 
   7461       /* `new_top' is the new top of the stack, after the instruction's */
   7462       /* execution.  `top' will be set to `new_top' after the `switch'  */
   7463       /* statement.                                                     */
   7464       if ( CUR.new_top > CUR.stackSize )
   7465       {
   7466         CUR.error = TT_Err_Stack_Overflow;
   7467         goto LErrorLabel_;
   7468       }
   7469 
   7470       CUR.step_ins = TRUE;
   7471       CUR.error    = TT_Err_Ok;
   7472 
   7473 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
   7474 
   7475       {
   7476         FT_Long*  args   = CUR.stack + CUR.args;
   7477         FT_Byte   opcode = CUR.opcode;
   7478 
   7479 
   7480 #undef  ARRAY_BOUND_ERROR
   7481 #define ARRAY_BOUND_ERROR  goto Set_Invalid_Ref
   7482 
   7483 
   7484         switch ( opcode )
   7485         {
   7486         case 0x00:  /* SVTCA y  */
   7487         case 0x01:  /* SVTCA x  */
   7488         case 0x02:  /* SPvTCA y */
   7489         case 0x03:  /* SPvTCA x */
   7490         case 0x04:  /* SFvTCA y */
   7491         case 0x05:  /* SFvTCA x */
   7492           {
   7493             FT_Short AA, BB;
   7494 
   7495 
   7496             AA = (FT_Short)( ( opcode & 1 ) << 14 );
   7497             BB = (FT_Short)( AA ^ 0x4000 );
   7498 
   7499             if ( opcode < 4 )
   7500             {
   7501               CUR.GS.projVector.x = AA;
   7502               CUR.GS.projVector.y = BB;
   7503 
   7504               CUR.GS.dualVector.x = AA;
   7505               CUR.GS.dualVector.y = BB;
   7506             }
   7507             else
   7508             {
   7509               GUESS_VECTOR( projVector );
   7510             }
   7511 
   7512             if ( ( opcode & 2 ) == 0 )
   7513             {
   7514               CUR.GS.freeVector.x = AA;
   7515               CUR.GS.freeVector.y = BB;
   7516             }
   7517             else
   7518             {
   7519               GUESS_VECTOR( freeVector );
   7520             }
   7521 
   7522             COMPUTE_Funcs();
   7523           }
   7524           break;
   7525 
   7526         case 0x06:  /* SPvTL // */
   7527         case 0x07:  /* SPvTL +  */
   7528           DO_SPVTL
   7529           break;
   7530 
   7531         case 0x08:  /* SFvTL // */
   7532         case 0x09:  /* SFvTL +  */
   7533           DO_SFVTL
   7534           break;
   7535 
   7536         case 0x0A:  /* SPvFS */
   7537           DO_SPVFS
   7538           break;
   7539 
   7540         case 0x0B:  /* SFvFS */
   7541           DO_SFVFS
   7542           break;
   7543 
   7544         case 0x0C:  /* GPV */
   7545           DO_GPV
   7546           break;
   7547 
   7548         case 0x0D:  /* GFV */
   7549           DO_GFV
   7550           break;
   7551 
   7552         case 0x0E:  /* SFvTPv */
   7553           DO_SFVTPV
   7554           break;
   7555 
   7556         case 0x0F:  /* ISECT  */
   7557           Ins_ISECT( EXEC_ARG_ args );
   7558           break;
   7559 
   7560         case 0x10:  /* SRP0 */
   7561           DO_SRP0
   7562           break;
   7563 
   7564         case 0x11:  /* SRP1 */
   7565           DO_SRP1
   7566           break;
   7567 
   7568         case 0x12:  /* SRP2 */
   7569           DO_SRP2
   7570           break;
   7571 
   7572         case 0x13:  /* SZP0 */
   7573           Ins_SZP0( EXEC_ARG_ args );
   7574           break;
   7575 
   7576         case 0x14:  /* SZP1 */
   7577           Ins_SZP1( EXEC_ARG_ args );
   7578           break;
   7579 
   7580         case 0x15:  /* SZP2 */
   7581           Ins_SZP2( EXEC_ARG_ args );
   7582           break;
   7583 
   7584         case 0x16:  /* SZPS */
   7585           Ins_SZPS( EXEC_ARG_ args );
   7586           break;
   7587 
   7588         case 0x17:  /* SLOOP */
   7589           DO_SLOOP
   7590           break;
   7591 
   7592         case 0x18:  /* RTG */
   7593           DO_RTG
   7594           break;
   7595 
   7596         case 0x19:  /* RTHG */
   7597           DO_RTHG
   7598           break;
   7599 
   7600         case 0x1A:  /* SMD */
   7601           DO_SMD
   7602           break;
   7603 
   7604         case 0x1B:  /* ELSE */
   7605           Ins_ELSE( EXEC_ARG_ args );
   7606           break;
   7607 
   7608         case 0x1C:  /* JMPR */
   7609           DO_JMPR
   7610           break;
   7611 
   7612         case 0x1D:  /* SCVTCI */
   7613           DO_SCVTCI
   7614           break;
   7615 
   7616         case 0x1E:  /* SSWCI */
   7617           DO_SSWCI
   7618           break;
   7619 
   7620         case 0x1F:  /* SSW */
   7621           DO_SSW
   7622           break;
   7623 
   7624         case 0x20:  /* DUP */
   7625           DO_DUP
   7626           break;
   7627 
   7628         case 0x21:  /* POP */
   7629           /* nothing :-) */
   7630           break;
   7631 
   7632         case 0x22:  /* CLEAR */
   7633           DO_CLEAR
   7634           break;
   7635 
   7636         case 0x23:  /* SWAP */
   7637           DO_SWAP
   7638           break;
   7639 
   7640         case 0x24:  /* DEPTH */
   7641           DO_DEPTH
   7642           break;
   7643 
   7644         case 0x25:  /* CINDEX */
   7645           DO_CINDEX
   7646           break;
   7647 
   7648         case 0x26:  /* MINDEX */
   7649           Ins_MINDEX( EXEC_ARG_ args );
   7650           break;
   7651 
   7652         case 0x27:  /* ALIGNPTS */
   7653           Ins_ALIGNPTS( EXEC_ARG_ args );
   7654           break;
   7655 
   7656         case 0x28:  /* ???? */
   7657           Ins_UNKNOWN( EXEC_ARG_ args );
   7658           break;
   7659 
   7660         case 0x29:  /* UTP */
   7661           Ins_UTP( EXEC_ARG_ args );
   7662           break;
   7663 
   7664         case 0x2A:  /* LOOPCALL */
   7665           Ins_LOOPCALL( EXEC_ARG_ args );
   7666           break;
   7667 
   7668         case 0x2B:  /* CALL */
   7669           Ins_CALL( EXEC_ARG_ args );
   7670           break;
   7671 
   7672         case 0x2C:  /* FDEF */
   7673           Ins_FDEF( EXEC_ARG_ args );
   7674           break;
   7675 
   7676         case 0x2D:  /* ENDF */
   7677           Ins_ENDF( EXEC_ARG_ args );
   7678           break;
   7679 
   7680         case 0x2E:  /* MDAP */
   7681         case 0x2F:  /* MDAP */
   7682           Ins_MDAP( EXEC_ARG_ args );
   7683           break;
   7684 
   7685 
   7686         case 0x30:  /* IUP */
   7687         case 0x31:  /* IUP */
   7688           Ins_IUP( EXEC_ARG_ args );
   7689           break;
   7690 
   7691         case 0x32:  /* SHP */
   7692         case 0x33:  /* SHP */
   7693           Ins_SHP( EXEC_ARG_ args );
   7694           break;
   7695 
   7696         case 0x34:  /* SHC */
   7697         case 0x35:  /* SHC */
   7698           Ins_SHC( EXEC_ARG_ args );
   7699           break;
   7700 
   7701         case 0x36:  /* SHZ */
   7702         case 0x37:  /* SHZ */
   7703           Ins_SHZ( EXEC_ARG_ args );
   7704           break;
   7705 
   7706         case 0x38:  /* SHPIX */
   7707           Ins_SHPIX( EXEC_ARG_ args );
   7708           break;
   7709 
   7710         case 0x39:  /* IP    */
   7711           Ins_IP( EXEC_ARG_ args );
   7712           break;
   7713 
   7714         case 0x3A:  /* MSIRP */
   7715         case 0x3B:  /* MSIRP */
   7716           Ins_MSIRP( EXEC_ARG_ args );
   7717           break;
   7718 
   7719         case 0x3C:  /* AlignRP */
   7720           Ins_ALIGNRP( EXEC_ARG_ args );
   7721           break;
   7722 
   7723         case 0x3D:  /* RTDG */
   7724           DO_RTDG
   7725           break;
   7726 
   7727         case 0x3E:  /* MIAP */
   7728         case 0x3F:  /* MIAP */
   7729           Ins_MIAP( EXEC_ARG_ args );
   7730           break;
   7731 
   7732         case 0x40:  /* NPUSHB */
   7733           Ins_NPUSHB( EXEC_ARG_ args );
   7734           break;
   7735 
   7736         case 0x41:  /* NPUSHW */
   7737           Ins_NPUSHW( EXEC_ARG_ args );
   7738           break;
   7739 
   7740         case 0x42:  /* WS */
   7741           DO_WS
   7742           break;
   7743 
   7744       Set_Invalid_Ref:
   7745             CUR.error = TT_Err_Invalid_Reference;
   7746           break;
   7747 
   7748         case 0x43:  /* RS */
   7749           DO_RS
   7750           break;
   7751 
   7752         case 0x44:  /* WCVTP */
   7753           DO_WCVTP
   7754           break;
   7755 
   7756         case 0x45:  /* RCVT */
   7757           DO_RCVT
   7758           break;
   7759 
   7760         case 0x46:  /* GC */
   7761         case 0x47:  /* GC */
   7762           Ins_GC( EXEC_ARG_ args );
   7763           break;
   7764 
   7765         case 0x48:  /* SCFS */
   7766           Ins_SCFS( EXEC_ARG_ args );
   7767           break;
   7768 
   7769         case 0x49:  /* MD */
   7770         case 0x4A:  /* MD */
   7771           Ins_MD( EXEC_ARG_ args );
   7772           break;
   7773 
   7774         case 0x4B:  /* MPPEM */
   7775           DO_MPPEM
   7776           break;
   7777 
   7778         case 0x4C:  /* MPS */
   7779           DO_MPS
   7780           break;
   7781 
   7782         case 0x4D:  /* FLIPON */
   7783           DO_FLIPON
   7784           break;
   7785 
   7786         case 0x4E:  /* FLIPOFF */
   7787           DO_FLIPOFF
   7788           break;
   7789 
   7790         case 0x4F:  /* DEBUG */
   7791           DO_DEBUG
   7792           break;
   7793 
   7794         case 0x50:  /* LT */
   7795           DO_LT
   7796           break;
   7797 
   7798         case 0x51:  /* LTEQ */
   7799           DO_LTEQ
   7800           break;
   7801 
   7802         case 0x52:  /* GT */
   7803           DO_GT
   7804           break;
   7805 
   7806         case 0x53:  /* GTEQ */
   7807           DO_GTEQ
   7808           break;
   7809 
   7810         case 0x54:  /* EQ */
   7811           DO_EQ
   7812           break;
   7813 
   7814         case 0x55:  /* NEQ */
   7815           DO_NEQ
   7816           break;
   7817 
   7818         case 0x56:  /* ODD */
   7819           DO_ODD
   7820           break;
   7821 
   7822         case 0x57:  /* EVEN */
   7823           DO_EVEN
   7824           break;
   7825 
   7826         case 0x58:  /* IF */
   7827           Ins_IF( EXEC_ARG_ args );
   7828           break;
   7829 
   7830         case 0x59:  /* EIF */
   7831           /* do nothing */
   7832           break;
   7833 
   7834         case 0x5A:  /* AND */
   7835           DO_AND
   7836           break;
   7837 
   7838         case 0x5B:  /* OR */
   7839           DO_OR
   7840           break;
   7841 
   7842         case 0x5C:  /* NOT */
   7843           DO_NOT
   7844           break;
   7845 
   7846         case 0x5D:  /* DELTAP1 */
   7847           Ins_DELTAP( EXEC_ARG_ args );
   7848           break;
   7849 
   7850         case 0x5E:  /* SDB */
   7851           DO_SDB
   7852           break;
   7853 
   7854         case 0x5F:  /* SDS */
   7855           DO_SDS
   7856           break;
   7857 
   7858         case 0x60:  /* ADD */
   7859           DO_ADD
   7860           break;
   7861 
   7862         case 0x61:  /* SUB */
   7863           DO_SUB
   7864           break;
   7865 
   7866         case 0x62:  /* DIV */
   7867           DO_DIV
   7868           break;
   7869 
   7870         case 0x63:  /* MUL */
   7871           DO_MUL
   7872           break;
   7873 
   7874         case 0x64:  /* ABS */
   7875           DO_ABS
   7876           break;
   7877 
   7878         case 0x65:  /* NEG */
   7879           DO_NEG
   7880           break;
   7881 
   7882         case 0x66:  /* FLOOR */
   7883           DO_FLOOR
   7884           break;
   7885 
   7886         case 0x67:  /* CEILING */
   7887           DO_CEILING
   7888           break;
   7889 
   7890         case 0x68:  /* ROUND */
   7891         case 0x69:  /* ROUND */
   7892         case 0x6A:  /* ROUND */
   7893         case 0x6B:  /* ROUND */
   7894           DO_ROUND
   7895           break;
   7896 
   7897         case 0x6C:  /* NROUND */
   7898         case 0x6D:  /* NROUND */
   7899         case 0x6E:  /* NRRUND */
   7900         case 0x6F:  /* NROUND */
   7901           DO_NROUND
   7902           break;
   7903 
   7904         case 0x70:  /* WCVTF */
   7905           DO_WCVTF
   7906           break;
   7907 
   7908         case 0x71:  /* DELTAP2 */
   7909         case 0x72:  /* DELTAP3 */
   7910           Ins_DELTAP( EXEC_ARG_ args );
   7911           break;
   7912 
   7913         case 0x73:  /* DELTAC0 */
   7914         case 0x74:  /* DELTAC1 */
   7915         case 0x75:  /* DELTAC2 */
   7916           Ins_DELTAC( EXEC_ARG_ args );
   7917           break;
   7918 
   7919         case 0x76:  /* SROUND */
   7920           DO_SROUND
   7921           break;
   7922 
   7923         case 0x77:  /* S45Round */
   7924           DO_S45ROUND
   7925           break;
   7926 
   7927         case 0x78:  /* JROT */
   7928           DO_JROT
   7929           break;
   7930 
   7931         case 0x79:  /* JROF */
   7932           DO_JROF
   7933           break;
   7934 
   7935         case 0x7A:  /* ROFF */
   7936           DO_ROFF
   7937           break;
   7938 
   7939         case 0x7B:  /* ???? */
   7940           Ins_UNKNOWN( EXEC_ARG_ args );
   7941           break;
   7942 
   7943         case 0x7C:  /* RUTG */
   7944           DO_RUTG
   7945           break;
   7946 
   7947         case 0x7D:  /* RDTG */
   7948           DO_RDTG
   7949           break;
   7950 
   7951         case 0x7E:  /* SANGW */
   7952         case 0x7F:  /* AA    */
   7953           /* nothing - obsolete */
   7954           break;
   7955 
   7956         case 0x80:  /* FLIPPT */
   7957           Ins_FLIPPT( EXEC_ARG_ args );
   7958           break;
   7959 
   7960         case 0x81:  /* FLIPRGON */
   7961           Ins_FLIPRGON( EXEC_ARG_ args );
   7962           break;
   7963 
   7964         case 0x82:  /* FLIPRGOFF */
   7965           Ins_FLIPRGOFF( EXEC_ARG_ args );
   7966           break;
   7967 
   7968         case 0x83:  /* UNKNOWN */
   7969         case 0x84:  /* UNKNOWN */
   7970           Ins_UNKNOWN( EXEC_ARG_ args );
   7971           break;
   7972 
   7973         case 0x85:  /* SCANCTRL */
   7974           Ins_SCANCTRL( EXEC_ARG_ args );
   7975           break;
   7976 
   7977         case 0x86:  /* SDPVTL */
   7978         case 0x87:  /* SDPVTL */
   7979           Ins_SDPVTL( EXEC_ARG_ args );
   7980           break;
   7981 
   7982         case 0x88:  /* GETINFO */
   7983           Ins_GETINFO( EXEC_ARG_ args );
   7984           break;
   7985 
   7986         case 0x89:  /* IDEF */
   7987           Ins_IDEF( EXEC_ARG_ args );
   7988           break;
   7989 
   7990         case 0x8A:  /* ROLL */
   7991           Ins_ROLL( EXEC_ARG_ args );
   7992           break;
   7993 
   7994         case 0x8B:  /* MAX */
   7995           DO_MAX
   7996           break;
   7997 
   7998         case 0x8C:  /* MIN */
   7999           DO_MIN
   8000           break;
   8001 
   8002         case 0x8D:  /* SCANTYPE */
   8003           Ins_SCANTYPE( EXEC_ARG_ args );
   8004           break;
   8005 
   8006         case 0x8E:  /* INSTCTRL */
   8007           Ins_INSTCTRL( EXEC_ARG_ args );
   8008           break;
   8009 
   8010         case 0x8F:
   8011           Ins_UNKNOWN( EXEC_ARG_ args );
   8012           break;
   8013 
   8014         default:
   8015           if ( opcode >= 0xE0 )
   8016             Ins_MIRP( EXEC_ARG_ args );
   8017           else if ( opcode >= 0xC0 )
   8018             Ins_MDRP( EXEC_ARG_ args );
   8019           else if ( opcode >= 0xB8 )
   8020             Ins_PUSHW( EXEC_ARG_ args );
   8021           else if ( opcode >= 0xB0 )
   8022             Ins_PUSHB( EXEC_ARG_ args );
   8023           else
   8024             Ins_UNKNOWN( EXEC_ARG_ args );
   8025         }
   8026 
   8027       }
   8028 
   8029 #else
   8030 
   8031       Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
   8032 
   8033 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
   8034 
   8035       if ( CUR.error != TT_Err_Ok )
   8036       {
   8037         switch ( CUR.error )
   8038         {
   8039         case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
   8040           {
   8041             TT_DefRecord*  def   = CUR.IDefs;
   8042             TT_DefRecord*  limit = def + CUR.numIDefs;
   8043 
   8044 
   8045             for ( ; def < limit; def++ )
   8046             {
   8047               if ( def->active && CUR.opcode == (FT_Byte)def->opc )
   8048               {
   8049                 TT_CallRec*  callrec;
   8050 
   8051 
   8052                 if ( CUR.callTop >= CUR.callSize )
   8053                 {
   8054                   CUR.error = TT_Err_Invalid_Reference;
   8055                   goto LErrorLabel_;
   8056                 }
   8057 
   8058                 callrec = &CUR.callStack[CUR.callTop];
   8059 
   8060                 callrec->Caller_Range = CUR.curRange;
   8061                 callrec->Caller_IP    = CUR.IP + 1;
   8062                 callrec->Cur_Count    = 1;
   8063                 callrec->Cur_Restart  = def->start;
   8064 
   8065                 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
   8066                   goto LErrorLabel_;
   8067 
   8068                 goto LSuiteLabel_;
   8069               }
   8070             }
   8071           }
   8072 
   8073           CUR.error = TT_Err_Invalid_Opcode;
   8074           goto LErrorLabel_;
   8075 
   8076 #if 0
   8077           break;   /* Unreachable code warning suppression.             */
   8078                    /* Leave to remind in case a later change the editor */
   8079                    /* to consider break;                                */
   8080 #endif
   8081 
   8082         default:
   8083           goto LErrorLabel_;
   8084 
   8085 #if 0
   8086         break;
   8087 #endif
   8088         }
   8089       }
   8090 
   8091       CUR.top = CUR.new_top;
   8092 
   8093       if ( CUR.step_ins )
   8094         CUR.IP += CUR.length;
   8095 
   8096       /* increment instruction counter and check if we didn't */
   8097       /* run this program for too long (e.g. infinite loops). */
   8098       if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
   8099         return TT_Err_Execution_Too_Long;
   8100 
   8101     LSuiteLabel_:
   8102       if ( CUR.IP >= CUR.codeSize )
   8103       {
   8104         if ( CUR.callTop > 0 )
   8105         {
   8106           CUR.error = TT_Err_Code_Overflow;
   8107           goto LErrorLabel_;
   8108         }
   8109         else
   8110           goto LNo_Error_;
   8111       }
   8112     } while ( !CUR.instruction_trap );
   8113 
   8114   LNo_Error_:
   8115 
   8116 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
   8117     *exc = cur;
   8118 #endif
   8119 
   8120     return TT_Err_Ok;
   8121 
   8122   LErrorCodeOverflow_:
   8123     CUR.error = TT_Err_Code_Overflow;
   8124 
   8125   LErrorLabel_:
   8126 
   8127 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
   8128     *exc = cur;
   8129 #endif
   8130 
   8131     return CUR.error;
   8132   }
   8133 
   8134 
   8135 #endif /* TT_USE_BYTECODE_INTERPRETER */
   8136 
   8137 
   8138 /* END */
   8139