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