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