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