tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ttinterp.c (184629B)


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