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