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