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