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