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