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