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