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