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