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