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