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