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