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