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