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