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