< prev index next >

src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c

Print this page


   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;


 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;


 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 ),


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,


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 );


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,


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;


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,


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 


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;


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... */


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 )


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 )


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      */


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 


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                           */


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           */


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 


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 );


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     {


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     }


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 */


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     }


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;


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 ) ||


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 


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;


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 ) )


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 )


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     }


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     {


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                          &&


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 


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 )


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 ) )


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];


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     /*


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 )


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.                                    */


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 );


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;


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       {


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;


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_;


   1 /****************************************************************************
   2  *
   3  * ttinterp.c
   4  *
   5  *   TrueType bytecode interpreter (body).
   6  *
   7  * Copyright (C) 1996-2019 by
   8  * David Turner, Robert Wilhelm, and Werner Lemberg.
   9  *
  10  * This file is part of the FreeType project, and may only be used,
  11  * modified, and distributed under the terms of the FreeType project
  12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
  13  * this file you indicate that you have read the license and
  14  * understand and accept it fully.
  15  *
  16  */
  17 
  18 
  19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
  20 /* issues; many thanks!                                                */
  21 
  22 
  23 #include <ft2build.h>
  24 #include FT_INTERNAL_DEBUG_H
  25 #include FT_INTERNAL_CALC_H
  26 #include FT_TRIGONOMETRY_H
  27 #include FT_SYSTEM_H
  28 #include FT_DRIVER_H
  29 #include FT_MULTIPLE_MASTERS_H
  30 
  31 #include "ttinterp.h"
  32 #include "tterrors.h"
  33 #include "ttsubpix.h"
  34 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
  35 #include "ttgxvar.h"
  36 #endif
  37 
  38 
  39 #ifdef TT_USE_BYTECODE_INTERPRETER
  40 
  41 
  42   /**************************************************************************
  43    *
  44    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  45    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  46    * messages during execution.
  47    */
  48 #undef  FT_COMPONENT
  49 #define FT_COMPONENT  ttinterp
  50 
  51 
  52 #define NO_SUBPIXEL_HINTING                                                  \
  53           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
  54             TT_INTERPRETER_VERSION_35 )
  55 
  56 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
  57 #define SUBPIXEL_HINTING_INFINALITY                                          \
  58           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
  59             TT_INTERPRETER_VERSION_38 )
  60 #endif
  61 
  62 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
  63 #define SUBPIXEL_HINTING_MINIMAL                                             \
  64           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
  65             TT_INTERPRETER_VERSION_40 )
  66 #endif
  67 
  68 #define PROJECT( v1, v2 )                                   \
  69           exc->func_project( exc,                           \
  70                              SUB_LONG( (v1)->x, (v2)->x ),  \
  71                              SUB_LONG( (v1)->y, (v2)->y ) )
  72 
  73 #define DUALPROJ( v1, v2 )                                   \
  74           exc->func_dualproj( exc,                           \
  75                               SUB_LONG( (v1)->x, (v2)->x ),  \
  76                               SUB_LONG( (v1)->y, (v2)->y ) )
  77 
  78 #define FAST_PROJECT( v )                          \
  79           exc->func_project( exc, (v)->x, (v)->y )
  80 
  81 #define FAST_DUALPROJ( v )                          \
  82           exc->func_dualproj( exc, (v)->x, (v)->y )
  83 
  84 
  85   /**************************************************************************
  86    *
  87    * Two simple bounds-checking macros.
  88    */
  89 #define BOUNDS( x, n )   ( (FT_UInt)(x)  >= (FT_UInt)(n)  )
  90 #define BOUNDSL( x, n )  ( (FT_ULong)(x) >= (FT_ULong)(n) )
  91 
  92 
  93 #undef  SUCCESS
  94 #define SUCCESS  0
  95 
  96 #undef  FAILURE
  97 #define FAILURE  1
  98 
  99 
 100   /**************************************************************************
 101    *
 102    *                       CODERANGE FUNCTIONS
 103    *
 104    */
 105 
 106 
 107   /**************************************************************************
 108    *
 109    * @Function:
 110    *   TT_Goto_CodeRange
 111    *
 112    * @Description:
 113    *   Switches to a new code range (updates the code related elements in
 114    *   `exec', and `IP').
 115    *
 116    * @Input:
 117    *   range ::
 118    *     The new execution code range.
 119    *
 120    *   IP ::
 121    *     The new IP in the new code range.
 122    *
 123    * @InOut:
 124    *   exec ::
 125    *     The target execution context.
 126    */
 127   FT_LOCAL_DEF( void )
 128   TT_Goto_CodeRange( TT_ExecContext  exec,
 129                      FT_Int          range,
 130                      FT_Long         IP )
 131   {
 132     TT_CodeRange*  coderange;
 133 
 134 
 135     FT_ASSERT( range >= 1 && range <= 3 );
 136 
 137     coderange = &exec->codeRangeTable[range - 1];
 138 
 139     FT_ASSERT( coderange->base );
 140 
 141     /* NOTE: Because the last instruction of a program may be a CALL */
 142     /*       which will return to the first byte *after* the code    */
 143     /*       range, we test for IP <= Size instead of IP < Size.     */
 144     /*                                                               */
 145     FT_ASSERT( IP <= coderange->size );
 146 
 147     exec->code     = coderange->base;
 148     exec->codeSize = coderange->size;
 149     exec->IP       = IP;
 150     exec->curRange = range;
 151   }
 152 
 153 
 154   /**************************************************************************
 155    *
 156    * @Function:
 157    *   TT_Set_CodeRange
 158    *
 159    * @Description:
 160    *   Sets a code range.
 161    *
 162    * @Input:
 163    *   range ::
 164    *     The code range index.
 165    *
 166    *   base ::
 167    *     The new code base.
 168    *
 169    *   length ::
 170    *     The range size in bytes.
 171    *
 172    * @InOut:
 173    *   exec ::
 174    *     The target execution context.
 175    */
 176   FT_LOCAL_DEF( void )
 177   TT_Set_CodeRange( TT_ExecContext  exec,
 178                     FT_Int          range,
 179                     void*           base,
 180                     FT_Long         length )
 181   {
 182     FT_ASSERT( range >= 1 && range <= 3 );
 183 
 184     exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
 185     exec->codeRangeTable[range - 1].size = length;
 186   }
 187 
 188 
 189   /**************************************************************************
 190    *
 191    * @Function:
 192    *   TT_Clear_CodeRange
 193    *
 194    * @Description:
 195    *   Clears a code range.
 196    *
 197    * @Input:
 198    *   range ::
 199    *     The code range index.
 200    *
 201    * @InOut:
 202    *   exec ::
 203    *     The target execution context.
 204    */
 205   FT_LOCAL_DEF( void )
 206   TT_Clear_CodeRange( TT_ExecContext  exec,
 207                       FT_Int          range )
 208   {
 209     FT_ASSERT( range >= 1 && range <= 3 );
 210 
 211     exec->codeRangeTable[range - 1].base = NULL;
 212     exec->codeRangeTable[range - 1].size = 0;
 213   }
 214 
 215 
 216   /**************************************************************************
 217    *
 218    *                  EXECUTION CONTEXT ROUTINES
 219    *
 220    */
 221 
 222 
 223   /**************************************************************************
 224    *
 225    * @Function:
 226    *   TT_Done_Context
 227    *
 228    * @Description:
 229    *   Destroys a given context.
 230    *
 231    * @Input:
 232    *   exec ::
 233    *     A handle to the target execution context.
 234    *
 235    *   memory ::
 236    *     A handle to the parent memory object.
 237    *
 238    * @Note:
 239    *   Only the glyph loader and debugger should call this function.
 240    */
 241   FT_LOCAL_DEF( void )
 242   TT_Done_Context( TT_ExecContext  exec )
 243   {
 244     FT_Memory  memory = exec->memory;
 245 
 246 
 247     /* points zone */
 248     exec->maxPoints   = 0;
 249     exec->maxContours = 0;
 250 
 251     /* free stack */
 252     FT_FREE( exec->stack );
 253     exec->stackSize = 0;
 254 
 255     /* free call stack */
 256     FT_FREE( exec->callStack );
 257     exec->callSize = 0;
 258     exec->callTop  = 0;
 259 
 260     /* free glyph code range */
 261     FT_FREE( exec->glyphIns );
 262     exec->glyphSize = 0;
 263 
 264     exec->size = NULL;
 265     exec->face = NULL;
 266 
 267     FT_FREE( exec );
 268   }
 269 
 270 
 271   /**************************************************************************
 272    *
 273    * @Function:
 274    *   Init_Context
 275    *
 276    * @Description:
 277    *   Initializes a context object.
 278    *
 279    * @Input:
 280    *   memory ::
 281    *     A handle to the parent memory object.
 282    *
 283    * @InOut:
 284    *   exec ::
 285    *     A handle to the target execution context.
 286    *
 287    * @Return:
 288    *   FreeType error code.  0 means success.
 289    */
 290   static FT_Error
 291   Init_Context( TT_ExecContext  exec,
 292                 FT_Memory       memory )
 293   {
 294     FT_Error  error;
 295 
 296 
 297     FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
 298 
 299     exec->memory   = memory;
 300     exec->callSize = 32;
 301 
 302     if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
 303       goto Fail_Memory;
 304 
 305     /* all values in the context are set to 0 already, but this is */
 306     /* here as a remainder                                         */
 307     exec->maxPoints   = 0;
 308     exec->maxContours = 0;
 309 
 310     exec->stackSize = 0;
 311     exec->glyphSize = 0;
 312 
 313     exec->stack    = NULL;
 314     exec->glyphIns = NULL;
 315 
 316     exec->face = NULL;
 317     exec->size = NULL;
 318 
 319     return FT_Err_Ok;
 320 
 321   Fail_Memory:
 322     FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
 323     TT_Done_Context( exec );
 324 
 325     return error;
 326  }
 327 
 328 
 329   /**************************************************************************
 330    *
 331    * @Function:
 332    *   Update_Max
 333    *
 334    * @Description:
 335    *   Checks the size of a buffer and reallocates it if necessary.
 336    *
 337    * @Input:
 338    *   memory ::
 339    *     A handle to the parent memory object.
 340    *
 341    *   multiplier ::
 342    *     The size in bytes of each element in the buffer.
 343    *
 344    *   new_max ::
 345    *     The new capacity (size) of the buffer.
 346    *
 347    * @InOut:
 348    *   size ::
 349    *     The address of the buffer's current size expressed
 350    *     in elements.
 351    *
 352    *   buff ::
 353    *     The address of the buffer base pointer.
 354    *
 355    * @Return:
 356    *   FreeType error code.  0 means success.
 357    */
 358   FT_LOCAL_DEF( FT_Error )
 359   Update_Max( FT_Memory  memory,
 360               FT_ULong*  size,
 361               FT_ULong   multiplier,
 362               void*      _pbuff,
 363               FT_ULong   new_max )
 364   {
 365     FT_Error  error;
 366     void**    pbuff = (void**)_pbuff;
 367 
 368 
 369     if ( *size < new_max )
 370     {
 371       if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
 372         return error;
 373       *size = new_max;
 374     }
 375 
 376     return FT_Err_Ok;
 377   }
 378 
 379 
 380   /**************************************************************************
 381    *
 382    * @Function:
 383    *   TT_Load_Context
 384    *
 385    * @Description:
 386    *   Prepare an execution context for glyph hinting.
 387    *
 388    * @Input:
 389    *   face ::
 390    *     A handle to the source face object.
 391    *
 392    *   size ::
 393    *     A handle to the source size object.
 394    *
 395    * @InOut:
 396    *   exec ::
 397    *     A handle to the target execution context.
 398    *
 399    * @Return:
 400    *   FreeType error code.  0 means success.
 401    *
 402    * @Note:
 403    *   Only the glyph loader and debugger should call this function.
 404    */
 405   FT_LOCAL_DEF( FT_Error )
 406   TT_Load_Context( TT_ExecContext  exec,
 407                    TT_Face         face,
 408                    TT_Size         size )
 409   {
 410     FT_Int          i;
 411     FT_ULong        tmp;
 412     TT_MaxProfile*  maxp;
 413     FT_Error        error;
 414 
 415 
 416     exec->face = face;
 417     maxp       = &face->max_profile;
 418     exec->size = size;
 419 
 420     if ( size )
 421     {
 422       exec->numFDefs   = size->num_function_defs;
 423       exec->maxFDefs   = size->max_function_defs;
 424       exec->numIDefs   = size->num_instruction_defs;


 471                         sizeof ( FT_Byte ),
 472                         (void*)&exec->glyphIns,
 473                         maxp->maxSizeOfInstructions );
 474     exec->glyphSize = (FT_UShort)tmp;
 475     if ( error )
 476       return error;
 477 
 478     exec->pts.n_points   = 0;
 479     exec->pts.n_contours = 0;
 480 
 481     exec->zp1 = exec->pts;
 482     exec->zp2 = exec->pts;
 483     exec->zp0 = exec->pts;
 484 
 485     exec->instruction_trap = FALSE;
 486 
 487     return FT_Err_Ok;
 488   }
 489 
 490 
 491   /**************************************************************************
 492    *
 493    * @Function:
 494    *   TT_Save_Context
 495    *
 496    * @Description:
 497    *   Saves the code ranges in a `size' object.
 498    *
 499    * @Input:
 500    *   exec ::
 501    *     A handle to the source execution context.
 502    *
 503    * @InOut:
 504    *   size ::
 505    *     A handle to the target size object.
 506    *
 507    * @Note:
 508    *   Only the glyph loader and debugger should call this function.
 509    */
 510   FT_LOCAL_DEF( void )
 511   TT_Save_Context( TT_ExecContext  exec,
 512                    TT_Size         size )
 513   {
 514     FT_Int  i;
 515 
 516 
 517     /* XXX: Will probably disappear soon with all the code range */
 518     /*      management, which is now rather obsolete.            */
 519     /*                                                           */
 520     size->num_function_defs    = exec->numFDefs;
 521     size->num_instruction_defs = exec->numIDefs;
 522 
 523     size->max_func = exec->maxFunc;
 524     size->max_ins  = exec->maxIns;
 525 
 526     for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
 527       size->codeRangeTable[i] = exec->codeRangeTable[i];
 528   }
 529 
 530 
 531   /**************************************************************************
 532    *
 533    * @Function:
 534    *   TT_Run_Context
 535    *
 536    * @Description:
 537    *   Executes one or more instructions in the execution context.
 538    *
 539    * @Input:
 540    *   exec ::
 541    *     A handle to the target execution context.
 542    *
 543    * @Return:
 544    *   TrueType error code.  0 means success.
 545    */






 546   FT_LOCAL_DEF( FT_Error )
 547   TT_Run_Context( TT_ExecContext  exec )
 548   {
 549     TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
 550 
 551     exec->zp0 = exec->pts;
 552     exec->zp1 = exec->pts;
 553     exec->zp2 = exec->pts;
 554 
 555     exec->GS.gep0 = 1;
 556     exec->GS.gep1 = 1;
 557     exec->GS.gep2 = 1;
 558 
 559     exec->GS.projVector.x = 0x4000;
 560     exec->GS.projVector.y = 0x0000;
 561 
 562     exec->GS.freeVector = exec->GS.projVector;
 563     exec->GS.dualVector = exec->GS.projVector;
 564 
 565     exec->GS.round_state = 1;


 609       goto Fail;
 610 
 611     memory = driver->root.root.memory;
 612 
 613     /* allocate object */
 614     if ( FT_NEW( exec ) )
 615       goto Fail;
 616 
 617     /* initialize it; in case of error this deallocates `exec' too */
 618     error = Init_Context( exec, memory );
 619     if ( error )
 620       goto Fail;
 621 
 622     return exec;
 623 
 624   Fail:
 625     return NULL;
 626   }
 627 
 628 
 629   /**************************************************************************
 630    *
 631    * Before an opcode is executed, the interpreter verifies that there are
 632    * enough arguments on the stack, with the help of the `Pop_Push_Count'
 633    * table.
 634    *
 635    * For each opcode, the first column gives the number of arguments that
 636    * are popped from the stack; the second one gives the number of those
 637    * that are pushed in result.
 638    *
 639    * Opcodes which have a varying number of parameters in the data stream
 640    * (NPUSHB, NPUSHW) are handled specially; they have a negative value in
 641    * the `opcode_length' table, and the value in `Pop_Push_Count' is set
 642    * to zero.
 643    *
 644    */
 645 
 646 
 647 #undef  PACK
 648 #define PACK( x, y )  ( ( x << 4 ) | y )
 649 
 650 
 651   static
 652   const FT_Byte  Pop_Push_Count[256] =
 653   {
 654     /* opcodes are gathered in groups of 16 */
 655     /* please keep the spaces as they are   */
 656 
 657     /*  SVTCA  y  */  PACK( 0, 0 ),
 658     /*  SVTCA  x  */  PACK( 0, 0 ),
 659     /*  SPvTCA y  */  PACK( 0, 0 ),
 660     /*  SPvTCA x  */  PACK( 0, 0 ),
 661     /*  SFvTCA y  */  PACK( 0, 0 ),
 662     /*  SFvTCA x  */  PACK( 0, 0 ),
 663     /*  SPvTL //  */  PACK( 2, 0 ),
 664     /*  SPvTL +   */  PACK( 2, 0 ),


1129     "7 INS_$AE",
1130     "7 INS_$AF",
1131 
1132     "8 PushB[0]",
1133     "8 PushB[1]",
1134     "8 PushB[2]",
1135     "8 PushB[3]",
1136     "8 PushB[4]",
1137     "8 PushB[5]",
1138     "8 PushB[6]",
1139     "8 PushB[7]",
1140     "8 PushW[0]",
1141     "8 PushW[1]",
1142     "8 PushW[2]",
1143     "8 PushW[3]",
1144     "8 PushW[4]",
1145     "8 PushW[5]",
1146     "8 PushW[6]",
1147     "8 PushW[7]",
1148 
1149     "7 MDRP[G]",
1150     "7 MDRP[B]",
1151     "7 MDRP[W]",
1152     "7 MDRP[?]",
1153     "8 MDRP[rG]",
1154     "8 MDRP[rB]",
1155     "8 MDRP[rW]",
1156     "8 MDRP[r?]",
1157     "8 MDRP[mG]",
1158     "8 MDRP[mB]",
1159     "8 MDRP[mW]",
1160     "8 MDRP[m?]",
1161     "9 MDRP[mrG]",
1162     "9 MDRP[mrB]",
1163     "9 MDRP[mrW]",
1164     "9 MDRP[mr?]",
1165 
1166     "8 MDRP[pG]",
1167     "8 MDRP[pB]",
1168     "8 MDRP[pW]",
1169     "8 MDRP[p?]",
1170     "9 MDRP[prG]",
1171     "9 MDRP[prB]",
1172     "9 MDRP[prW]",
1173     "9 MDRP[pr?]",
1174     "9 MDRP[pmG]",
1175     "9 MDRP[pmB]",
1176     "9 MDRP[pmW]",
1177     "9 MDRP[pm?]",
1178     "A MDRP[pmrG]",
1179     "A MDRP[pmrB]",
1180     "A MDRP[pmrW]",
1181     "A MDRP[pmr?]",
1182 
1183     "7 MIRP[G]",
1184     "7 MIRP[B]",
1185     "7 MIRP[W]",
1186     "7 MIRP[?]",
1187     "8 MIRP[rG]",
1188     "8 MIRP[rB]",
1189     "8 MIRP[rW]",
1190     "8 MIRP[r?]",
1191     "8 MIRP[mG]",
1192     "8 MIRP[mB]",
1193     "8 MIRP[mW]",
1194     "8 MIRP[m?]",
1195     "9 MIRP[mrG]",
1196     "9 MIRP[mrB]",
1197     "9 MIRP[mrW]",
1198     "9 MIRP[mr?]",
1199 
1200     "8 MIRP[pG]",
1201     "8 MIRP[pB]",
1202     "8 MIRP[pW]",
1203     "8 MIRP[p?]",
1204     "9 MIRP[prG]",
1205     "9 MIRP[prB]",
1206     "9 MIRP[prW]",
1207     "9 MIRP[pr?]",
1208     "9 MIRP[pmG]",
1209     "9 MIRP[pmB]",
1210     "9 MIRP[pmW]",
1211     "9 MIRP[pm?]",
1212     "A MIRP[pmrG]",
1213     "A MIRP[pmrB]",
1214     "A MIRP[pmrW]",
1215     "A MIRP[pmr?]"
1216   };
1217 
1218 #endif /* FT_DEBUG_LEVEL_TRACE */
1219 
1220 
1221   static
1222   const FT_Char  opcode_length[256] =
1223   {
1224     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1225     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1226     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1227     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1228 
1229    -1,-2, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1230     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1231     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1232     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1233 
1234     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1235     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,


1448 
1449     /* add them */
1450     lo = lo1 + lo2;
1451     hi = hi1 + hi2 + ( lo < lo1 );
1452 
1453     /* divide the result by 2^14 with rounding */
1454     s   = hi >> 31;
1455     l   = lo + (FT_UInt32)s;
1456     hi += s + ( l < lo );
1457     lo  = l;
1458 
1459     l   = lo + 0x2000U;
1460     hi += ( l < lo );
1461 
1462     return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
1463   }
1464 
1465 #endif /* TT_DotFix14 */
1466 
1467 
1468   /**************************************************************************
1469    *
1470    * @Function:
1471    *   Current_Ratio
1472    *
1473    * @Description:
1474    *   Returns the current aspect ratio scaling factor depending on the
1475    *   projection vector's state and device resolutions.
1476    *
1477    * @Return:
1478    *   The aspect ratio in 16.16 format, always <= 1.0 .
1479    */
1480   static FT_Long
1481   Current_Ratio( TT_ExecContext  exc )
1482   {
1483     if ( !exc->tt_metrics.ratio )
1484     {
1485       if ( exc->GS.projVector.y == 0 )
1486         exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;
1487 
1488       else if ( exc->GS.projVector.x == 0 )
1489         exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;
1490 
1491       else
1492       {
1493         FT_F26Dot6  x, y;
1494 
1495 
1496         x = TT_MulFix14( exc->tt_metrics.x_ratio,
1497                          exc->GS.projVector.x );
1498         y = TT_MulFix14( exc->tt_metrics.y_ratio,
1499                          exc->GS.projVector.y );


1501       }
1502     }
1503     return exc->tt_metrics.ratio;
1504   }
1505 
1506 
1507   FT_CALLBACK_DEF( FT_Long )
1508   Current_Ppem( TT_ExecContext  exc )
1509   {
1510     return exc->tt_metrics.ppem;
1511   }
1512 
1513 
1514   FT_CALLBACK_DEF( FT_Long )
1515   Current_Ppem_Stretched( TT_ExecContext  exc )
1516   {
1517     return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );
1518   }
1519 
1520 
1521   /**************************************************************************
1522    *
1523    * Functions related to the control value table (CVT).
1524    *
1525    */
1526 
1527 
1528   FT_CALLBACK_DEF( FT_F26Dot6 )
1529   Read_CVT( TT_ExecContext  exc,
1530             FT_ULong        idx )
1531   {
1532     return exc->cvt[idx];
1533   }
1534 
1535 
1536   FT_CALLBACK_DEF( FT_F26Dot6 )
1537   Read_CVT_Stretched( TT_ExecContext  exc,
1538                       FT_ULong        idx )
1539   {
1540     return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
1541   }
1542 
1543 
1544   FT_CALLBACK_DEF( void )
1545   Write_CVT( TT_ExecContext  exc,


1547              FT_F26Dot6      value )
1548   {
1549     exc->cvt[idx] = value;
1550   }
1551 
1552 
1553   FT_CALLBACK_DEF( void )
1554   Write_CVT_Stretched( TT_ExecContext  exc,
1555                        FT_ULong        idx,
1556                        FT_F26Dot6      value )
1557   {
1558     exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
1559   }
1560 
1561 
1562   FT_CALLBACK_DEF( void )
1563   Move_CVT( TT_ExecContext  exc,
1564             FT_ULong        idx,
1565             FT_F26Dot6      value )
1566   {
1567     exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value );
1568   }
1569 
1570 
1571   FT_CALLBACK_DEF( void )
1572   Move_CVT_Stretched( TT_ExecContext  exc,
1573                       FT_ULong        idx,
1574                       FT_F26Dot6      value )
1575   {
1576     exc->cvt[idx] = ADD_LONG( exc->cvt[idx],
1577                               FT_DivFix( value, Current_Ratio( exc ) ) );
1578   }
1579 
1580 
1581   /**************************************************************************
1582    *
1583    * @Function:
1584    *   GetShortIns
1585    *
1586    * @Description:
1587    *   Returns a short integer taken from the instruction stream at
1588    *   address IP.
1589    *
1590    * @Return:
1591    *   Short read at code[IP].
1592    *
1593    * @Note:
1594    *   This one could become a macro.
1595    */
1596   static FT_Short
1597   GetShortIns( TT_ExecContext  exc )
1598   {
1599     /* Reading a byte stream so there is no endianness (DaveP) */
1600     exc->IP += 2;
1601     return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
1602                          exc->code[exc->IP - 1]      );
1603   }
1604 
1605 
1606   /**************************************************************************
1607    *
1608    * @Function:
1609    *   Ins_Goto_CodeRange
1610    *
1611    * @Description:
1612    *   Goes to a certain code range in the instruction stream.
1613    *
1614    * @Input:
1615    *   aRange ::
1616    *     The index of the code range.
1617    *
1618    *   aIP ::
1619    *     The new IP address in the code range.
1620    *
1621    * @Return:
1622    *   SUCCESS or FAILURE.
1623    */
1624   static FT_Bool
1625   Ins_Goto_CodeRange( TT_ExecContext  exc,
1626                       FT_Int          aRange,
1627                       FT_Long         aIP )
1628   {
1629     TT_CodeRange*  range;
1630 
1631 
1632     if ( aRange < 1 || aRange > 3 )
1633     {
1634       exc->error = FT_THROW( Bad_Argument );
1635       return FAILURE;
1636     }
1637 
1638     range = &exc->codeRangeTable[aRange - 1];
1639 
1640     if ( !range->base )     /* invalid coderange */
1641     {
1642       exc->error = FT_THROW( Invalid_CodeRange );
1643       return FAILURE;


1645 
1646     /* NOTE: Because the last instruction of a program may be a CALL */
1647     /*       which will return to the first byte *after* the code    */
1648     /*       range, we test for aIP <= Size, instead of aIP < Size.  */
1649 
1650     if ( aIP > range->size )
1651     {
1652       exc->error = FT_THROW( Code_Overflow );
1653       return FAILURE;
1654     }
1655 
1656     exc->code     = range->base;
1657     exc->codeSize = range->size;
1658     exc->IP       = aIP;
1659     exc->curRange = aRange;
1660 
1661     return SUCCESS;
1662   }
1663 
1664 
1665   /**************************************************************************
1666    *
1667    * @Function:
1668    *   Direct_Move
1669    *
1670    * @Description:
1671    *   Moves a point by a given distance along the freedom vector.  The
1672    *   point will be `touched'.
1673    *
1674    * @Input:
1675    *   point ::
1676    *     The index of the point to move.
1677    *
1678    *   distance ::
1679    *     The distance to apply.
1680    *
1681    * @InOut:
1682    *   zone ::
1683    *     The affected glyph zone.
1684    *
1685    * @Note:
1686    *   See `ttinterp.h' for details on backward compatibility mode.
1687    *   `Touches' the point.
1688    */
1689   static void
1690   Direct_Move( TT_ExecContext  exc,
1691                TT_GlyphZone    zone,
1692                FT_UShort       point,
1693                FT_F26Dot6      distance )
1694   {
1695     FT_F26Dot6  v;
1696 
1697 
1698     v = exc->GS.freeVector.x;
1699 
1700     if ( v != 0 )
1701     {
1702 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1703       if ( SUBPIXEL_HINTING_INFINALITY                            &&
1704            ( !exc->ignore_x_mode                                ||
1705              ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
1706         zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1707                                        FT_MulDiv( distance,
1708                                                   v,


1734     v = exc->GS.freeVector.y;
1735 
1736     if ( v != 0 )
1737     {
1738 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1739       if ( !( SUBPIXEL_HINTING_MINIMAL    &&
1740               exc->backward_compatibility &&
1741               exc->iupx_called            &&
1742               exc->iupy_called            ) )
1743 #endif
1744         zone->cur[point].y = ADD_LONG( zone->cur[point].y,
1745                                        FT_MulDiv( distance,
1746                                                   v,
1747                                                   exc->F_dot_P ) );
1748 
1749       zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1750     }
1751   }
1752 
1753 
1754   /**************************************************************************
1755    *
1756    * @Function:
1757    *   Direct_Move_Orig
1758    *
1759    * @Description:
1760    *   Moves the *original* position of a point by a given distance along
1761    *   the freedom vector.  Obviously, the point will not be `touched'.
1762    *
1763    * @Input:
1764    *   point ::
1765    *     The index of the point to move.
1766    *
1767    *   distance ::
1768    *     The distance to apply.
1769    *
1770    * @InOut:
1771    *   zone ::
1772    *     The affected glyph zone.
1773    */
1774   static void
1775   Direct_Move_Orig( TT_ExecContext  exc,
1776                     TT_GlyphZone    zone,
1777                     FT_UShort       point,
1778                     FT_F26Dot6      distance )
1779   {
1780     FT_F26Dot6  v;
1781 
1782 
1783     v = exc->GS.freeVector.x;
1784 
1785     if ( v != 0 )
1786       zone->org[point].x = ADD_LONG( zone->org[point].x,
1787                                      FT_MulDiv( distance,
1788                                                 v,
1789                                                 exc->F_dot_P ) );
1790 
1791     v = exc->GS.freeVector.y;
1792 
1793     if ( v != 0 )
1794       zone->org[point].y = ADD_LONG( zone->org[point].y,
1795                                      FT_MulDiv( distance,
1796                                                 v,
1797                                                 exc->F_dot_P ) );
1798   }
1799 
1800 
1801   /**************************************************************************
1802    *
1803    * Special versions of Direct_Move()
1804    *
1805    *   The following versions are used whenever both vectors are both
1806    *   along one of the coordinate unit vectors, i.e. in 90% of the cases.
1807    *   See `ttinterp.h' for details on backward compatibility mode.
1808    *
1809    */
1810 
1811 
1812   static void
1813   Direct_Move_X( TT_ExecContext  exc,
1814                  TT_GlyphZone    zone,
1815                  FT_UShort       point,
1816                  FT_F26Dot6      distance )
1817   {
1818 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1819     if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
1820       zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1821     else
1822 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1823 
1824 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1825     if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
1826       zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1827     else
1828 #endif
1829 


1836 
1837   static void
1838   Direct_Move_Y( TT_ExecContext  exc,
1839                  TT_GlyphZone    zone,
1840                  FT_UShort       point,
1841                  FT_F26Dot6      distance )
1842   {
1843     FT_UNUSED( exc );
1844 
1845 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1846     if ( !( SUBPIXEL_HINTING_MINIMAL             &&
1847             exc->backward_compatibility          &&
1848             exc->iupx_called && exc->iupy_called ) )
1849 #endif
1850       zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );
1851 
1852     zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1853   }
1854 
1855 
1856   /**************************************************************************
1857    *
1858    * Special versions of Direct_Move_Orig()
1859    *
1860    *   The following versions are used whenever both vectors are both
1861    *   along one of the coordinate unit vectors, i.e. in 90% of the cases.
1862    *
1863    */
1864 
1865 
1866   static void
1867   Direct_Move_Orig_X( TT_ExecContext  exc,
1868                       TT_GlyphZone    zone,
1869                       FT_UShort       point,
1870                       FT_F26Dot6      distance )
1871   {
1872     FT_UNUSED( exc );
1873 
1874     zone->org[point].x = ADD_LONG( zone->org[point].x, distance );
1875   }
1876 
1877 
1878   static void
1879   Direct_Move_Orig_Y( TT_ExecContext  exc,
1880                       TT_GlyphZone    zone,
1881                       FT_UShort       point,
1882                       FT_F26Dot6      distance )
1883   {
1884     FT_UNUSED( exc );
1885 
1886     zone->org[point].y = ADD_LONG( zone->org[point].y, distance );
1887   }
1888 
1889 
1890   /**************************************************************************
1891    *
1892    * @Function:
1893    *   Round_None
1894    *
1895    * @Description:
1896    *   Does not round, but adds engine compensation.
1897    *
1898    * @Input:
1899    *   distance ::
1900    *     The distance (not) to round.
1901    *
1902    *   compensation ::
1903    *     The engine compensation.
1904    *
1905    * @Return:
1906    *   The compensated distance.
1907    *
1908    * @Note:
1909    *   The TrueType specification says very few about the relationship
1910    *   between rounding and engine compensation.  However, it seems from
1911    *   the description of super round that we should add the compensation
1912    *   before rounding.
1913    */
1914   static FT_F26Dot6
1915   Round_None( TT_ExecContext  exc,
1916               FT_F26Dot6      distance,
1917               FT_F26Dot6      compensation )
1918   {
1919     FT_F26Dot6  val;
1920 
1921     FT_UNUSED( exc );
1922 
1923 
1924     if ( distance >= 0 )
1925     {
1926       val = ADD_LONG( distance, compensation );
1927       if ( val < 0 )
1928         val = 0;
1929     }
1930     else
1931     {
1932       val = SUB_LONG( distance, compensation );
1933       if ( val > 0 )
1934         val = 0;
1935     }
1936     return val;
1937   }
1938 
1939 
1940   /**************************************************************************
1941    *
1942    * @Function:
1943    *   Round_To_Grid
1944    *
1945    * @Description:
1946    *   Rounds value to grid after adding engine compensation.
1947    *
1948    * @Input:
1949    *   distance ::
1950    *     The distance to round.
1951    *
1952    *   compensation ::
1953    *     The engine compensation.
1954    *
1955    * @Return:
1956    *   Rounded distance.
1957    */
1958   static FT_F26Dot6
1959   Round_To_Grid( TT_ExecContext  exc,
1960                  FT_F26Dot6      distance,
1961                  FT_F26Dot6      compensation )
1962   {
1963     FT_F26Dot6  val;
1964 
1965     FT_UNUSED( exc );
1966 
1967 
1968     if ( distance >= 0 )
1969     {
1970       val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );
1971       if ( val < 0 )
1972         val = 0;
1973     }
1974     else
1975     {
1976       val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,
1977                                                    distance ) ) );
1978       if ( val > 0 )
1979         val = 0;
1980     }
1981 
1982     return val;
1983   }
1984 
1985 
1986   /**************************************************************************
1987    *
1988    * @Function:
1989    *   Round_To_Half_Grid
1990    *
1991    * @Description:
1992    *   Rounds value to half grid after adding engine compensation.
1993    *
1994    * @Input:
1995    *   distance ::
1996    *     The distance to round.
1997    *
1998    *   compensation ::
1999    *     The engine compensation.
2000    *
2001    * @Return:
2002    *   Rounded distance.
2003    */
2004   static FT_F26Dot6
2005   Round_To_Half_Grid( TT_ExecContext  exc,
2006                       FT_F26Dot6      distance,
2007                       FT_F26Dot6      compensation )
2008   {
2009     FT_F26Dot6  val;
2010 
2011     FT_UNUSED( exc );
2012 
2013 
2014     if ( distance >= 0 )
2015     {
2016       val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),
2017                       32 );
2018       if ( val < 0 )
2019         val = 32;
2020     }
2021     else
2022     {
2023       val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,
2024                                                         distance ) ),
2025                                 32 ) );
2026       if ( val > 0 )
2027         val = -32;
2028     }
2029 
2030     return val;
2031   }
2032 
2033 
2034   /**************************************************************************
2035    *
2036    * @Function:
2037    *   Round_Down_To_Grid
2038    *
2039    * @Description:
2040    *   Rounds value down to grid after adding engine compensation.
2041    *
2042    * @Input:
2043    *   distance ::
2044    *     The distance to round.
2045    *
2046    *   compensation ::
2047    *     The engine compensation.
2048    *
2049    * @Return:
2050    *   Rounded distance.
2051    */
2052   static FT_F26Dot6
2053   Round_Down_To_Grid( TT_ExecContext  exc,
2054                       FT_F26Dot6      distance,
2055                       FT_F26Dot6      compensation )
2056   {
2057     FT_F26Dot6  val;
2058 
2059     FT_UNUSED( exc );
2060 
2061 
2062     if ( distance >= 0 )
2063     {
2064       val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );
2065       if ( val < 0 )
2066         val = 0;
2067     }
2068     else
2069     {
2070       val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );
2071       if ( val > 0 )
2072         val = 0;
2073     }
2074 
2075     return val;
2076   }
2077 
2078 
2079   /**************************************************************************
2080    *
2081    * @Function:
2082    *   Round_Up_To_Grid
2083    *
2084    * @Description:
2085    *   Rounds value up to grid after adding engine compensation.
2086    *
2087    * @Input:
2088    *   distance ::
2089    *     The distance to round.
2090    *
2091    *   compensation ::
2092    *     The engine compensation.
2093    *
2094    * @Return:
2095    *   Rounded distance.
2096    */
2097   static FT_F26Dot6
2098   Round_Up_To_Grid( TT_ExecContext  exc,
2099                     FT_F26Dot6      distance,
2100                     FT_F26Dot6      compensation )
2101   {
2102     FT_F26Dot6  val;
2103 
2104     FT_UNUSED( exc );
2105 
2106 
2107     if ( distance >= 0 )
2108     {
2109       val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );
2110       if ( val < 0 )
2111         val = 0;
2112     }
2113     else
2114     {
2115       val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,
2116                                                   distance ) ) );
2117       if ( val > 0 )
2118         val = 0;
2119     }
2120 
2121     return val;
2122   }
2123 
2124 
2125   /**************************************************************************
2126    *
2127    * @Function:
2128    *   Round_To_Double_Grid
2129    *
2130    * @Description:
2131    *   Rounds value to double grid after adding engine compensation.
2132    *
2133    * @Input:
2134    *   distance ::
2135    *     The distance to round.
2136    *
2137    *   compensation ::
2138    *     The engine compensation.
2139    *
2140    * @Return:
2141    *   Rounded distance.
2142    */
2143   static FT_F26Dot6
2144   Round_To_Double_Grid( TT_ExecContext  exc,
2145                         FT_F26Dot6      distance,
2146                         FT_F26Dot6      compensation )
2147   {
2148     FT_F26Dot6  val;
2149 
2150     FT_UNUSED( exc );
2151 
2152 
2153     if ( distance >= 0 )
2154     {
2155       val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );
2156       if ( val < 0 )
2157         val = 0;
2158     }
2159     else
2160     {
2161       val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),
2162                                          32 ) );
2163       if ( val > 0 )
2164         val = 0;
2165     }
2166 
2167     return val;
2168   }
2169 
2170 
2171   /**************************************************************************
2172    *
2173    * @Function:
2174    *   Round_Super
2175    *
2176    * @Description:
2177    *   Super-rounds value to grid after adding engine compensation.
2178    *
2179    * @Input:
2180    *   distance ::
2181    *     The distance to round.
2182    *
2183    *   compensation ::
2184    *     The engine compensation.
2185    *
2186    * @Return:
2187    *   Rounded distance.
2188    *
2189    * @Note:
2190    *   The TrueType specification says very little about the relationship
2191    *   between rounding and engine compensation.  However, it seems from
2192    *   the description of super round that we should add the compensation
2193    *   before rounding.
2194    */
2195   static FT_F26Dot6
2196   Round_Super( TT_ExecContext  exc,
2197                FT_F26Dot6      distance,
2198                FT_F26Dot6      compensation )
2199   {
2200     FT_F26Dot6  val;
2201 
2202 
2203     if ( distance >= 0 )
2204     {
2205       val = ADD_LONG( distance,
2206                       exc->threshold - exc->phase + compensation ) &
2207               -exc->period;
2208       val = ADD_LONG( val, exc->phase );
2209       if ( val < 0 )
2210         val = exc->phase;
2211     }
2212     else
2213     {
2214       val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,
2215                                 distance ) &
2216                         -exc->period );
2217       val = SUB_LONG( val, exc->phase );
2218       if ( val > 0 )
2219         val = -exc->phase;
2220     }
2221 
2222     return val;
2223   }
2224 
2225 
2226   /**************************************************************************
2227    *
2228    * @Function:
2229    *   Round_Super_45
2230    *
2231    * @Description:
2232    *   Super-rounds value to grid after adding engine compensation.
2233    *
2234    * @Input:
2235    *   distance ::
2236    *     The distance to round.
2237    *
2238    *   compensation ::
2239    *     The engine compensation.
2240    *
2241    * @Return:
2242    *   Rounded distance.
2243    *
2244    * @Note:
2245    *   There is a separate function for Round_Super_45() as we may need
2246    *   greater precision.
2247    */
2248   static FT_F26Dot6
2249   Round_Super_45( TT_ExecContext  exc,
2250                   FT_F26Dot6      distance,
2251                   FT_F26Dot6      compensation )
2252   {
2253     FT_F26Dot6  val;
2254 
2255 
2256     if ( distance >= 0 )
2257     {
2258       val = ( ADD_LONG( distance,
2259                         exc->threshold - exc->phase + compensation ) /
2260                 exc->period ) * exc->period;
2261       val = ADD_LONG( val, exc->phase );
2262       if ( val < 0 )
2263         val = exc->phase;
2264     }
2265     else
2266     {
2267       val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,
2268                                   distance ) /
2269                           exc->period ) * exc->period );
2270       val = SUB_LONG( val, exc->phase );
2271       if ( val > 0 )
2272         val = -exc->phase;
2273     }
2274 
2275     return val;
2276   }
2277 
2278 
2279   /**************************************************************************
2280    *
2281    * @Function:
2282    *   Compute_Round
2283    *
2284    * @Description:
2285    *   Sets the rounding mode.
2286    *
2287    * @Input:
2288    *   round_mode ::
2289    *     The rounding mode to be used.
2290    */
2291   static void
2292   Compute_Round( TT_ExecContext  exc,
2293                  FT_Byte         round_mode )
2294   {
2295     switch ( round_mode )
2296     {
2297     case TT_Round_Off:
2298       exc->func_round = (TT_Round_Func)Round_None;
2299       break;
2300 
2301     case TT_Round_To_Grid:
2302       exc->func_round = (TT_Round_Func)Round_To_Grid;
2303       break;
2304 
2305     case TT_Round_Up_To_Grid:
2306       exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
2307       break;
2308 
2309     case TT_Round_Down_To_Grid:
2310       exc->func_round = (TT_Round_Func)Round_Down_To_Grid;


2312 
2313     case TT_Round_To_Half_Grid:
2314       exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
2315       break;
2316 
2317     case TT_Round_To_Double_Grid:
2318       exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
2319       break;
2320 
2321     case TT_Round_Super:
2322       exc->func_round = (TT_Round_Func)Round_Super;
2323       break;
2324 
2325     case TT_Round_Super_45:
2326       exc->func_round = (TT_Round_Func)Round_Super_45;
2327       break;
2328     }
2329   }
2330 
2331 
2332   /**************************************************************************
2333    *
2334    * @Function:
2335    *   SetSuperRound
2336    *
2337    * @Description:
2338    *   Sets Super Round parameters.
2339    *
2340    * @Input:
2341    *   GridPeriod ::
2342    *     The grid period.
2343    *
2344    *   selector ::
2345    *     The SROUND opcode.
2346    */
2347   static void
2348   SetSuperRound( TT_ExecContext  exc,
2349                  FT_F2Dot14      GridPeriod,
2350                  FT_Long         selector )
2351   {
2352     switch ( (FT_Int)( selector & 0xC0 ) )
2353     {
2354       case 0:
2355         exc->period = GridPeriod / 2;
2356         break;
2357 
2358       case 0x40:
2359         exc->period = GridPeriod;
2360         break;
2361 
2362       case 0x80:
2363         exc->period = GridPeriod * 2;
2364         break;
2365 
2366       /* This opcode is reserved, but... */


2383       exc->phase = exc->period / 2;
2384       break;
2385 
2386     case 0x30:
2387       exc->phase = exc->period * 3 / 4;
2388       break;
2389     }
2390 
2391     if ( ( selector & 0x0F ) == 0 )
2392       exc->threshold = exc->period - 1;
2393     else
2394       exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;
2395 
2396     /* convert to F26Dot6 format */
2397     exc->period    >>= 8;
2398     exc->phase     >>= 8;
2399     exc->threshold >>= 8;
2400   }
2401 
2402 
2403   /**************************************************************************
2404    *
2405    * @Function:
2406    *   Project
2407    *
2408    * @Description:
2409    *   Computes the projection of vector given by (v2-v1) along the
2410    *   current projection vector.
2411    *
2412    * @Input:
2413    *   v1 ::
2414    *     First input vector.
2415    *   v2 ::
2416    *     Second input vector.
2417    *
2418    * @Return:
2419    *   The distance in F26dot6 format.
2420    */
2421   static FT_F26Dot6
2422   Project( TT_ExecContext  exc,
2423            FT_Pos          dx,
2424            FT_Pos          dy )
2425   {
2426     return TT_DotFix14( dx, dy,
2427                         exc->GS.projVector.x,
2428                         exc->GS.projVector.y );
2429   }
2430 
2431 
2432   /**************************************************************************
2433    *
2434    * @Function:
2435    *   Dual_Project
2436    *
2437    * @Description:
2438    *   Computes the projection of the vector given by (v2-v1) along the
2439    *   current dual vector.
2440    *
2441    * @Input:
2442    *   v1 ::
2443    *     First input vector.
2444    *   v2 ::
2445    *     Second input vector.
2446    *
2447    * @Return:
2448    *   The distance in F26dot6 format.
2449    */
2450   static FT_F26Dot6
2451   Dual_Project( TT_ExecContext  exc,
2452                 FT_Pos          dx,
2453                 FT_Pos          dy )
2454   {
2455     return TT_DotFix14( dx, dy,
2456                         exc->GS.dualVector.x,
2457                         exc->GS.dualVector.y );
2458   }
2459 
2460 
2461   /**************************************************************************
2462    *
2463    * @Function:
2464    *   Project_x
2465    *
2466    * @Description:
2467    *   Computes the projection of the vector given by (v2-v1) along the
2468    *   horizontal axis.
2469    *
2470    * @Input:
2471    *   v1 ::
2472    *     First input vector.
2473    *   v2 ::
2474    *     Second input vector.
2475    *
2476    * @Return:
2477    *   The distance in F26dot6 format.
2478    */
2479   static FT_F26Dot6
2480   Project_x( TT_ExecContext  exc,
2481              FT_Pos          dx,
2482              FT_Pos          dy )
2483   {
2484     FT_UNUSED( exc );
2485     FT_UNUSED( dy );
2486 
2487     return dx;
2488   }
2489 
2490 
2491   /**************************************************************************
2492    *
2493    * @Function:
2494    *   Project_y
2495    *
2496    * @Description:
2497    *   Computes the projection of the vector given by (v2-v1) along the
2498    *   vertical axis.
2499    *
2500    * @Input:
2501    *   v1 ::
2502    *     First input vector.
2503    *   v2 ::
2504    *     Second input vector.
2505    *
2506    * @Return:
2507    *   The distance in F26dot6 format.
2508    */
2509   static FT_F26Dot6
2510   Project_y( TT_ExecContext  exc,
2511              FT_Pos          dx,
2512              FT_Pos          dy )
2513   {
2514     FT_UNUSED( exc );
2515     FT_UNUSED( dx );
2516 
2517     return dy;
2518   }
2519 
2520 
2521   /**************************************************************************
2522    *
2523    * @Function:
2524    *   Compute_Funcs
2525    *
2526    * @Description:
2527    *   Computes the projection and movement function pointers according
2528    *   to the current graphics state.
2529    */
2530   static void
2531   Compute_Funcs( TT_ExecContext  exc )
2532   {
2533     if ( exc->GS.freeVector.x == 0x4000 )
2534       exc->F_dot_P = exc->GS.projVector.x;
2535     else if ( exc->GS.freeVector.y == 0x4000 )
2536       exc->F_dot_P = exc->GS.projVector.y;
2537     else
2538       exc->F_dot_P =
2539         ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
2540           (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
2541 
2542     if ( exc->GS.projVector.x == 0x4000 )
2543       exc->func_project = (TT_Project_Func)Project_x;
2544     else if ( exc->GS.projVector.y == 0x4000 )
2545       exc->func_project = (TT_Project_Func)Project_y;
2546     else
2547       exc->func_project = (TT_Project_Func)Project;
2548 
2549     if ( exc->GS.dualVector.x == 0x4000 )


2564         exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2565       }
2566       else if ( exc->GS.freeVector.y == 0x4000 )
2567       {
2568         exc->func_move      = (TT_Move_Func)Direct_Move_Y;
2569         exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2570       }
2571     }
2572 
2573     /* at small sizes, F_dot_P can become too small, resulting   */
2574     /* in overflows and `spikes' in a number of glyphs like `w'. */
2575 
2576     if ( FT_ABS( exc->F_dot_P ) < 0x400L )
2577       exc->F_dot_P = 0x4000L;
2578 
2579     /* Disable cached aspect ratio */
2580     exc->tt_metrics.ratio = 0;
2581   }
2582 
2583 
2584   /**************************************************************************
2585    *
2586    * @Function:
2587    *   Normalize
2588    *
2589    * @Description:
2590    *   Norms a vector.
2591    *
2592    * @Input:
2593    *   Vx ::
2594    *     The horizontal input vector coordinate.
2595    *   Vy ::
2596    *     The vertical input vector coordinate.
2597    *
2598    * @Output:
2599    *   R ::
2600    *     The normed unit vector.
2601    *
2602    * @Return:
2603    *   Returns FAILURE if a vector parameter is zero.
2604    *
2605    * @Note:
2606    *   In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and
2607    *   R is undefined.
2608    */
2609   static FT_Bool
2610   Normalize( FT_F26Dot6      Vx,
2611              FT_F26Dot6      Vy,
2612              FT_UnitVector*  R )
2613   {
2614     FT_Vector V;
2615 
2616 
2617     if ( Vx == 0 && Vy == 0 )
2618     {
2619       /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
2620       /*      to normalize the vector (0,0).  Return immediately. */
2621       return SUCCESS;
2622     }
2623 
2624     V.x = Vx;
2625     V.y = Vy;
2626 
2627     FT_Vector_NormLen( &V );
2628 
2629     R->x = (FT_F2Dot14)( V.x / 4 );
2630     R->y = (FT_F2Dot14)( V.y / 4 );
2631 
2632     return SUCCESS;
2633   }
2634 
2635 
2636   /**************************************************************************
2637    *
2638    * Here we start with the implementation of the various opcodes.
2639    *
2640    */
2641 
2642 
2643 #define ARRAY_BOUND_ERROR                         \
2644     do                                            \
2645     {                                             \
2646       exc->error = FT_THROW( Invalid_Reference ); \
2647       return;                                     \
2648     } while (0)
2649 
2650 
2651   /**************************************************************************
2652    *
2653    * MPPEM[]:      Measure Pixel Per EM
2654    * Opcode range: 0x4B
2655    * Stack:        --> Euint16
2656    */
2657   static void
2658   Ins_MPPEM( TT_ExecContext  exc,
2659              FT_Long*        args )
2660   {
2661     args[0] = exc->func_cur_ppem( exc );
2662   }
2663 
2664 
2665   /**************************************************************************
2666    *
2667    * MPS[]:        Measure Point Size
2668    * Opcode range: 0x4C
2669    * Stack:        --> Euint16
2670    */
2671   static void
2672   Ins_MPS( TT_ExecContext  exc,
2673            FT_Long*        args )
2674   {
2675     if ( NO_SUBPIXEL_HINTING )
2676     {
2677       /* Microsoft's GDI bytecode interpreter always returns value 12; */
2678       /* we return the current PPEM value instead.                     */
2679       args[0] = exc->func_cur_ppem( exc );
2680     }
2681     else
2682     {
2683       /* A possible practical application of the MPS instruction is to   */
2684       /* implement optical scaling and similar features, which should be */
2685       /* based on perceptual attributes, thus independent of the         */
2686       /* resolution.                                                     */
2687       args[0] = exc->pointSize;
2688     }
2689   }
2690 
2691 
2692   /**************************************************************************
2693    *
2694    * DUP[]:        DUPlicate the stack's top element
2695    * Opcode range: 0x20
2696    * Stack:        StkElt --> StkElt StkElt
2697    */
2698   static void
2699   Ins_DUP( FT_Long*  args )
2700   {
2701     args[1] = args[0];
2702   }
2703 
2704 
2705   /**************************************************************************
2706    *
2707    * POP[]:        POP the stack's top element
2708    * Opcode range: 0x21
2709    * Stack:        StkElt -->
2710    */
2711   static void
2712   Ins_POP( void )
2713   {
2714     /* nothing to do */
2715   }
2716 
2717 
2718   /**************************************************************************
2719    *
2720    * CLEAR[]:      CLEAR the entire stack
2721    * Opcode range: 0x22
2722    * Stack:        StkElt... -->
2723    */
2724   static void
2725   Ins_CLEAR( TT_ExecContext  exc )
2726   {
2727     exc->new_top = 0;
2728   }
2729 
2730 
2731   /**************************************************************************
2732    *
2733    * SWAP[]:       SWAP the stack's top two elements
2734    * Opcode range: 0x23
2735    * Stack:        2 * StkElt --> 2 * StkElt
2736    */
2737   static void
2738   Ins_SWAP( FT_Long*  args )
2739   {
2740     FT_Long  L;
2741 
2742 
2743     L       = args[0];
2744     args[0] = args[1];
2745     args[1] = L;
2746   }
2747 
2748 
2749   /**************************************************************************
2750    *
2751    * DEPTH[]:      return the stack DEPTH
2752    * Opcode range: 0x24
2753    * Stack:        --> uint32
2754    */
2755   static void
2756   Ins_DEPTH( TT_ExecContext  exc,
2757              FT_Long*        args )
2758   {
2759     args[0] = exc->top;
2760   }
2761 
2762 
2763   /**************************************************************************
2764    *
2765    * LT[]:         Less Than
2766    * Opcode range: 0x50
2767    * Stack:        int32? int32? --> bool
2768    */
2769   static void
2770   Ins_LT( FT_Long*  args )
2771   {
2772     args[0] = ( args[0] < args[1] );
2773   }
2774 
2775 
2776   /**************************************************************************
2777    *
2778    * LTEQ[]:       Less Than or EQual
2779    * Opcode range: 0x51
2780    * Stack:        int32? int32? --> bool
2781    */
2782   static void
2783   Ins_LTEQ( FT_Long*  args )
2784   {
2785     args[0] = ( args[0] <= args[1] );
2786   }
2787 
2788 
2789   /**************************************************************************
2790    *
2791    * GT[]:         Greater Than
2792    * Opcode range: 0x52
2793    * Stack:        int32? int32? --> bool
2794    */
2795   static void
2796   Ins_GT( FT_Long*  args )
2797   {
2798     args[0] = ( args[0] > args[1] );
2799   }
2800 
2801 
2802   /**************************************************************************
2803    *
2804    * GTEQ[]:       Greater Than or EQual
2805    * Opcode range: 0x53
2806    * Stack:        int32? int32? --> bool
2807    */
2808   static void
2809   Ins_GTEQ( FT_Long*  args )
2810   {
2811     args[0] = ( args[0] >= args[1] );
2812   }
2813 
2814 
2815   /**************************************************************************
2816    *
2817    * EQ[]:         EQual
2818    * Opcode range: 0x54
2819    * Stack:        StkElt StkElt --> bool
2820    */
2821   static void
2822   Ins_EQ( FT_Long*  args )
2823   {
2824     args[0] = ( args[0] == args[1] );
2825   }
2826 
2827 
2828   /**************************************************************************
2829    *
2830    * NEQ[]:        Not EQual
2831    * Opcode range: 0x55
2832    * Stack:        StkElt StkElt --> bool
2833    */
2834   static void
2835   Ins_NEQ( FT_Long*  args )
2836   {
2837     args[0] = ( args[0] != args[1] );
2838   }
2839 
2840 
2841   /**************************************************************************
2842    *
2843    * ODD[]:        Is ODD
2844    * Opcode range: 0x56
2845    * Stack:        f26.6 --> bool
2846    */
2847   static void
2848   Ins_ODD( TT_ExecContext  exc,
2849            FT_Long*        args )
2850   {
2851     args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 );
2852   }
2853 
2854 
2855   /**************************************************************************
2856    *
2857    * EVEN[]:       Is EVEN
2858    * Opcode range: 0x57
2859    * Stack:        f26.6 --> bool
2860    */
2861   static void
2862   Ins_EVEN( TT_ExecContext  exc,
2863             FT_Long*        args )
2864   {
2865     args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 );
2866   }
2867 
2868 
2869   /**************************************************************************
2870    *
2871    * AND[]:        logical AND
2872    * Opcode range: 0x5A
2873    * Stack:        uint32 uint32 --> uint32
2874    */
2875   static void
2876   Ins_AND( FT_Long*  args )
2877   {
2878     args[0] = ( args[0] && args[1] );
2879   }
2880 
2881 
2882   /**************************************************************************
2883    *
2884    * OR[]:         logical OR
2885    * Opcode range: 0x5B
2886    * Stack:        uint32 uint32 --> uint32
2887    */
2888   static void
2889   Ins_OR( FT_Long*  args )
2890   {
2891     args[0] = ( args[0] || args[1] );
2892   }
2893 
2894 
2895   /**************************************************************************
2896    *
2897    * NOT[]:        logical NOT
2898    * Opcode range: 0x5C
2899    * Stack:        StkElt --> uint32
2900    */
2901   static void
2902   Ins_NOT( FT_Long*  args )
2903   {
2904     args[0] = !args[0];
2905   }
2906 
2907 
2908   /**************************************************************************
2909    *
2910    * ADD[]:        ADD
2911    * Opcode range: 0x60
2912    * Stack:        f26.6 f26.6 --> f26.6
2913    */
2914   static void
2915   Ins_ADD( FT_Long*  args )
2916   {
2917     args[0] = ADD_LONG( args[0], args[1] );
2918   }
2919 
2920 
2921   /**************************************************************************
2922    *
2923    * SUB[]:        SUBtract
2924    * Opcode range: 0x61
2925    * Stack:        f26.6 f26.6 --> f26.6
2926    */
2927   static void
2928   Ins_SUB( FT_Long*  args )
2929   {
2930     args[0] = SUB_LONG( args[0], args[1] );
2931   }
2932 
2933 
2934   /**************************************************************************
2935    *
2936    * DIV[]:        DIVide
2937    * Opcode range: 0x62
2938    * Stack:        f26.6 f26.6 --> f26.6
2939    */
2940   static void
2941   Ins_DIV( TT_ExecContext  exc,
2942            FT_Long*        args )
2943   {
2944     if ( args[1] == 0 )
2945       exc->error = FT_THROW( Divide_By_Zero );
2946     else
2947       args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
2948   }
2949 
2950 
2951   /**************************************************************************
2952    *
2953    * MUL[]:        MULtiply
2954    * Opcode range: 0x63
2955    * Stack:        f26.6 f26.6 --> f26.6
2956    */
2957   static void
2958   Ins_MUL( FT_Long*  args )
2959   {
2960     args[0] = FT_MulDiv( args[0], args[1], 64L );
2961   }
2962 
2963 
2964   /**************************************************************************
2965    *
2966    * ABS[]:        ABSolute value
2967    * Opcode range: 0x64
2968    * Stack:        f26.6 --> f26.6
2969    */
2970   static void
2971   Ins_ABS( FT_Long*  args )
2972   {
2973     if ( args[0] < 0 )
2974       args[0] = NEG_LONG( args[0] );
2975   }
2976 
2977 
2978   /**************************************************************************
2979    *
2980    * NEG[]:        NEGate
2981    * Opcode range: 0x65
2982    * Stack:        f26.6 --> f26.6
2983    */
2984   static void
2985   Ins_NEG( FT_Long*  args )
2986   {
2987     args[0] = NEG_LONG( args[0] );
2988   }
2989 
2990 
2991   /**************************************************************************
2992    *
2993    * FLOOR[]:      FLOOR
2994    * Opcode range: 0x66
2995    * Stack:        f26.6 --> f26.6
2996    */
2997   static void
2998   Ins_FLOOR( FT_Long*  args )
2999   {
3000     args[0] = FT_PIX_FLOOR( args[0] );
3001   }
3002 
3003 
3004   /**************************************************************************
3005    *
3006    * CEILING[]:    CEILING
3007    * Opcode range: 0x67
3008    * Stack:        f26.6 --> f26.6
3009    */
3010   static void
3011   Ins_CEILING( FT_Long*  args )
3012   {
3013     args[0] = FT_PIX_CEIL_LONG( args[0] );
3014   }
3015 
3016 
3017   /**************************************************************************
3018    *
3019    * RS[]:         Read Store
3020    * Opcode range: 0x43
3021    * Stack:        uint32 --> uint32
3022    */
3023   static void
3024   Ins_RS( TT_ExecContext  exc,
3025           FT_Long*        args )
3026   {
3027     FT_ULong  I = (FT_ULong)args[0];
3028 
3029 
3030     if ( BOUNDSL( I, exc->storeSize ) )
3031     {
3032       if ( exc->pedantic_hinting )
3033         ARRAY_BOUND_ERROR;
3034       else
3035         args[0] = 0;
3036     }
3037     else
3038     {
3039 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3040       /* subpixel hinting - avoid Typeman Dstroke and */
3041       /* IStroke and Vacuform rounds                  */
3042       if ( SUBPIXEL_HINTING_INFINALITY                 &&
3043            exc->ignore_x_mode                          &&
3044            ( ( I == 24                             &&
3045                ( exc->face->sph_found_func_flags &
3046                  ( SPH_FDEF_SPACING_1 |
3047                    SPH_FDEF_SPACING_2 )          ) ) ||
3048              ( I == 22                      &&
3049                ( exc->sph_in_func_flags   &
3050                  SPH_FDEF_TYPEMAN_STROKES ) )        ||
3051              ( I == 8                              &&
3052                ( exc->face->sph_found_func_flags &
3053                  SPH_FDEF_VACUFORM_ROUND_1       ) &&
3054                exc->iup_called                     ) ) )
3055         args[0] = 0;
3056       else
3057 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3058         args[0] = exc->storage[I];
3059     }
3060   }
3061 
3062 
3063   /**************************************************************************
3064    *
3065    * WS[]:         Write Store
3066    * Opcode range: 0x42
3067    * Stack:        uint32 uint32 -->
3068    */
3069   static void
3070   Ins_WS( TT_ExecContext  exc,
3071           FT_Long*        args )
3072   {
3073     FT_ULong  I = (FT_ULong)args[0];
3074 
3075 
3076     if ( BOUNDSL( I, exc->storeSize ) )
3077     {
3078       if ( exc->pedantic_hinting )
3079         ARRAY_BOUND_ERROR;
3080     }
3081     else
3082       exc->storage[I] = args[1];
3083   }
3084 
3085 
3086   /**************************************************************************
3087    *
3088    * WCVTP[]:      Write CVT in Pixel units
3089    * Opcode range: 0x44
3090    * Stack:        f26.6 uint32 -->
3091    */
3092   static void
3093   Ins_WCVTP( TT_ExecContext  exc,
3094              FT_Long*        args )
3095   {
3096     FT_ULong  I = (FT_ULong)args[0];
3097 
3098 
3099     if ( BOUNDSL( I, exc->cvtSize ) )
3100     {
3101       if ( exc->pedantic_hinting )
3102         ARRAY_BOUND_ERROR;
3103     }
3104     else
3105       exc->func_write_cvt( exc, I, args[1] );
3106   }
3107 
3108 
3109   /**************************************************************************
3110    *
3111    * WCVTF[]:      Write CVT in Funits
3112    * Opcode range: 0x70
3113    * Stack:        uint32 uint32 -->
3114    */
3115   static void
3116   Ins_WCVTF( TT_ExecContext  exc,
3117              FT_Long*        args )
3118   {
3119     FT_ULong  I = (FT_ULong)args[0];
3120 
3121 
3122     if ( BOUNDSL( I, exc->cvtSize ) )
3123     {
3124       if ( exc->pedantic_hinting )
3125         ARRAY_BOUND_ERROR;
3126     }
3127     else
3128       exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );
3129   }
3130 
3131 
3132   /**************************************************************************
3133    *
3134    * RCVT[]:       Read CVT
3135    * Opcode range: 0x45
3136    * Stack:        uint32 --> f26.6
3137    */
3138   static void
3139   Ins_RCVT( TT_ExecContext  exc,
3140             FT_Long*        args )
3141   {
3142     FT_ULong  I = (FT_ULong)args[0];
3143 
3144 
3145     if ( BOUNDSL( I, exc->cvtSize ) )
3146     {
3147       if ( exc->pedantic_hinting )
3148         ARRAY_BOUND_ERROR;
3149       else
3150         args[0] = 0;
3151     }
3152     else
3153       args[0] = exc->func_read_cvt( exc, I );
3154   }
3155 
3156 
3157   /**************************************************************************
3158    *
3159    * AA[]:         Adjust Angle
3160    * Opcode range: 0x7F
3161    * Stack:        uint32 -->
3162    */
3163   static void
3164   Ins_AA( void )
3165   {
3166     /* intentionally no longer supported */
3167   }
3168 
3169 
3170   /**************************************************************************
3171    *
3172    * DEBUG[]:      DEBUG.  Unsupported.
3173    * Opcode range: 0x4F
3174    * Stack:        uint32 -->
3175    *
3176    * Note: The original instruction pops a value from the stack.
3177    */
3178   static void
3179   Ins_DEBUG( TT_ExecContext  exc )
3180   {
3181     exc->error = FT_THROW( Debug_OpCode );
3182   }
3183 
3184 
3185   /**************************************************************************
3186    *
3187    * ROUND[ab]:    ROUND value
3188    * Opcode range: 0x68-0x6B
3189    * Stack:        f26.6 --> f26.6
3190    */
3191   static void
3192   Ins_ROUND( TT_ExecContext  exc,
3193              FT_Long*        args )
3194   {
3195     args[0] = exc->func_round(
3196                 exc,
3197                 args[0],
3198                 exc->tt_metrics.compensations[exc->opcode - 0x68] );
3199   }
3200 
3201 
3202   /**************************************************************************
3203    *
3204    * NROUND[ab]:   No ROUNDing of value
3205    * Opcode range: 0x6C-0x6F
3206    * Stack:        f26.6 --> f26.6
3207    */
3208   static void
3209   Ins_NROUND( TT_ExecContext  exc,
3210               FT_Long*        args )
3211   {
3212     args[0] = Round_None(
3213                 exc,
3214                 args[0],
3215                 exc->tt_metrics.compensations[exc->opcode - 0x6C] );
3216   }
3217 
3218 
3219   /**************************************************************************
3220    *
3221    * MAX[]:        MAXimum
3222    * Opcode range: 0x8B
3223    * Stack:        int32? int32? --> int32
3224    */
3225   static void
3226   Ins_MAX( FT_Long*  args )
3227   {
3228     if ( args[1] > args[0] )
3229       args[0] = args[1];
3230   }
3231 
3232 
3233   /**************************************************************************
3234    *
3235    * MIN[]:        MINimum
3236    * Opcode range: 0x8C
3237    * Stack:        int32? int32? --> int32
3238    */
3239   static void
3240   Ins_MIN( FT_Long*  args )
3241   {
3242     if ( args[1] < args[0] )
3243       args[0] = args[1];
3244   }
3245 
3246 
3247   /**************************************************************************
3248    *
3249    * MINDEX[]:     Move INDEXed element
3250    * Opcode range: 0x26
3251    * Stack:        int32? --> StkElt
3252    */
3253   static void
3254   Ins_MINDEX( TT_ExecContext  exc,
3255               FT_Long*        args )
3256   {
3257     FT_Long  L, K;
3258 
3259 
3260     L = args[0];
3261 
3262     if ( L <= 0 || L > exc->args )
3263     {
3264       if ( exc->pedantic_hinting )
3265         exc->error = FT_THROW( Invalid_Reference );
3266     }
3267     else
3268     {
3269       K = exc->stack[exc->args - L];
3270 
3271       FT_ARRAY_MOVE( &exc->stack[exc->args - L    ],
3272                      &exc->stack[exc->args - L + 1],
3273                      ( L - 1 ) );
3274 
3275       exc->stack[exc->args - 1] = K;
3276     }
3277   }
3278 
3279 
3280   /**************************************************************************
3281    *
3282    * CINDEX[]:     Copy INDEXed element
3283    * Opcode range: 0x25
3284    * Stack:        int32 --> StkElt
3285    */
3286   static void
3287   Ins_CINDEX( TT_ExecContext  exc,
3288               FT_Long*        args )
3289   {
3290     FT_Long  L;
3291 
3292 
3293     L = args[0];
3294 
3295     if ( L <= 0 || L > exc->args )
3296     {
3297       if ( exc->pedantic_hinting )
3298         exc->error = FT_THROW( Invalid_Reference );
3299       args[0] = 0;
3300     }
3301     else
3302       args[0] = exc->stack[exc->args - L];
3303   }
3304 
3305 
3306   /**************************************************************************
3307    *
3308    * ROLL[]:       ROLL top three elements
3309    * Opcode range: 0x8A
3310    * Stack:        3 * StkElt --> 3 * StkElt
3311    */
3312   static void
3313   Ins_ROLL( FT_Long*  args )
3314   {
3315     FT_Long  A, B, C;
3316 
3317 
3318     A = args[2];
3319     B = args[1];
3320     C = args[0];
3321 
3322     args[2] = C;
3323     args[1] = A;
3324     args[0] = B;
3325   }
3326 
3327 
3328   /**************************************************************************
3329    *
3330    * MANAGING THE FLOW OF CONTROL
3331    *
3332    */
3333 
3334 
3335   /**************************************************************************
3336    *
3337    * SLOOP[]:      Set LOOP variable
3338    * Opcode range: 0x17
3339    * Stack:        int32? -->
3340    */
3341   static void
3342   Ins_SLOOP( TT_ExecContext  exc,
3343              FT_Long*        args )
3344   {
3345     if ( args[0] < 0 )
3346       exc->error = FT_THROW( Bad_Argument );
3347     else
3348     {
3349       /* we heuristically limit the number of loops to 16 bits */
3350       exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0];
3351     }
3352   }
3353 
3354 
3355   static FT_Bool
3356   SkipCode( TT_ExecContext  exc )
3357   {
3358     exc->IP += exc->length;
3359 
3360     if ( exc->IP < exc->codeSize )


3362       exc->opcode = exc->code[exc->IP];
3363 
3364       exc->length = opcode_length[exc->opcode];
3365       if ( exc->length < 0 )
3366       {
3367         if ( exc->IP + 1 >= exc->codeSize )
3368           goto Fail_Overflow;
3369         exc->length = 2 - exc->length * exc->code[exc->IP + 1];
3370       }
3371 
3372       if ( exc->IP + exc->length <= exc->codeSize )
3373         return SUCCESS;
3374     }
3375 
3376   Fail_Overflow:
3377     exc->error = FT_THROW( Code_Overflow );
3378     return FAILURE;
3379   }
3380 
3381 
3382   /**************************************************************************
3383    *
3384    * IF[]:         IF test
3385    * Opcode range: 0x58
3386    * Stack:        StkElt -->
3387    */
3388   static void
3389   Ins_IF( TT_ExecContext  exc,
3390           FT_Long*        args )
3391   {
3392     FT_Int   nIfs;
3393     FT_Bool  Out;
3394 
3395 
3396     if ( args[0] != 0 )
3397       return;
3398 
3399     nIfs = 1;
3400     Out = 0;
3401 
3402     do
3403     {
3404       if ( SkipCode( exc ) == FAILURE )
3405         return;
3406 
3407       switch ( exc->opcode )
3408       {
3409       case 0x58:      /* IF */
3410         nIfs++;
3411         break;
3412 
3413       case 0x1B:      /* ELSE */
3414         Out = FT_BOOL( nIfs == 1 );
3415         break;
3416 
3417       case 0x59:      /* EIF */
3418         nIfs--;
3419         Out = FT_BOOL( nIfs == 0 );
3420         break;
3421       }
3422     } while ( Out == 0 );
3423   }
3424 
3425 
3426   /**************************************************************************
3427    *
3428    * ELSE[]:       ELSE
3429    * Opcode range: 0x1B
3430    * Stack:        -->
3431    */
3432   static void
3433   Ins_ELSE( TT_ExecContext  exc )
3434   {
3435     FT_Int  nIfs;
3436 
3437 
3438     nIfs = 1;
3439 
3440     do
3441     {
3442       if ( SkipCode( exc ) == FAILURE )
3443         return;
3444 
3445       switch ( exc->opcode )
3446       {
3447       case 0x58:    /* IF */
3448         nIfs++;
3449         break;
3450 
3451       case 0x59:    /* EIF */
3452         nIfs--;
3453         break;
3454       }
3455     } while ( nIfs != 0 );
3456   }
3457 
3458 
3459   /**************************************************************************
3460    *
3461    * EIF[]:        End IF
3462    * Opcode range: 0x59
3463    * Stack:        -->
3464    */
3465   static void
3466   Ins_EIF( void )
3467   {
3468     /* nothing to do */
3469   }
3470 
3471 
3472   /**************************************************************************
3473    *
3474    * JMPR[]:       JuMP Relative
3475    * Opcode range: 0x1C
3476    * Stack:        int32 -->
3477    */
3478   static void
3479   Ins_JMPR( TT_ExecContext  exc,
3480             FT_Long*        args )
3481   {
3482     if ( args[0] == 0 && exc->args == 0 )
3483     {
3484       exc->error = FT_THROW( Bad_Argument );
3485       return;
3486     }
3487 
3488     exc->IP += args[0];
3489     if ( exc->IP < 0                                             ||
3490          ( exc->callTop > 0                                    &&
3491            exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
3492     {
3493       exc->error = FT_THROW( Bad_Argument );
3494       return;
3495     }
3496 
3497     exc->step_ins = FALSE;
3498 
3499     if ( args[0] < 0 )
3500     {
3501       if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
3502         exc->error = FT_THROW( Execution_Too_Long );
3503     }
3504   }
3505 
3506 
3507   /**************************************************************************
3508    *
3509    * JROT[]:       Jump Relative On True
3510    * Opcode range: 0x78
3511    * Stack:        StkElt int32 -->
3512    */
3513   static void
3514   Ins_JROT( TT_ExecContext  exc,
3515             FT_Long*        args )
3516   {
3517     if ( args[1] != 0 )
3518       Ins_JMPR( exc, args );
3519   }
3520 
3521 
3522   /**************************************************************************
3523    *
3524    * JROF[]:       Jump Relative On False
3525    * Opcode range: 0x79
3526    * Stack:        StkElt int32 -->
3527    */
3528   static void
3529   Ins_JROF( TT_ExecContext  exc,
3530             FT_Long*        args )
3531   {
3532     if ( args[1] == 0 )
3533       Ins_JMPR( exc, args );
3534   }
3535 
3536 
3537   /**************************************************************************
3538    *
3539    * DEFINING AND USING FUNCTIONS AND INSTRUCTIONS
3540    *
3541    */
3542 
3543 
3544   /**************************************************************************
3545    *
3546    * FDEF[]:       Function DEFinition
3547    * Opcode range: 0x2C
3548    * Stack:        uint32 -->
3549    */
3550   static void
3551   Ins_FDEF( TT_ExecContext  exc,
3552             FT_Long*        args )
3553   {
3554     FT_ULong       n;
3555     TT_DefRecord*  rec;
3556     TT_DefRecord*  limit;
3557 
3558 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3559     /* arguments to opcodes are skipped by `SKIP_Code' */
3560     FT_Byte    opcode_pattern[9][12] = {
3561                  /* #0 inline delta function 1 */
3562                  {
3563                    0x4B, /* PPEM    */
3564                    0x53, /* GTEQ    */
3565                    0x23, /* SWAP    */
3566                    0x4B, /* PPEM    */
3567                    0x51, /* LTEQ    */
3568                    0x5A, /* AND     */
3569                    0x58, /* IF      */


3827             ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
3828       }
3829 
3830 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3831 
3832       switch ( exc->opcode )
3833       {
3834       case 0x89:    /* IDEF */
3835       case 0x2C:    /* FDEF */
3836         exc->error = FT_THROW( Nested_DEFS );
3837         return;
3838 
3839       case 0x2D:   /* ENDF */
3840         rec->end = exc->IP;
3841         return;
3842       }
3843     }
3844   }
3845 
3846 
3847   /**************************************************************************
3848    *
3849    * ENDF[]:       END Function definition
3850    * Opcode range: 0x2D
3851    * Stack:        -->
3852    */
3853   static void
3854   Ins_ENDF( TT_ExecContext  exc )
3855   {
3856     TT_CallRec*  pRec;
3857 
3858 
3859 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3860     exc->sph_in_func_flags = 0x0000;
3861 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3862 
3863     if ( exc->callTop <= 0 )     /* We encountered an ENDF without a call */
3864     {
3865       exc->error = FT_THROW( ENDF_In_Exec_Stream );
3866       return;
3867     }
3868 
3869     exc->callTop--;
3870 
3871     pRec = &exc->callStack[exc->callTop];
3872 


3876 
3877     if ( pRec->Cur_Count > 0 )
3878     {
3879       exc->callTop++;
3880       exc->IP = pRec->Def->start;
3881     }
3882     else
3883       /* Loop through the current function */
3884       Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );
3885 
3886     /* Exit the current call frame.                      */
3887 
3888     /* NOTE: If the last instruction of a program is a   */
3889     /*       CALL or LOOPCALL, the return address is     */
3890     /*       always out of the code range.  This is a    */
3891     /*       valid address, and it is why we do not test */
3892     /*       the result of Ins_Goto_CodeRange() here!    */
3893   }
3894 
3895 
3896   /**************************************************************************
3897    *
3898    * CALL[]:       CALL function
3899    * Opcode range: 0x2B
3900    * Stack:        uint32? -->
3901    */
3902   static void
3903   Ins_CALL( TT_ExecContext  exc,
3904             FT_Long*        args )
3905   {
3906     FT_ULong       F;
3907     TT_CallRec*    pCrec;
3908     TT_DefRecord*  def;
3909 
3910 
3911     /* first of all, check the index */
3912 
3913     F = (FT_ULong)args[0];
3914     if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3915       goto Fail;
3916 
3917     /* Except for some old Apple fonts, all functions in a TrueType */
3918     /* font are defined in increasing order, starting from 0.  This */
3919     /* means that we normally have                                  */
3920     /*                                                              */
3921     /*    exc->maxFunc+1 == exc->numFDefs                           */


3965     pCrec = exc->callStack + exc->callTop;
3966 
3967     pCrec->Caller_Range = exc->curRange;
3968     pCrec->Caller_IP    = exc->IP + 1;
3969     pCrec->Cur_Count    = 1;
3970     pCrec->Def          = def;
3971 
3972     exc->callTop++;
3973 
3974     Ins_Goto_CodeRange( exc, def->range, def->start );
3975 
3976     exc->step_ins = FALSE;
3977 
3978     return;
3979 
3980   Fail:
3981     exc->error = FT_THROW( Invalid_Reference );
3982   }
3983 
3984 
3985   /**************************************************************************
3986    *
3987    * LOOPCALL[]:   LOOP and CALL function
3988    * Opcode range: 0x2A
3989    * Stack:        uint32? Eint16? -->
3990    */
3991   static void
3992   Ins_LOOPCALL( TT_ExecContext  exc,
3993                 FT_Long*        args )
3994   {
3995     FT_ULong       F;
3996     TT_CallRec*    pCrec;
3997     TT_DefRecord*  def;
3998 
3999 
4000     /* first of all, check the index */
4001     F = (FT_ULong)args[1];
4002     if ( BOUNDSL( F, exc->maxFunc + 1 ) )
4003       goto Fail;
4004 
4005     /* Except for some old Apple fonts, all functions in a TrueType */
4006     /* font are defined in increasing order, starting from 0.  This */
4007     /* means that we normally have                                  */
4008     /*                                                              */
4009     /*    exc->maxFunc+1 == exc->numFDefs                           */
4010     /*    exc->FDefs[n].opc == n for n in 0..exc->maxFunc           */


4058       pCrec->Def          = def;
4059 
4060       exc->callTop++;
4061 
4062       Ins_Goto_CodeRange( exc, def->range, def->start );
4063 
4064       exc->step_ins = FALSE;
4065 
4066       exc->loopcall_counter += (FT_ULong)args[0];
4067       if ( exc->loopcall_counter > exc->loopcall_counter_max )
4068         exc->error = FT_THROW( Execution_Too_Long );
4069     }
4070 
4071     return;
4072 
4073   Fail:
4074     exc->error = FT_THROW( Invalid_Reference );
4075   }
4076 
4077 
4078   /**************************************************************************
4079    *
4080    * IDEF[]:       Instruction DEFinition
4081    * Opcode range: 0x89
4082    * Stack:        Eint8 -->
4083    */
4084   static void
4085   Ins_IDEF( TT_ExecContext  exc,
4086             FT_Long*        args )
4087   {
4088     TT_DefRecord*  def;
4089     TT_DefRecord*  limit;
4090 
4091 
4092     /* we enable IDEF only in `prep' or `fpgm' */
4093     if ( exc->curRange == tt_coderange_glyph )
4094     {
4095       exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
4096       return;
4097     }
4098 
4099     /*  First of all, look for the same function in our table */
4100 
4101     def   = exc->IDefs;
4102     limit = def + exc->numIDefs;
4103 


4133 
4134     /* Now skip the whole function definition. */
4135     /* We don't allow nested IDEFs & FDEFs.    */
4136 
4137     while ( SkipCode( exc ) == SUCCESS )
4138     {
4139       switch ( exc->opcode )
4140       {
4141       case 0x89:   /* IDEF */
4142       case 0x2C:   /* FDEF */
4143         exc->error = FT_THROW( Nested_DEFS );
4144         return;
4145       case 0x2D:   /* ENDF */
4146         def->end = exc->IP;
4147         return;
4148       }
4149     }
4150   }
4151 
4152 
4153   /**************************************************************************
4154    *
4155    * PUSHING DATA ONTO THE INTERPRETER STACK
4156    *
4157    */
4158 
4159 
4160   /**************************************************************************
4161    *
4162    * NPUSHB[]:     PUSH N Bytes
4163    * Opcode range: 0x40
4164    * Stack:        --> uint32...
4165    */
4166   static void
4167   Ins_NPUSHB( TT_ExecContext  exc,
4168               FT_Long*        args )
4169   {
4170     FT_UShort  L, K;
4171 
4172 
4173     L = (FT_UShort)exc->code[exc->IP + 1];
4174 
4175     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4176     {
4177       exc->error = FT_THROW( Stack_Overflow );
4178       return;
4179     }
4180 
4181     for ( K = 1; K <= L; K++ )
4182       args[K - 1] = exc->code[exc->IP + K + 1];
4183 
4184     exc->new_top += L;
4185   }
4186 
4187 
4188   /**************************************************************************
4189    *
4190    * NPUSHW[]:     PUSH N Words
4191    * Opcode range: 0x41
4192    * Stack:        --> int32...
4193    */
4194   static void
4195   Ins_NPUSHW( TT_ExecContext  exc,
4196               FT_Long*        args )
4197   {
4198     FT_UShort  L, K;
4199 
4200 
4201     L = (FT_UShort)exc->code[exc->IP + 1];
4202 
4203     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4204     {
4205       exc->error = FT_THROW( Stack_Overflow );
4206       return;
4207     }
4208 
4209     exc->IP += 2;
4210 
4211     for ( K = 0; K < L; K++ )
4212       args[K] = GetShortIns( exc );
4213 
4214     exc->step_ins = FALSE;
4215     exc->new_top += L;
4216   }
4217 
4218 
4219   /**************************************************************************
4220    *
4221    * PUSHB[abc]:   PUSH Bytes
4222    * Opcode range: 0xB0-0xB7
4223    * Stack:        --> uint32...
4224    */
4225   static void
4226   Ins_PUSHB( TT_ExecContext  exc,
4227              FT_Long*        args )
4228   {
4229     FT_UShort  L, K;
4230 
4231 
4232     L = (FT_UShort)( exc->opcode - 0xB0 + 1 );
4233 
4234     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4235     {
4236       exc->error = FT_THROW( Stack_Overflow );
4237       return;
4238     }
4239 
4240     for ( K = 1; K <= L; K++ )
4241       args[K - 1] = exc->code[exc->IP + K];
4242   }
4243 
4244 
4245   /**************************************************************************
4246    *
4247    * PUSHW[abc]:   PUSH Words
4248    * Opcode range: 0xB8-0xBF
4249    * Stack:        --> int32...
4250    */
4251   static void
4252   Ins_PUSHW( TT_ExecContext  exc,
4253              FT_Long*        args )
4254   {
4255     FT_UShort  L, K;
4256 
4257 
4258     L = (FT_UShort)( exc->opcode - 0xB8 + 1 );
4259 
4260     if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4261     {
4262       exc->error = FT_THROW( Stack_Overflow );
4263       return;
4264     }
4265 
4266     exc->IP++;
4267 
4268     for ( K = 0; K < L; K++ )
4269       args[K] = GetShortIns( exc );
4270 
4271     exc->step_ins = FALSE;
4272   }
4273 
4274 
4275   /**************************************************************************
4276    *
4277    * MANAGING THE GRAPHICS STATE
4278    *
4279    */
4280 
4281 
4282   static FT_Bool
4283   Ins_SxVTL( TT_ExecContext  exc,
4284              FT_UShort       aIdx1,
4285              FT_UShort       aIdx2,
4286              FT_UnitVector*  Vec )
4287   {
4288     FT_Long     A, B, C;
4289     FT_Vector*  p1;
4290     FT_Vector*  p2;
4291 
4292     FT_Byte  opcode = exc->opcode;
4293 
4294 
4295     if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
4296          BOUNDS( aIdx2, exc->zp1.n_points ) )
4297     {
4298       if ( exc->pedantic_hinting )
4299         exc->error = FT_THROW( Invalid_Reference );


4313 
4314     if ( A == 0 && B == 0 )
4315     {
4316       A      = 0x4000;
4317       opcode = 0;
4318     }
4319 
4320     if ( ( opcode & 1 ) != 0 )
4321     {
4322       C = B;   /* counter clockwise rotation */
4323       B = A;
4324       A = NEG_LONG( C );
4325     }
4326 
4327     Normalize( A, B, Vec );
4328 
4329     return SUCCESS;
4330   }
4331 
4332 
4333   /**************************************************************************
4334    *
4335    * SVTCA[a]:     Set (F and P) Vectors to Coordinate Axis
4336    * Opcode range: 0x00-0x01
4337    * Stack:        -->
4338    *
4339    * SPvTCA[a]:    Set PVector to Coordinate Axis
4340    * Opcode range: 0x02-0x03
4341    * Stack:        -->
4342    *
4343    * SFvTCA[a]:    Set FVector to Coordinate Axis
4344    * Opcode range: 0x04-0x05
4345    * Stack:        -->
4346    */
4347   static void
4348   Ins_SxyTCA( TT_ExecContext  exc )
4349   {
4350     FT_Short  AA, BB;
4351 
4352     FT_Byte  opcode = exc->opcode;
4353 
4354 
4355     AA = (FT_Short)( ( opcode & 1 ) << 14 );
4356     BB = (FT_Short)( AA ^ 0x4000 );
4357 
4358     if ( opcode < 4 )
4359     {
4360       exc->GS.projVector.x = AA;
4361       exc->GS.projVector.y = BB;
4362 
4363       exc->GS.dualVector.x = AA;
4364       exc->GS.dualVector.y = BB;
4365     }
4366 
4367     if ( ( opcode & 2 ) == 0 )
4368     {
4369       exc->GS.freeVector.x = AA;
4370       exc->GS.freeVector.y = BB;
4371     }
4372 
4373     Compute_Funcs( exc );
4374   }
4375 
4376 
4377   /**************************************************************************
4378    *
4379    * SPvTL[a]:     Set PVector To Line
4380    * Opcode range: 0x06-0x07
4381    * Stack:        uint32 uint32 -->
4382    */
4383   static void
4384   Ins_SPVTL( TT_ExecContext  exc,
4385              FT_Long*        args )
4386   {
4387     if ( Ins_SxVTL( exc,
4388                     (FT_UShort)args[1],
4389                     (FT_UShort)args[0],
4390                     &exc->GS.projVector ) == SUCCESS )
4391     {
4392       exc->GS.dualVector = exc->GS.projVector;
4393       Compute_Funcs( exc );
4394     }
4395   }
4396 
4397 
4398   /**************************************************************************
4399    *
4400    * SFvTL[a]:     Set FVector To Line
4401    * Opcode range: 0x08-0x09
4402    * Stack:        uint32 uint32 -->
4403    */
4404   static void
4405   Ins_SFVTL( TT_ExecContext  exc,
4406              FT_Long*        args )
4407   {
4408     if ( Ins_SxVTL( exc,
4409                     (FT_UShort)args[1],
4410                     (FT_UShort)args[0],
4411                     &exc->GS.freeVector ) == SUCCESS )
4412     {
4413       Compute_Funcs( exc );
4414     }
4415   }
4416 
4417 
4418   /**************************************************************************
4419    *
4420    * SFvTPv[]:     Set FVector To PVector
4421    * Opcode range: 0x0E
4422    * Stack:        -->
4423    */
4424   static void
4425   Ins_SFVTPV( TT_ExecContext  exc )
4426   {
4427     exc->GS.freeVector = exc->GS.projVector;
4428     Compute_Funcs( exc );
4429   }
4430 
4431 
4432   /**************************************************************************
4433    *
4434    * SPvFS[]:      Set PVector From Stack
4435    * Opcode range: 0x0A
4436    * Stack:        f2.14 f2.14 -->
4437    */
4438   static void
4439   Ins_SPVFS( TT_ExecContext  exc,
4440              FT_Long*        args )
4441   {
4442     FT_Short  S;
4443     FT_Long   X, Y;
4444 
4445 
4446     /* Only use low 16bits, then sign extend */
4447     S = (FT_Short)args[1];
4448     Y = (FT_Long)S;
4449     S = (FT_Short)args[0];
4450     X = (FT_Long)S;
4451 
4452     Normalize( X, Y, &exc->GS.projVector );
4453 
4454     exc->GS.dualVector = exc->GS.projVector;
4455     Compute_Funcs( exc );
4456   }
4457 
4458 
4459   /**************************************************************************
4460    *
4461    * SFvFS[]:      Set FVector From Stack
4462    * Opcode range: 0x0B
4463    * Stack:        f2.14 f2.14 -->
4464    */
4465   static void
4466   Ins_SFVFS( TT_ExecContext  exc,
4467              FT_Long*        args )
4468   {
4469     FT_Short  S;
4470     FT_Long   X, Y;
4471 
4472 
4473     /* Only use low 16bits, then sign extend */
4474     S = (FT_Short)args[1];
4475     Y = (FT_Long)S;
4476     S = (FT_Short)args[0];
4477     X = S;
4478 
4479     Normalize( X, Y, &exc->GS.freeVector );
4480     Compute_Funcs( exc );
4481   }
4482 
4483 
4484   /**************************************************************************
4485    *
4486    * GPv[]:        Get Projection Vector
4487    * Opcode range: 0x0C
4488    * Stack:        ef2.14 --> ef2.14
4489    */
4490   static void
4491   Ins_GPV( TT_ExecContext  exc,
4492            FT_Long*        args )
4493   {
4494     args[0] = exc->GS.projVector.x;
4495     args[1] = exc->GS.projVector.y;
4496   }
4497 
4498 
4499   /**************************************************************************
4500    *
4501    * GFv[]:        Get Freedom Vector
4502    * Opcode range: 0x0D
4503    * Stack:        ef2.14 --> ef2.14
4504    */
4505   static void
4506   Ins_GFV( TT_ExecContext  exc,
4507            FT_Long*        args )
4508   {
4509     args[0] = exc->GS.freeVector.x;
4510     args[1] = exc->GS.freeVector.y;
4511   }
4512 
4513 
4514   /**************************************************************************
4515    *
4516    * SRP0[]:       Set Reference Point 0
4517    * Opcode range: 0x10
4518    * Stack:        uint32 -->
4519    */
4520   static void
4521   Ins_SRP0( TT_ExecContext  exc,
4522             FT_Long*        args )
4523   {
4524     exc->GS.rp0 = (FT_UShort)args[0];
4525   }
4526 
4527 
4528   /**************************************************************************
4529    *
4530    * SRP1[]:       Set Reference Point 1
4531    * Opcode range: 0x11
4532    * Stack:        uint32 -->
4533    */
4534   static void
4535   Ins_SRP1( TT_ExecContext  exc,
4536             FT_Long*        args )
4537   {
4538     exc->GS.rp1 = (FT_UShort)args[0];
4539   }
4540 
4541 
4542   /**************************************************************************
4543    *
4544    * SRP2[]:       Set Reference Point 2
4545    * Opcode range: 0x12
4546    * Stack:        uint32 -->
4547    */
4548   static void
4549   Ins_SRP2( TT_ExecContext  exc,
4550             FT_Long*        args )
4551   {
4552     exc->GS.rp2 = (FT_UShort)args[0];
4553   }
4554 
4555 
4556   /**************************************************************************
4557    *
4558    * SMD[]:        Set Minimum Distance
4559    * Opcode range: 0x1A
4560    * Stack:        f26.6 -->
4561    */
4562   static void
4563   Ins_SMD( TT_ExecContext  exc,
4564            FT_Long*        args )
4565   {
4566     exc->GS.minimum_distance = args[0];
4567   }
4568 
4569 
4570   /**************************************************************************
4571    *
4572    * SCVTCI[]:     Set Control Value Table Cut In
4573    * Opcode range: 0x1D
4574    * Stack:        f26.6 -->
4575    */
4576   static void
4577   Ins_SCVTCI( TT_ExecContext  exc,
4578               FT_Long*        args )
4579   {
4580     exc->GS.control_value_cutin = (FT_F26Dot6)args[0];
4581   }
4582 
4583 
4584   /**************************************************************************
4585    *
4586    * SSWCI[]:      Set Single Width Cut In
4587    * Opcode range: 0x1E
4588    * Stack:        f26.6 -->
4589    */
4590   static void
4591   Ins_SSWCI( TT_ExecContext  exc,
4592              FT_Long*        args )
4593   {
4594     exc->GS.single_width_cutin = (FT_F26Dot6)args[0];
4595   }
4596 
4597 
4598   /**************************************************************************
4599    *
4600    * SSW[]:        Set Single Width
4601    * Opcode range: 0x1F
4602    * Stack:        int32? -->
4603    */
4604   static void
4605   Ins_SSW( TT_ExecContext  exc,
4606            FT_Long*        args )
4607   {
4608     exc->GS.single_width_value = FT_MulFix( args[0],
4609                                             exc->tt_metrics.scale );
4610   }
4611 
4612 
4613   /**************************************************************************
4614    *
4615    * FLIPON[]:     Set auto-FLIP to ON
4616    * Opcode range: 0x4D
4617    * Stack:        -->
4618    */
4619   static void
4620   Ins_FLIPON( TT_ExecContext  exc )
4621   {
4622     exc->GS.auto_flip = TRUE;
4623   }
4624 
4625 
4626   /**************************************************************************
4627    *
4628    * FLIPOFF[]:    Set auto-FLIP to OFF
4629    * Opcode range: 0x4E
4630    * Stack:        -->
4631    */
4632   static void
4633   Ins_FLIPOFF( TT_ExecContext  exc )
4634   {
4635     exc->GS.auto_flip = FALSE;
4636   }
4637 
4638 
4639   /**************************************************************************
4640    *
4641    * SANGW[]:      Set ANGle Weight
4642    * Opcode range: 0x7E
4643    * Stack:        uint32 -->
4644    */
4645   static void
4646   Ins_SANGW( void )
4647   {
4648     /* instruction not supported anymore */
4649   }
4650 
4651 
4652   /**************************************************************************
4653    *
4654    * SDB[]:        Set Delta Base
4655    * Opcode range: 0x5E
4656    * Stack:        uint32 -->
4657    */
4658   static void
4659   Ins_SDB( TT_ExecContext  exc,
4660            FT_Long*        args )
4661   {
4662     exc->GS.delta_base = (FT_UShort)args[0];
4663   }
4664 
4665 
4666   /**************************************************************************
4667    *
4668    * SDS[]:        Set Delta Shift
4669    * Opcode range: 0x5F
4670    * Stack:        uint32 -->
4671    */
4672   static void
4673   Ins_SDS( TT_ExecContext  exc,
4674            FT_Long*        args )
4675   {
4676     if ( (FT_ULong)args[0] > 6UL )
4677       exc->error = FT_THROW( Bad_Argument );
4678     else
4679       exc->GS.delta_shift = (FT_UShort)args[0];
4680   }
4681 
4682 
4683   /**************************************************************************
4684    *
4685    * RTHG[]:       Round To Half Grid
4686    * Opcode range: 0x19
4687    * Stack:        -->
4688    */
4689   static void
4690   Ins_RTHG( TT_ExecContext  exc )
4691   {
4692     exc->GS.round_state = TT_Round_To_Half_Grid;
4693     exc->func_round     = (TT_Round_Func)Round_To_Half_Grid;
4694   }
4695 
4696 
4697   /**************************************************************************
4698    *
4699    * RTG[]:        Round To Grid
4700    * Opcode range: 0x18
4701    * Stack:        -->
4702    */
4703   static void
4704   Ins_RTG( TT_ExecContext  exc )
4705   {
4706     exc->GS.round_state = TT_Round_To_Grid;
4707     exc->func_round     = (TT_Round_Func)Round_To_Grid;
4708   }
4709 
4710 
4711   /**************************************************************************
4712    * RTDG[]:       Round To Double Grid
4713    * Opcode range: 0x3D
4714    * Stack:        -->
4715    */
4716   static void
4717   Ins_RTDG( TT_ExecContext  exc )
4718   {
4719     exc->GS.round_state = TT_Round_To_Double_Grid;
4720     exc->func_round     = (TT_Round_Func)Round_To_Double_Grid;
4721   }
4722 
4723 
4724   /**************************************************************************
4725    * RUTG[]:       Round Up To Grid
4726    * Opcode range: 0x7C
4727    * Stack:        -->
4728    */
4729   static void
4730   Ins_RUTG( TT_ExecContext  exc )
4731   {
4732     exc->GS.round_state = TT_Round_Up_To_Grid;
4733     exc->func_round     = (TT_Round_Func)Round_Up_To_Grid;
4734   }
4735 
4736 
4737   /**************************************************************************
4738    *
4739    * RDTG[]:       Round Down To Grid
4740    * Opcode range: 0x7D
4741    * Stack:        -->
4742    */
4743   static void
4744   Ins_RDTG( TT_ExecContext  exc )
4745   {
4746     exc->GS.round_state = TT_Round_Down_To_Grid;
4747     exc->func_round     = (TT_Round_Func)Round_Down_To_Grid;
4748   }
4749 
4750 
4751   /**************************************************************************
4752    *
4753    * ROFF[]:       Round OFF
4754    * Opcode range: 0x7A
4755    * Stack:        -->
4756    */
4757   static void
4758   Ins_ROFF( TT_ExecContext  exc )
4759   {
4760     exc->GS.round_state = TT_Round_Off;
4761     exc->func_round     = (TT_Round_Func)Round_None;
4762   }
4763 
4764 
4765   /**************************************************************************
4766    *
4767    * SROUND[]:     Super ROUND
4768    * Opcode range: 0x76
4769    * Stack:        Eint8 -->
4770    */
4771   static void
4772   Ins_SROUND( TT_ExecContext  exc,
4773               FT_Long*        args )
4774   {
4775     SetSuperRound( exc, 0x4000, args[0] );
4776 
4777     exc->GS.round_state = TT_Round_Super;
4778     exc->func_round     = (TT_Round_Func)Round_Super;
4779   }
4780 
4781 
4782   /**************************************************************************
4783    *
4784    * S45ROUND[]:   Super ROUND 45 degrees
4785    * Opcode range: 0x77
4786    * Stack:        uint32 -->
4787    */
4788   static void
4789   Ins_S45ROUND( TT_ExecContext  exc,
4790                 FT_Long*        args )
4791   {
4792     SetSuperRound( exc, 0x2D41, args[0] );
4793 
4794     exc->GS.round_state = TT_Round_Super_45;
4795     exc->func_round     = (TT_Round_Func)Round_Super_45;
4796   }
4797 
4798 
4799   /**************************************************************************
4800    *
4801    * GC[a]:        Get Coordinate projected onto
4802    * Opcode range: 0x46-0x47
4803    * Stack:        uint32 --> f26.6
4804    *
4805    * XXX: UNDOCUMENTED: Measures from the original glyph must be taken
4806    *      along the dual projection vector!
4807    */
4808   static void
4809   Ins_GC( TT_ExecContext  exc,
4810           FT_Long*        args )
4811   {
4812     FT_ULong    L;
4813     FT_F26Dot6  R;
4814 
4815 
4816     L = (FT_ULong)args[0];
4817 
4818     if ( BOUNDSL( L, exc->zp2.n_points ) )
4819     {
4820       if ( exc->pedantic_hinting )
4821         exc->error = FT_THROW( Invalid_Reference );
4822       R = 0;
4823     }
4824     else
4825     {
4826       if ( exc->opcode & 1 )
4827         R = FAST_DUALPROJ( &exc->zp2.org[L] );
4828       else
4829         R = FAST_PROJECT( &exc->zp2.cur[L] );
4830     }
4831 
4832     args[0] = R;
4833   }
4834 
4835 
4836   /**************************************************************************
4837    *
4838    * SCFS[]:       Set Coordinate From Stack
4839    * Opcode range: 0x48
4840    * Stack:        f26.6 uint32 -->
4841    *
4842    * Formula:
4843    *
4844    *   OA := OA + ( value - OA.p )/( f.p ) * f
4845    */
4846   static void
4847   Ins_SCFS( TT_ExecContext  exc,
4848             FT_Long*        args )
4849   {
4850     FT_Long    K;
4851     FT_UShort  L;
4852 
4853 
4854     L = (FT_UShort)args[0];
4855 
4856     if ( BOUNDS( L, exc->zp2.n_points ) )
4857     {
4858       if ( exc->pedantic_hinting )
4859         exc->error = FT_THROW( Invalid_Reference );
4860       return;
4861     }
4862 
4863     K = FAST_PROJECT( &exc->zp2.cur[L] );
4864 
4865     exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );
4866 
4867     /* UNDOCUMENTED!  The MS rasterizer does that with */
4868     /* twilight points (confirmed by Greg Hitchcock)   */
4869     if ( exc->GS.gep2 == 0 )
4870       exc->zp2.org[L] = exc->zp2.cur[L];
4871   }
4872 
4873 
4874   /**************************************************************************
4875    *
4876    * MD[a]:        Measure Distance
4877    * Opcode range: 0x49-0x4A
4878    * Stack:        uint32 uint32 --> f26.6
4879    *
4880    * XXX: UNDOCUMENTED: Measure taken in the original glyph must be along
4881    *                    the dual projection vector.
4882    *
4883    * XXX: UNDOCUMENTED: Flag attributes are inverted!
4884    *                      0 => measure distance in original outline
4885    *                      1 => measure distance in grid-fitted outline
4886    *
4887    * XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1!
4888    */
4889   static void
4890   Ins_MD( TT_ExecContext  exc,
4891           FT_Long*        args )
4892   {
4893     FT_UShort   K, L;
4894     FT_F26Dot6  D;
4895 
4896 
4897     K = (FT_UShort)args[1];
4898     L = (FT_UShort)args[0];
4899 
4900     if ( BOUNDS( L, exc->zp0.n_points ) ||
4901          BOUNDS( K, exc->zp1.n_points ) )
4902     {
4903       if ( exc->pedantic_hinting )
4904         exc->error = FT_THROW( Invalid_Reference );
4905       D = 0;
4906     }
4907     else
4908     {


4941             vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );
4942 
4943             D = FAST_DUALPROJ( &vec );
4944           }
4945         }
4946       }
4947     }
4948 
4949 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
4950     /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
4951     if ( SUBPIXEL_HINTING_INFINALITY &&
4952          exc->ignore_x_mode          &&
4953          FT_ABS( D ) == 64           )
4954       D += 1;
4955 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
4956 
4957     args[0] = D;
4958   }
4959 
4960 
4961   /**************************************************************************
4962    *
4963    * SDPvTL[a]:    Set Dual PVector to Line
4964    * Opcode range: 0x86-0x87
4965    * Stack:        uint32 uint32 -->
4966    */
4967   static void
4968   Ins_SDPVTL( TT_ExecContext  exc,
4969               FT_Long*        args )
4970   {
4971     FT_Long    A, B, C;
4972     FT_UShort  p1, p2;            /* was FT_Int in pas type ERROR */
4973 
4974     FT_Byte  opcode = exc->opcode;
4975 
4976 
4977     p1 = (FT_UShort)args[1];
4978     p2 = (FT_UShort)args[0];
4979 
4980     if ( BOUNDS( p2, exc->zp1.n_points ) ||
4981          BOUNDS( p1, exc->zp2.n_points ) )
4982     {
4983       if ( exc->pedantic_hinting )
4984         exc->error = FT_THROW( Invalid_Reference );
4985       return;
4986     }


5024 
5025       if ( A == 0 && B == 0 )
5026       {
5027         A      = 0x4000;
5028         opcode = 0;
5029       }
5030     }
5031 
5032     if ( ( opcode & 1 ) != 0 )
5033     {
5034       C = B;   /* counter clockwise rotation */
5035       B = A;
5036       A = NEG_LONG( C );
5037     }
5038 
5039     Normalize( A, B, &exc->GS.projVector );
5040     Compute_Funcs( exc );
5041   }
5042 
5043 
5044   /**************************************************************************
5045    *
5046    * SZP0[]:       Set Zone Pointer 0
5047    * Opcode range: 0x13
5048    * Stack:        uint32 -->
5049    */
5050   static void
5051   Ins_SZP0( TT_ExecContext  exc,
5052             FT_Long*        args )
5053   {
5054     switch ( (FT_Int)args[0] )
5055     {
5056     case 0:
5057       exc->zp0 = exc->twilight;
5058       break;
5059 
5060     case 1:
5061       exc->zp0 = exc->pts;
5062       break;
5063 
5064     default:
5065       if ( exc->pedantic_hinting )
5066         exc->error = FT_THROW( Invalid_Reference );
5067       return;
5068     }
5069 
5070     exc->GS.gep0 = (FT_UShort)args[0];
5071   }
5072 
5073 
5074   /**************************************************************************
5075    *
5076    * SZP1[]:       Set Zone Pointer 1
5077    * Opcode range: 0x14
5078    * Stack:        uint32 -->
5079    */
5080   static void
5081   Ins_SZP1( TT_ExecContext  exc,
5082             FT_Long*        args )
5083   {
5084     switch ( (FT_Int)args[0] )
5085     {
5086     case 0:
5087       exc->zp1 = exc->twilight;
5088       break;
5089 
5090     case 1:
5091       exc->zp1 = exc->pts;
5092       break;
5093 
5094     default:
5095       if ( exc->pedantic_hinting )
5096         exc->error = FT_THROW( Invalid_Reference );
5097       return;
5098     }
5099 
5100     exc->GS.gep1 = (FT_UShort)args[0];
5101   }
5102 
5103 
5104   /**************************************************************************
5105    *
5106    * SZP2[]:       Set Zone Pointer 2
5107    * Opcode range: 0x15
5108    * Stack:        uint32 -->
5109    */
5110   static void
5111   Ins_SZP2( TT_ExecContext  exc,
5112             FT_Long*        args )
5113   {
5114     switch ( (FT_Int)args[0] )
5115     {
5116     case 0:
5117       exc->zp2 = exc->twilight;
5118       break;
5119 
5120     case 1:
5121       exc->zp2 = exc->pts;
5122       break;
5123 
5124     default:
5125       if ( exc->pedantic_hinting )
5126         exc->error = FT_THROW( Invalid_Reference );
5127       return;
5128     }
5129 
5130     exc->GS.gep2 = (FT_UShort)args[0];
5131   }
5132 
5133 
5134   /**************************************************************************
5135    *
5136    * SZPS[]:       Set Zone PointerS
5137    * Opcode range: 0x16
5138    * Stack:        uint32 -->
5139    */
5140   static void
5141   Ins_SZPS( TT_ExecContext  exc,
5142             FT_Long*        args )
5143   {
5144     switch ( (FT_Int)args[0] )
5145     {
5146     case 0:
5147       exc->zp0 = exc->twilight;
5148       break;
5149 
5150     case 1:
5151       exc->zp0 = exc->pts;
5152       break;
5153 
5154     default:
5155       if ( exc->pedantic_hinting )
5156         exc->error = FT_THROW( Invalid_Reference );
5157       return;
5158     }
5159 
5160     exc->zp1 = exc->zp0;
5161     exc->zp2 = exc->zp0;
5162 
5163     exc->GS.gep0 = (FT_UShort)args[0];
5164     exc->GS.gep1 = (FT_UShort)args[0];
5165     exc->GS.gep2 = (FT_UShort)args[0];
5166   }
5167 
5168 
5169   /**************************************************************************
5170    *
5171    * INSTCTRL[]:   INSTruction ConTRoL
5172    * Opcode range: 0x8E
5173    * Stack:        int32 int32 -->
5174    */
5175   static void
5176   Ins_INSTCTRL( TT_ExecContext  exc,
5177                 FT_Long*        args )
5178   {
5179     FT_ULong  K, L, Kf;
5180 
5181 
5182     K = (FT_ULong)args[1];
5183     L = (FT_ULong)args[0];
5184 
5185     /* selector values cannot be `OR'ed;                 */
5186     /* they are indices starting with index 1, not flags */
5187     if ( K < 1 || K > 3 )
5188     {
5189       if ( exc->pedantic_hinting )
5190         exc->error = FT_THROW( Invalid_Reference );
5191       return;
5192     }
5193 
5194     /* convert index to flag value */


5211     if ( K == 3 )
5212     {
5213 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5214       /* INSTCTRL modifying flag 3 also has an effect */
5215       /* outside of the CVT program                   */
5216       if ( SUBPIXEL_HINTING_INFINALITY )
5217         exc->ignore_x_mode = FT_BOOL( L == 4 );
5218 #endif
5219 
5220 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5221       /* Native ClearType fonts sign a waiver that turns off all backward  */
5222       /* compatibility hacks and lets them program points to the grid like */
5223       /* it's 1996.  They might sign a waiver for just one glyph, though.  */
5224       if ( SUBPIXEL_HINTING_MINIMAL )
5225         exc->backward_compatibility = !FT_BOOL( L == 4 );
5226 #endif
5227     }
5228   }
5229 
5230 
5231   /**************************************************************************
5232    *
5233    * SCANCTRL[]:   SCAN ConTRoL
5234    * Opcode range: 0x85
5235    * Stack:        uint32? -->
5236    */
5237   static void
5238   Ins_SCANCTRL( TT_ExecContext  exc,
5239                 FT_Long*        args )
5240   {
5241     FT_Int  A;
5242 
5243 
5244     /* Get Threshold */
5245     A = (FT_Int)( args[0] & 0xFF );
5246 
5247     if ( A == 0xFF )
5248     {
5249       exc->GS.scan_control = TRUE;
5250       return;
5251     }
5252     else if ( A == 0 )
5253     {
5254       exc->GS.scan_control = FALSE;
5255       return;
5256     }


5258     if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )
5259       exc->GS.scan_control = TRUE;
5260 
5261     if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )
5262       exc->GS.scan_control = TRUE;
5263 
5264     if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )
5265       exc->GS.scan_control = TRUE;
5266 
5267     if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )
5268       exc->GS.scan_control = FALSE;
5269 
5270     if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )
5271       exc->GS.scan_control = FALSE;
5272 
5273     if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )
5274       exc->GS.scan_control = FALSE;
5275   }
5276 
5277 
5278   /**************************************************************************
5279    *
5280    * SCANTYPE[]:   SCAN TYPE
5281    * Opcode range: 0x8D
5282    * Stack:        uint16 -->
5283    */
5284   static void
5285   Ins_SCANTYPE( TT_ExecContext  exc,
5286                 FT_Long*        args )
5287   {
5288     if ( args[0] >= 0 )
5289       exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;
5290   }
5291 
5292 
5293   /**************************************************************************
5294    *
5295    * MANAGING OUTLINES
5296    *
5297    */
5298 
5299 
5300   /**************************************************************************
5301    *
5302    * FLIPPT[]:     FLIP PoinT
5303    * Opcode range: 0x80
5304    * Stack:        uint32... -->
5305    */
5306   static void
5307   Ins_FLIPPT( TT_ExecContext  exc )
5308   {
5309     FT_UShort  point;
5310 
5311 
5312 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5313     /* See `ttinterp.h' for details on backward compatibility mode. */
5314     if ( SUBPIXEL_HINTING_MINIMAL    &&
5315          exc->backward_compatibility &&
5316          exc->iupx_called            &&
5317          exc->iupy_called            )
5318       goto Fail;
5319 #endif
5320 
5321     if ( exc->top < exc->GS.loop )
5322     {
5323       if ( exc->pedantic_hinting )
5324         exc->error = FT_THROW( Too_Few_Arguments );
5325       goto Fail;


5334       if ( BOUNDS( point, exc->pts.n_points ) )
5335       {
5336         if ( exc->pedantic_hinting )
5337         {
5338           exc->error = FT_THROW( Invalid_Reference );
5339           return;
5340         }
5341       }
5342       else
5343         exc->pts.tags[point] ^= FT_CURVE_TAG_ON;
5344 
5345       exc->GS.loop--;
5346     }
5347 
5348   Fail:
5349     exc->GS.loop = 1;
5350     exc->new_top = exc->args;
5351   }
5352 
5353 
5354   /**************************************************************************
5355    *
5356    * FLIPRGON[]:   FLIP RanGe ON
5357    * Opcode range: 0x81
5358    * Stack:        uint32 uint32 -->
5359    */
5360   static void
5361   Ins_FLIPRGON( TT_ExecContext  exc,
5362                 FT_Long*        args )
5363   {
5364     FT_UShort  I, K, L;
5365 
5366 
5367 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5368     /* See `ttinterp.h' for details on backward compatibility mode. */
5369     if ( SUBPIXEL_HINTING_MINIMAL    &&
5370          exc->backward_compatibility &&
5371          exc->iupx_called            &&
5372          exc->iupy_called            )
5373       return;
5374 #endif
5375 
5376     K = (FT_UShort)args[1];
5377     L = (FT_UShort)args[0];
5378 
5379     if ( BOUNDS( K, exc->pts.n_points ) ||
5380          BOUNDS( L, exc->pts.n_points ) )
5381     {
5382       if ( exc->pedantic_hinting )
5383         exc->error = FT_THROW( Invalid_Reference );
5384       return;
5385     }
5386 
5387     for ( I = L; I <= K; I++ )
5388       exc->pts.tags[I] |= FT_CURVE_TAG_ON;
5389   }
5390 
5391 
5392   /**************************************************************************
5393    *
5394    * FLIPRGOFF:    FLIP RanGe OFF
5395    * Opcode range: 0x82
5396    * Stack:        uint32 uint32 -->
5397    */
5398   static void
5399   Ins_FLIPRGOFF( TT_ExecContext  exc,
5400                  FT_Long*        args )
5401   {
5402     FT_UShort  I, K, L;
5403 
5404 
5405 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5406     /* See `ttinterp.h' for details on backward compatibility mode. */
5407     if ( SUBPIXEL_HINTING_MINIMAL    &&
5408          exc->backward_compatibility &&
5409          exc->iupx_called            &&
5410          exc->iupy_called            )
5411       return;
5412 #endif
5413 
5414     K = (FT_UShort)args[1];
5415     L = (FT_UShort)args[0];
5416 
5417     if ( BOUNDS( K, exc->pts.n_points ) ||


5489       if ( touch )
5490         exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5491     }
5492 
5493     if ( exc->GS.freeVector.y != 0 )
5494     {
5495 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5496       if ( !( SUBPIXEL_HINTING_MINIMAL    &&
5497               exc->backward_compatibility &&
5498               exc->iupx_called            &&
5499               exc->iupy_called            ) )
5500 #endif
5501         exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );
5502 
5503       if ( touch )
5504         exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5505     }
5506   }
5507 
5508 
5509   /**************************************************************************
5510    *
5511    * SHP[a]:       SHift Point by the last point
5512    * Opcode range: 0x32-0x33
5513    * Stack:        uint32... -->
5514    */
5515   static void
5516   Ins_SHP( TT_ExecContext  exc )
5517   {
5518     TT_GlyphZoneRec  zp;
5519     FT_UShort        refp;
5520 
5521     FT_F26Dot6       dx, dy;
5522     FT_UShort        point;
5523 
5524 
5525     if ( exc->top < exc->GS.loop )
5526     {
5527       if ( exc->pedantic_hinting )
5528         exc->error = FT_THROW( Invalid_Reference );
5529       goto Fail;
5530     }
5531 
5532     if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5533       return;
5534 


5546         }
5547       }
5548       else
5549 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5550       /* doesn't follow Cleartype spec but produces better result */
5551       if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
5552         Move_Zp2_Point( exc, point, 0, dy, TRUE );
5553       else
5554 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5555         Move_Zp2_Point( exc, point, dx, dy, TRUE );
5556 
5557       exc->GS.loop--;
5558     }
5559 
5560   Fail:
5561     exc->GS.loop = 1;
5562     exc->new_top = exc->args;
5563   }
5564 
5565 
5566   /**************************************************************************
5567    *
5568    * SHC[a]:       SHift Contour
5569    * Opcode range: 0x34-35
5570    * Stack:        uint32 -->
5571    *
5572    * UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual)
5573    *               contour in the twilight zone, namely contour number
5574    *               zero which includes all points of it.
5575    */
5576   static void
5577   Ins_SHC( TT_ExecContext  exc,
5578            FT_Long*        args )
5579   {
5580     TT_GlyphZoneRec  zp;
5581     FT_UShort        refp;
5582     FT_F26Dot6       dx, dy;
5583 
5584     FT_Short         contour, bounds;
5585     FT_UShort        start, limit, i;
5586 
5587 
5588     contour = (FT_Short)args[0];
5589     bounds  = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
5590 
5591     if ( BOUNDS( contour, bounds ) )
5592     {
5593       if ( exc->pedantic_hinting )
5594         exc->error = FT_THROW( Invalid_Reference );
5595       return;


5602       start = 0;
5603     else
5604       start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
5605                            exc->zp2.first_point );
5606 
5607     /* we use the number of points if in the twilight zone */
5608     if ( exc->GS.gep2 == 0 )
5609       limit = exc->zp2.n_points;
5610     else
5611       limit = (FT_UShort)( exc->zp2.contours[contour] -
5612                            exc->zp2.first_point + 1 );
5613 
5614     for ( i = start; i < limit; i++ )
5615     {
5616       if ( zp.cur != exc->zp2.cur || refp != i )
5617         Move_Zp2_Point( exc, i, dx, dy, TRUE );
5618     }
5619   }
5620 
5621 
5622   /**************************************************************************
5623    *
5624    * SHZ[a]:       SHift Zone
5625    * Opcode range: 0x36-37
5626    * Stack:        uint32 -->
5627    */
5628   static void
5629   Ins_SHZ( TT_ExecContext  exc,
5630            FT_Long*        args )
5631   {
5632     TT_GlyphZoneRec  zp;
5633     FT_UShort        refp;
5634     FT_F26Dot6       dx,
5635                      dy;
5636 
5637     FT_UShort        limit, i;
5638 
5639 
5640     if ( BOUNDS( args[0], 2 ) )
5641     {
5642       if ( exc->pedantic_hinting )
5643         exc->error = FT_THROW( Invalid_Reference );
5644       return;
5645     }
5646 
5647     if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )


