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