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