5650     /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.     */
5651     /*      Twilight zone has no real contours, so use `n_points'. */
5652     /*      Normal zone's `n_points' includes phantoms, so must    */
5653     /*      use end of last contour.                               */
5654     if ( exc->GS.gep2 == 0 )
5655       limit = (FT_UShort)exc->zp2.n_points;
5656     else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
5657       limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
5658     else
5659       limit = 0;
5660 
5661     /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5662     for ( i = 0; i < limit; i++ )
5663     {
5664       if ( zp.cur != exc->zp2.cur || refp != i )
5665         Move_Zp2_Point( exc, i, dx, dy, FALSE );
5666     }
5667   }
5668 
5669 
5670   /**************************************************************************
5671    *
5672    * SHPIX[]:      SHift points by a PIXel amount
5673    * Opcode range: 0x38
5674    * Stack:        f26.6 uint32... -->
5675    */
5676   static void
5677   Ins_SHPIX( TT_ExecContext  exc,
5678              FT_Long*        args )
5679   {
5680     FT_F26Dot6  dx, dy;
5681     FT_UShort   point;
5682 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5683     FT_Int      B1, B2;
5684 #endif
5685 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5686     FT_Bool     in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||
5687                                        exc->GS.gep1 == 0 ||
5688                                        exc->GS.gep2 == 0 );
5689 #endif
5690 
5691 
5692 
5693     if ( exc->top < exc->GS.loop + 1 )
5694     {
5695       if ( exc->pedantic_hinting )


5810                ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
5811                  ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )    ) ) )
5812           Move_Zp2_Point( exc, point, 0, dy, TRUE );
5813       }
5814       else
5815 #endif
5816         Move_Zp2_Point( exc, point, dx, dy, TRUE );
5817 
5818 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5819     Skip:
5820 #endif
5821       exc->GS.loop--;
5822     }
5823 
5824   Fail:
5825     exc->GS.loop = 1;
5826     exc->new_top = exc->args;
5827   }
5828 
5829 
5830   /**************************************************************************
5831    *
5832    * MSIRP[a]:     Move Stack Indirect Relative Position
5833    * Opcode range: 0x3A-0x3B
5834    * Stack:        f26.6 uint32 -->
5835    */
5836   static void
5837   Ins_MSIRP( TT_ExecContext  exc,
5838              FT_Long*        args )
5839   {
5840     FT_UShort   point = 0;
5841     FT_F26Dot6  distance;
5842 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5843     FT_F26Dot6  control_value_cutin = 0;
5844     FT_F26Dot6  delta;
5845 
5846 
5847     if ( SUBPIXEL_HINTING_INFINALITY )
5848     {
5849       control_value_cutin = exc->GS.control_value_cutin;
5850 
5851       if ( exc->ignore_x_mode                                 &&
5852            exc->GS.freeVector.x != 0                          &&
5853            !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
5854         control_value_cutin = 0;
5855     }


5885     if ( SUBPIXEL_HINTING_INFINALITY  &&
5886          exc->ignore_x_mode           &&
5887          exc->GS.freeVector.x != 0    &&
5888          delta >= control_value_cutin )
5889       distance = args[1];
5890 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5891 
5892     exc->func_move( exc,
5893                     &exc->zp1,
5894                     point,
5895                     SUB_LONG( args[1], distance ) );
5896 
5897     exc->GS.rp1 = exc->GS.rp0;
5898     exc->GS.rp2 = point;
5899 
5900     if ( ( exc->opcode & 1 ) != 0 )
5901       exc->GS.rp0 = point;
5902   }
5903 
5904 
5905   /**************************************************************************
5906    *
5907    * MDAP[a]:      Move Direct Absolute Point
5908    * Opcode range: 0x2E-0x2F
5909    * Stack:        uint32 -->
5910    */
5911   static void
5912   Ins_MDAP( TT_ExecContext  exc,
5913             FT_Long*        args )
5914   {
5915     FT_UShort   point;
5916     FT_F26Dot6  cur_dist;
5917     FT_F26Dot6  distance;
5918 
5919 
5920     point = (FT_UShort)args[0];
5921 
5922     if ( BOUNDS( point, exc->zp0.n_points ) )
5923     {
5924       if ( exc->pedantic_hinting )
5925         exc->error = FT_THROW( Invalid_Reference );
5926       return;
5927     }
5928 
5929     if ( ( exc->opcode & 1 ) != 0 )
5930     {


5939                                  exc->tt_metrics.compensations[0] ),
5940                      cur_dist );
5941       else
5942 #endif
5943         distance = SUB_LONG(
5944                      exc->func_round( exc,
5945                                       cur_dist,
5946                                       exc->tt_metrics.compensations[0] ),
5947                      cur_dist );
5948     }
5949     else
5950       distance = 0;
5951 
5952     exc->func_move( exc, &exc->zp0, point, distance );
5953 
5954     exc->GS.rp0 = point;
5955     exc->GS.rp1 = point;
5956   }
5957 
5958 
5959   /**************************************************************************
5960    *
5961    * MIAP[a]:      Move Indirect Absolute Point
5962    * Opcode range: 0x3E-0x3F
5963    * Stack:        uint32 uint32 -->
5964    */
5965   static void
5966   Ins_MIAP( TT_ExecContext  exc,
5967             FT_Long*        args )
5968   {
5969     FT_ULong    cvtEntry;
5970     FT_UShort   point;
5971     FT_F26Dot6  distance;
5972     FT_F26Dot6  org_dist;
5973     FT_F26Dot6  control_value_cutin;
5974 
5975 
5976     control_value_cutin = exc->GS.control_value_cutin;
5977     cvtEntry            = (FT_ULong)args[1];
5978     point               = (FT_UShort)args[0];
5979 
5980 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5981     if ( SUBPIXEL_HINTING_INFINALITY                        &&
5982          exc->ignore_x_mode                                 &&
5983          exc->GS.freeVector.x != 0                          &&
5984          exc->GS.freeVector.y == 0                          &&


6059            exc->ignore_x_mode          &&
6060            exc->GS.freeVector.x != 0   )
6061         distance = Round_None( exc,
6062                                distance,
6063                                exc->tt_metrics.compensations[0] );
6064       else
6065 #endif
6066         distance = exc->func_round( exc,
6067                                     distance,
6068                                     exc->tt_metrics.compensations[0] );
6069     }
6070 
6071     exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
6072 
6073   Fail:
6074     exc->GS.rp0 = point;
6075     exc->GS.rp1 = point;
6076   }
6077 
6078 
6079   /**************************************************************************
6080    *
6081    * MDRP[abcde]:  Move Direct Relative Point
6082    * Opcode range: 0xC0-0xDF
6083    * Stack:        uint32 -->
6084    */
6085   static void
6086   Ins_MDRP( TT_ExecContext  exc,
6087             FT_Long*        args )
6088   {
6089     FT_UShort   point = 0;
6090     FT_F26Dot6  org_dist, distance, minimum_distance;
6091 
6092 
6093     minimum_distance = exc->GS.minimum_distance;
6094 
6095 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6096     if ( SUBPIXEL_HINTING_INFINALITY                        &&
6097          exc->ignore_x_mode                                 &&
6098          exc->GS.freeVector.x != 0                          &&
6099          !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6100       minimum_distance = 0;
6101 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6102 
6103     point = (FT_UShort)args[0];
6104 


6203         if ( distance > NEG_LONG( minimum_distance ) )
6204           distance = NEG_LONG( minimum_distance );
6205       }
6206     }
6207 
6208     /* now move the point */
6209 
6210     org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
6211 
6212     exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );
6213 
6214   Fail:
6215     exc->GS.rp1 = exc->GS.rp0;
6216     exc->GS.rp2 = point;
6217 
6218     if ( ( exc->opcode & 16 ) != 0 )
6219       exc->GS.rp0 = point;
6220   }
6221 
6222 
6223   /**************************************************************************
6224    *
6225    * MIRP[abcde]:  Move Indirect Relative Point
6226    * Opcode range: 0xE0-0xFF
6227    * Stack:        int32? uint32 -->
6228    */
6229   static void
6230   Ins_MIRP( TT_ExecContext  exc,
6231             FT_Long*        args )
6232   {
6233     FT_UShort   point;
6234     FT_ULong    cvtEntry;
6235 
6236     FT_F26Dot6  cvt_dist,
6237                 distance,
6238                 cur_dist,
6239                 org_dist,
6240                 control_value_cutin,
6241                 minimum_distance;
6242 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6243     FT_Int      B1           = 0; /* pacify compiler */
6244     FT_Int      B2           = 0;
6245     FT_Bool     reverse_move = FALSE;
6246 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6247 
6248     FT_F26Dot6  delta;
6249 
6250 
6251     minimum_distance    = exc->GS.minimum_distance;
6252     control_value_cutin = exc->GS.control_value_cutin;
6253     point               = (FT_UShort)args[0];
6254     cvtEntry            = (FT_ULong)( ADD_LONG( args[1], 1 ) );
6255 
6256 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6257     if ( SUBPIXEL_HINTING_INFINALITY                        &&
6258          exc->ignore_x_mode                                 &&
6259          exc->GS.freeVector.x != 0                          &&
6260          !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6261       control_value_cutin = minimum_distance = 0;
6262 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6263 
6264     /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6265 
6266     if ( BOUNDS( point,       exc->zp1.n_points ) ||
6267          BOUNDSL( cvtEntry,   exc->cvtSize + 1 )  ||
6268          BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6269     {
6270       if ( exc->pedantic_hinting )
6271         exc->error = FT_THROW( Invalid_Reference );
6272       goto Fail;
6273     }
6274 
6275     if ( !cvtEntry )
6276       cvt_dist = 0;
6277     else
6278       cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );
6279 
6280     /* single width test */
6281 
6282     delta = SUB_LONG( cvt_dist, exc->GS.single_width_value );
6283     if ( delta < 0 )
6284       delta = NEG_LONG( delta );
6285 
6286     if ( delta < exc->GS.single_width_cutin )
6287     {
6288       if ( cvt_dist >= 0 )
6289         cvt_dist =  exc->GS.single_width_value;
6290       else
6291         cvt_dist = -exc->GS.single_width_value;
6292     }
6293 
6294     /* UNDOCUMENTED!  The MS rasterizer does that with */
6295     /* twilight points (confirmed by Greg Hitchcock)   */
6296     if ( exc->GS.gep1 == 0 )
6297     {
6298       exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x +
6299                               TT_MulFix14( cvt_dist,
6300                                            exc->GS.freeVector.x );
6301       exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y +
6302                               TT_MulFix14( cvt_dist,
6303                                            exc->GS.freeVector.y );
6304       exc->zp1.cur[point]   = exc->zp1.org[point];
6305     }
6306 
6307     org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );
6308     cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );
6309 
6310     /* auto-flip test */
6311 
6312     if ( exc->GS.auto_flip )
6313     {
6314       if ( ( org_dist ^ cvt_dist ) < 0 )
6315         cvt_dist = NEG_LONG( cvt_dist );
6316     }
6317 
6318 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6319     if ( SUBPIXEL_HINTING_INFINALITY                               &&
6320          exc->ignore_x_mode                                        &&
6321          exc->GS.freeVector.y != 0                                 &&
6322          ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6323     {
6324       if ( cur_dist < -64 )
6325         cvt_dist -= 16;
6326       else if ( cur_dist > 64 && cur_dist < 84 )
6327         cvt_dist += 32;
6328     }
6329 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6330 
6331     /* control value cut-in and round */
6332 
6333     if ( ( exc->opcode & 4 ) != 0 )
6334     {
6335       /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
6336       /*      refer to the same zone.                                  */
6337 
6338       if ( exc->GS.gep0 == exc->GS.gep1 )
6339       {



6340         /* XXX: According to Greg Hitchcock, the following wording is */
6341         /*      the right one:                                        */
6342         /*                                                            */
6343         /*        When the absolute difference between the value in   */
6344         /*        the table [CVT] and the measurement directly from   */
6345         /*        the outline is _greater_ than the cut_in value, the */
6346         /*        outline measurement is used.                        */
6347         /*                                                            */
6348         /*      This is from `instgly.doc'.  The description in       */
6349         /*      `ttinst2.doc', version 1.66, is thus incorrect since  */
6350         /*      it implies `>=' instead of `>'.                       */
6351 
6352         delta = SUB_LONG( cvt_dist, org_dist );
6353         if ( delta < 0 )
6354           delta = NEG_LONG( delta );
6355 
6356         if ( delta > control_value_cutin )
6357           cvt_dist = org_dist;
6358       }
6359 
6360       distance = exc->func_round(
6361                    exc,
6362                    cvt_dist,
6363                    exc->tt_metrics.compensations[exc->opcode & 3] );
6364     }
6365     else
6366     {
6367 
6368 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6369       /* do cvt cut-in always in MIRP for sph */
6370       if ( SUBPIXEL_HINTING_INFINALITY  &&
6371            exc->ignore_x_mode           &&
6372            exc->GS.gep0 == exc->GS.gep1 )
6373       {



6374         delta = SUB_LONG( cvt_dist, org_dist );
6375         if ( delta < 0 )
6376           delta = NEG_LONG( delta );
6377 
6378         if ( delta > control_value_cutin )
6379           cvt_dist = org_dist;
6380       }
6381 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6382 
6383       distance = Round_None(
6384                    exc,
6385                    cvt_dist,
6386                    exc->tt_metrics.compensations[exc->opcode & 3] );
6387     }
6388 
6389     /* minimum distance test */
6390 
6391     if ( ( exc->opcode & 8 ) != 0 )
6392     {
6393       if ( org_dist >= 0 )


6450 
6451       if ( reverse_move )
6452         exc->func_move( exc,
6453                         &exc->zp1,
6454                         point,
6455                         SUB_LONG( cur_dist, distance ) );
6456     }
6457 
6458 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6459 
6460   Fail:
6461     exc->GS.rp1 = exc->GS.rp0;
6462 
6463     if ( ( exc->opcode & 16 ) != 0 )
6464       exc->GS.rp0 = point;
6465 
6466     exc->GS.rp2 = point;
6467   }
6468 
6469 
6470   /**************************************************************************
6471    *
6472    * ALIGNRP[]:    ALIGN Relative Point
6473    * Opcode range: 0x3C
6474    * Stack:        uint32 uint32... -->
6475    */
6476   static void
6477   Ins_ALIGNRP( TT_ExecContext  exc )
6478   {
6479     FT_UShort   point;
6480     FT_F26Dot6  distance;
6481 
6482 
6483 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6484     if ( SUBPIXEL_HINTING_INFINALITY                               &&
6485          exc->ignore_x_mode                                        &&
6486          exc->iup_called                                           &&
6487          ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6488     {
6489       exc->error = FT_THROW( Invalid_Reference );
6490       goto Fail;
6491     }
6492 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6493 
6494     if ( exc->top < exc->GS.loop                  ||
6495          BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )


6513           return;
6514         }
6515       }
6516       else
6517       {
6518         distance = PROJECT( exc->zp1.cur + point,
6519                             exc->zp0.cur + exc->GS.rp0 );
6520 
6521         exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
6522       }
6523 
6524       exc->GS.loop--;
6525     }
6526 
6527   Fail:
6528     exc->GS.loop = 1;
6529     exc->new_top = exc->args;
6530   }
6531 
6532 
6533   /**************************************************************************
6534    *
6535    * ISECT[]:      moves point to InterSECTion
6536    * Opcode range: 0x0F
6537    * Stack:        5 * uint32 -->
6538    */
6539   static void
6540   Ins_ISECT( TT_ExecContext  exc,
6541              FT_Long*        args )
6542   {
6543     FT_UShort   point,
6544                 a0, a1,
6545                 b0, b1;
6546 
6547     FT_F26Dot6  discriminant, dotproduct;
6548 
6549     FT_F26Dot6  dx,  dy,
6550                 dax, day,
6551                 dbx, dby;
6552 
6553     FT_F26Dot6  val;
6554 
6555     FT_Vector   R;
6556 
6557 
6558     point = (FT_UShort)args[0];


6609       exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );
6610       exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );
6611     }
6612     else
6613     {
6614       /* else, take the middle of the middles of A and B */
6615 
6616       /* XXX: Block in backward_compatibility and/or post-IUP? */
6617       exc->zp2.cur[point].x =
6618         ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),
6619                   ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;
6620       exc->zp2.cur[point].y =
6621         ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),
6622                   ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;
6623     }
6624 
6625     exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6626   }
6627 
6628 
6629   /**************************************************************************
6630    *
6631    * ALIGNPTS[]:   ALIGN PoinTS
6632    * Opcode range: 0x27
6633    * Stack:        uint32 uint32 -->
6634    */
6635   static void
6636   Ins_ALIGNPTS( TT_ExecContext  exc,
6637                 FT_Long*        args )
6638   {
6639     FT_UShort   p1, p2;
6640     FT_F26Dot6  distance;
6641 
6642 
6643     p1 = (FT_UShort)args[0];
6644     p2 = (FT_UShort)args[1];
6645 
6646     if ( BOUNDS( p1, exc->zp1.n_points ) ||
6647          BOUNDS( p2, exc->zp0.n_points ) )
6648     {
6649       if ( exc->pedantic_hinting )
6650         exc->error = FT_THROW( Invalid_Reference );
6651       return;
6652     }
6653 
6654     distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;
6655 
6656     exc->func_move( exc, &exc->zp1, p1, distance );
6657     exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );
6658   }
6659 
6660 
6661   /**************************************************************************
6662    *
6663    * IP[]:         Interpolate Point
6664    * Opcode range: 0x39
6665    * Stack:        uint32... -->
6666    */
6667 
6668   /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6669 
6670   static void
6671   Ins_IP( TT_ExecContext  exc )
6672   {
6673     FT_F26Dot6  old_range, cur_range;
6674     FT_Vector*  orus_base;
6675     FT_Vector*  cur_base;
6676     FT_Int      twilight;
6677 
6678 
6679     if ( exc->top < exc->GS.loop )
6680     {
6681       if ( exc->pedantic_hinting )
6682         exc->error = FT_THROW( Invalid_Reference );
6683       goto Fail;
6684     }
6685 
6686     /*


6801           /*              new_dist = org_dist                .       */
6802 
6803           new_dist = org_dist;
6804         }
6805       }
6806       else
6807         new_dist = 0;
6808 
6809       exc->func_move( exc,
6810                       &exc->zp2,
6811                       (FT_UShort)point,
6812                       SUB_LONG( new_dist, cur_dist ) );
6813     }
6814 
6815   Fail:
6816     exc->GS.loop = 1;
6817     exc->new_top = exc->args;
6818   }
6819 
6820 
6821   /**************************************************************************
6822    *
6823    * UTP[a]:       UnTouch Point
6824    * Opcode range: 0x29
6825    * Stack:        uint32 -->
6826    */
6827   static void
6828   Ins_UTP( TT_ExecContext  exc,
6829            FT_Long*        args )
6830   {
6831     FT_UShort  point;
6832     FT_Byte    mask;
6833 
6834 
6835     point = (FT_UShort)args[0];
6836 
6837     if ( BOUNDS( point, exc->zp0.n_points ) )
6838     {
6839       if ( exc->pedantic_hinting )
6840         exc->error = FT_THROW( Invalid_Reference );
6841       return;
6842     }
6843 
6844     mask = 0xFF;
6845 
6846     if ( exc->GS.freeVector.x != 0 )


6970 
6971         else
6972         {
6973           if ( !scale_valid )
6974           {
6975             scale_valid = 1;
6976             scale       = FT_DivFix( SUB_LONG( cur2, cur1 ),
6977                                      SUB_LONG( orus2, orus1 ) );
6978           }
6979 
6980           x = ADD_LONG( cur1,
6981                         FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),
6982                                    scale ) );
6983         }
6984         worker->curs[i].x = x;
6985       }
6986     }
6987   }
6988 
6989 
6990   /**************************************************************************
6991    *
6992    * IUP[a]:       Interpolate Untouched Points
6993    * Opcode range: 0x30-0x31
6994    * Stack:        -->
6995    */
6996   static void
6997   Ins_IUP( TT_ExecContext  exc )
6998   {
6999     IUP_WorkerRec  V;
7000     FT_Byte        mask;
7001 
7002     FT_UInt   first_point;   /* first point of contour        */
7003     FT_UInt   end_point;     /* end point (last+1) of contour */
7004 
7005     FT_UInt   first_touched; /* first touched point in contour   */
7006     FT_UInt   cur_touched;   /* current touched point in contour */
7007 
7008     FT_UInt   point;         /* current point   */
7009     FT_Short  contour;       /* current contour */
7010 
7011 
7012 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7013     /* See `ttinterp.h' for details on backward compatibility mode.  */
7014     /* Allow IUP until it has been called on both axes.  Immediately */
7015     /* return on subsequent ones.                                    */


7098         {
7099           _iup_worker_interpolate( &V,
7100                                    (FT_UShort)( cur_touched + 1 ),
7101                                    end_point,
7102                                    cur_touched,
7103                                    first_touched );
7104 
7105           if ( first_touched > 0 )
7106             _iup_worker_interpolate( &V,
7107                                      first_point,
7108                                      first_touched - 1,
7109                                      cur_touched,
7110                                      first_touched );
7111         }
7112       }
7113       contour++;
7114     } while ( contour < exc->pts.n_contours );
7115   }
7116 
7117 
7118   /**************************************************************************
7119    *
7120    * DELTAPn[]:    DELTA exceptions P1, P2, P3
7121    * Opcode range: 0x5D,0x71,0x72
7122    * Stack:        uint32 (2 * uint32)... -->
7123    */
7124   static void
7125   Ins_DELTAP( TT_ExecContext  exc,
7126               FT_Long*        args )
7127   {
7128     FT_ULong   nump, k;
7129     FT_UShort  A;
7130     FT_ULong   C, P;
7131     FT_Long    B;
7132 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7133     FT_UShort  B1, B2;
7134 
7135 
7136     if ( SUBPIXEL_HINTING_INFINALITY                              &&
7137          exc->ignore_x_mode                                       &&
7138          exc->iup_called                                          &&
7139          ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7140       goto Fail;
7141 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7142 
7143     P    = (FT_ULong)exc->func_cur_ppem( exc );


7265                    ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
7266                      ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )        ) )
7267                 exc->func_move( exc, &exc->zp0, A, B );
7268             }
7269             else
7270 #endif
7271               exc->func_move( exc, &exc->zp0, A, B );
7272           }
7273         }
7274       }
7275       else
7276         if ( exc->pedantic_hinting )
7277           exc->error = FT_THROW( Invalid_Reference );
7278     }
7279 
7280   Fail:
7281     exc->new_top = exc->args;
7282   }
7283 
7284 
7285   /**************************************************************************
7286    *
7287    * DELTACn[]:    DELTA exceptions C1, C2, C3
7288    * Opcode range: 0x73,0x74,0x75
7289    * Stack:        uint32 (2 * uint32)... -->
7290    */
7291   static void
7292   Ins_DELTAC( TT_ExecContext  exc,
7293               FT_Long*        args )
7294   {
7295     FT_ULong  nump, k;
7296     FT_ULong  A, C, P;
7297     FT_Long   B;
7298 
7299 
7300     P    = (FT_ULong)exc->func_cur_ppem( exc );
7301     nump = (FT_ULong)args[0];
7302 
7303     for ( k = 1; k <= nump; k++ )
7304     {
7305       if ( exc->args < 2 )
7306       {
7307         if ( exc->pedantic_hinting )
7308           exc->error = FT_THROW( Too_Few_Arguments );
7309         exc->args = 0;
7310         goto Fail;


7343 
7344         C += exc->GS.delta_base;
7345 
7346         if ( P == C )
7347         {
7348           B = ( (FT_ULong)B & 0xF ) - 8;
7349           if ( B >= 0 )
7350             B++;
7351           B *= 1L << ( 6 - exc->GS.delta_shift );
7352 
7353           exc->func_move_cvt( exc, A, B );
7354         }
7355       }
7356     }
7357 
7358   Fail:
7359     exc->new_top = exc->args;
7360   }
7361 
7362 
7363   /**************************************************************************
7364    *
7365    * MISC. INSTRUCTIONS
7366    *
7367    */
7368 
7369 
7370   /**************************************************************************
7371    *
7372    * GETINFO[]:    GET INFOrmation
7373    * Opcode range: 0x88
7374    * Stack:        uint32 --> uint32
7375    *
7376    * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May
7377    *      2015) not documented in the OpenType specification.
7378    *
7379    *      Selector bit 11 is incorrectly described as bit 8, while the
7380    *      real meaning of bit 8 (vertical LCD subpixels) stays
7381    *      undocumented.  The same mistake can be found in Greg Hitchcock's
7382    *      whitepaper.
7383    */
7384   static void
7385   Ins_GETINFO( TT_ExecContext  exc,
7386                FT_Long*        args )
7387   {
7388     FT_Long    K;
7389     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( exc->face );
7390 
7391 
7392     K = 0;
7393 
7394 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7395     /*********************************
7396      * RASTERIZER VERSION
7397      * Selector Bit:  0
7398      * Return Bit(s): 0-7
7399      */
7400     if ( SUBPIXEL_HINTING_INFINALITY &&
7401          ( args[0] & 1 ) != 0        &&
7402          exc->subpixel_hinting       )
7403     {
7404       if ( exc->ignore_x_mode )
7405       {
7406         /* if in ClearType backward compatibility mode,         */
7407         /* we sometimes change the TrueType version dynamically */
7408         K = exc->rasterizer_version;
7409         FT_TRACE6(( "Setting rasterizer version %d\n",
7410                     exc->rasterizer_version ));
7411       }
7412       else
7413         K = TT_INTERPRETER_VERSION_38;
7414     }
7415     else
7416 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7417       if ( ( args[0] & 1 ) != 0 )
7418         K = driver->interpreter_version;
7419 
7420     /*********************************
7421      * GLYPH ROTATED
7422      * Selector Bit:  1
7423      * Return Bit(s): 8
7424      */
7425     if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )
7426       K |= 1 << 8;
7427 
7428     /*********************************
7429      * GLYPH STRETCHED
7430      * Selector Bit:  2
7431      * Return Bit(s): 9
7432      */
7433     if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )
7434       K |= 1 << 9;
7435 
7436 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7437     /*********************************
7438      * VARIATION GLYPH
7439      * Selector Bit:  3
7440      * Return Bit(s): 10
7441      *
7442      * XXX: UNDOCUMENTED!
7443      */
7444     if ( (args[0] & 8 ) != 0 && exc->face->blend )
7445       K |= 1 << 10;
7446 #endif
7447 
7448     /*********************************
7449      * BI-LEVEL HINTING AND
7450      * GRAYSCALE RENDERING
7451      * Selector Bit:  5
7452      * Return Bit(s): 12
7453      */
7454     if ( ( args[0] & 32 ) != 0 && exc->grayscale )
7455       K |= 1 << 12;
7456 
7457 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7458     /* Toggle the following flags only outside of monochrome mode.      */
7459     /* Otherwise, instructions may behave weirdly and rendering results */
7460     /* may differ between v35 and v40 mode, e.g., in `Times New Roman   */
7461     /* Bold Italic'. */
7462     if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
7463     {
7464       /*********************************
7465        * HINTING FOR SUBPIXEL
7466        * Selector Bit:  6
7467        * Return Bit(s): 13
7468        *
7469        * v40 does subpixel hinting by default.
7470        */
7471       if ( ( args[0] & 64 ) != 0 )
7472         K |= 1 << 13;
7473 
7474       /*********************************
7475        * VERTICAL LCD SUBPIXELS?
7476        * Selector Bit:  8
7477        * Return Bit(s): 15
7478        */
7479       if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
7480         K |= 1 << 15;
7481 
7482       /*********************************
7483        * SUBPIXEL POSITIONED?
7484        * Selector Bit:  10
7485        * Return Bit(s): 17
7486        *
7487        * XXX: FreeType supports it, dependent on what client does?
7488        */
7489       if ( ( args[0] & 1024 ) != 0 )
7490         K |= 1 << 17;
7491 
7492       /*********************************
7493        * SYMMETRICAL SMOOTHING
7494        * Selector Bit:  11
7495        * Return Bit(s): 18
7496        *
7497        * The only smoothing method FreeType supports unless someone sets
7498        * FT_LOAD_TARGET_MONO.
7499        */
7500       if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
7501         K |= 1 << 18;
7502 
7503       /*********************************
7504        * CLEARTYPE HINTING AND
7505        * GRAYSCALE RENDERING
7506        * Selector Bit:  12
7507        * Return Bit(s): 19
7508        *
7509        * Grayscale rendering is what FreeType does anyway unless someone
7510        * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V)
7511        */
7512       if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
7513         K |= 1 << 19;
7514     }
7515 #endif
7516 
7517 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7518 
7519     if ( SUBPIXEL_HINTING_INFINALITY                          &&
7520          exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7521     {
7522 
7523       if ( exc->rasterizer_version >= 37 )
7524       {
7525         /*********************************
7526          * HINTING FOR SUBPIXEL
7527          * Selector Bit:  6
7528          * Return Bit(s): 13
7529          */
7530         if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
7531           K |= 1 << 13;
7532 
7533         /*********************************
7534          * COMPATIBLE WIDTHS ENABLED
7535          * Selector Bit:  7
7536          * Return Bit(s): 14
7537          *
7538          * Functionality still needs to be added
7539          */
7540         if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
7541           K |= 1 << 14;
7542 
7543         /*********************************
7544          * VERTICAL LCD SUBPIXELS?
7545          * Selector Bit:  8
7546          * Return Bit(s): 15
7547          *
7548          * Functionality still needs to be added
7549          */
7550         if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
7551           K |= 1 << 15;
7552 
7553         /*********************************
7554          * HINTING FOR BGR?
7555          * Selector Bit:  9
7556          * Return Bit(s): 16
7557          *
7558          * Functionality still needs to be added
7559          */
7560         if ( ( args[0] & 512 ) != 0 && exc->bgr )
7561           K |= 1 << 16;
7562 
7563         if ( exc->rasterizer_version >= 38 )
7564         {
7565           /*********************************
7566            * SUBPIXEL POSITIONED?
7567            * Selector Bit:  10
7568            * Return Bit(s): 17
7569            *
7570            * Functionality still needs to be added
7571            */
7572           if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
7573             K |= 1 << 17;
7574 
7575           /*********************************
7576            * SYMMETRICAL SMOOTHING
7577            * Selector Bit:  11
7578            * Return Bit(s): 18
7579            *
7580            * Functionality still needs to be added
7581            */
7582           if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
7583             K |= 1 << 18;
7584 
7585           /*********************************
7586            * GRAY CLEARTYPE
7587            * Selector Bit:  12
7588            * Return Bit(s): 19
7589            *
7590            * Functionality still needs to be added
7591            */
7592           if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
7593             K |= 1 << 19;
7594         }
7595       }
7596     }
7597 
7598 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7599 
7600     args[0] = K;
7601   }
7602 
7603 
7604 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7605 
7606   /**************************************************************************
7607    *
7608    * GETVARIATION[]: get normalized variation (blend) coordinates
7609    * Opcode range: 0x91
7610    * Stack:        --> f2.14...
7611    *
7612    * XXX: UNDOCUMENTED!  There is no official documentation from Apple for
7613    *      this bytecode instruction.  Active only if a font has GX
7614    *      variation axes.
7615    */
7616   static void
7617   Ins_GETVARIATION( TT_ExecContext  exc,
7618                     FT_Long*        args )
7619   {
7620     FT_UInt    num_axes = exc->face->blend->num_axis;
7621     FT_Fixed*  coords   = exc->face->blend->normalizedcoords;
7622 
7623     FT_UInt  i;
7624 
7625 
7626     if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) )
7627     {
7628       exc->error = FT_THROW( Stack_Overflow );
7629       return;
7630     }
7631 
7632     if ( coords )
7633     {
7634       for ( i = 0; i < num_axes; i++ )
7635         args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
7636     }
7637     else
7638     {
7639       for ( i = 0; i < num_axes; i++ )
7640         args[i] = 0;
7641     }
7642   }
7643 
7644 
7645   /**************************************************************************
7646    *
7647    * GETDATA[]:    no idea what this is good for
7648    * Opcode range: 0x92
7649    * Stack:        --> 17
7650    *
7651    * XXX: UNDOCUMENTED!  There is no documentation from Apple for this
7652    *      very weird bytecode instruction.
7653    */
7654   static void
7655   Ins_GETDATA( FT_Long*  args )
7656   {
7657     args[0] = 17;
7658   }
7659 
7660 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
7661 
7662 
7663   static void
7664   Ins_UNKNOWN( TT_ExecContext  exc )
7665   {
7666     TT_DefRecord*  def   = exc->IDefs;
7667     TT_DefRecord*  limit = def + exc->numIDefs;
7668 
7669 
7670     for ( ; def < limit; def++ )
7671     {
7672       if ( (FT_Byte)def->opc == exc->opcode && def->active )
7673       {


7681         }
7682 
7683         call = exc->callStack + exc->callTop++;
7684 
7685         call->Caller_Range = exc->curRange;
7686         call->Caller_IP    = exc->IP + 1;
7687         call->Cur_Count    = 1;
7688         call->Def          = def;
7689 
7690         Ins_Goto_CodeRange( exc, def->range, def->start );
7691 
7692         exc->step_ins = FALSE;
7693         return;
7694       }
7695     }
7696 
7697     exc->error = FT_THROW( Invalid_Opcode );
7698   }
7699 
7700 
7701   /**************************************************************************
7702    *
7703    * RUN
7704    *
7705    * This function executes a run of opcodes.  It will exit in the
7706    * following cases:
7707    *
7708    * - Errors (in which case it returns FALSE).
7709    *
7710    * - Reaching the end of the main code range (returns TRUE).
7711    *   Reaching the end of a code range within a function call is an
7712    *   error.
7713    *
7714    * - After executing one single opcode, if the flag `Instruction_Trap'
7715    *   is set to TRUE (returns TRUE).
7716    *
7717    * On exit with TRUE, test IP < CodeSize to know whether it comes from
7718    * an instruction trap or a normal termination.
7719    *
7720    *
7721    * Note: The documented DEBUG opcode pops a value from the stack.  This
7722    *       behaviour is unsupported; here a DEBUG opcode is always an
7723    *       error.
7724    *
7725    *
7726    * THIS IS THE INTERPRETER'S MAIN LOOP.
7727    *
7728    */
7729 
7730 
7731   /* documentation is in ttinterp.h */
7732 
7733   FT_EXPORT_DEF( FT_Error )
7734   TT_RunIns( TT_ExecContext  exc )
7735   {
7736     FT_ULong   ins_counter = 0;  /* executed instructions counter */
7737     FT_ULong   num_twilight_points;
7738     FT_UShort  i;
7739 
7740 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7741     FT_Byte    opcode_pattern[1][2] = {
7742                   /* #8 TypeMan Talk Align */
7743                   {
7744                     0x06, /* SPVTL   */
7745                     0x7D, /* RDTG    */
7746                   },
7747                 };
7748     FT_UShort  opcode_patterns   = 1;


7850       exc->func_move_cvt  = Move_CVT;
7851     }
7852 
7853     Compute_Funcs( exc );
7854     Compute_Round( exc, (FT_Byte)exc->GS.round_state );
7855 
7856     do
7857     {
7858       exc->opcode = exc->code[exc->IP];
7859 
7860 #ifdef FT_DEBUG_LEVEL_TRACE
7861       {
7862         FT_Long  cnt = FT_MIN( 8, exc->top );
7863         FT_Long  n;
7864 
7865 
7866         /* if tracing level is 7, show current code position */
7867         /* and the first few stack elements also             */
7868         FT_TRACE6(( "  " ));
7869         FT_TRACE7(( "%06d ", exc->IP ));
7870         FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 ));
7871         FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'
7872                               ? 2
7873                               : 12 - ( *opcode_name[exc->opcode] - '0' ),
7874                               "#" ));
7875         for ( n = 1; n <= cnt; n++ )
7876           FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
7877         FT_TRACE6(( "\n" ));
7878       }
7879 #endif /* FT_DEBUG_LEVEL_TRACE */
7880 
7881       if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
7882       {
7883         if ( exc->IP + 1 >= exc->codeSize )
7884           goto LErrorCodeOverflow_;
7885 
7886         exc->length = 2 - exc->length * exc->code[exc->IP + 1];
7887       }
7888 
7889       if ( exc->IP + exc->length > exc->codeSize )
7890         goto LErrorCodeOverflow_;


< prev index next >