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