ttinterp.c revision ee451cb395940862dad63c85adfe8f2fd55e864c
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 "../../include/ft2build.h" 24#include "../../include/freetype/internal/ftdebug.h" 25#include "../../include/freetype/internal/ftcalc.h" 26#include "../../include/freetype/fttrigon.h" 27#include "../../include/freetype/ftsystem.h" 28#include "../../include/freetype/ftttdrv.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.zp2.cur == NULL) return; /* Security fix: Google Chris6 ufuzz109.pdf page #1 */ 5833 if ( CUR.GS.freeVector.x != 0 ) 5834 { 5835 CUR.zp2.cur[point].x += dx; 5836 if ( touch ) 5837 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; 5838 } 5839 5840 if ( CUR.GS.freeVector.y != 0 ) 5841 { 5842 CUR.zp2.cur[point].y += dy; 5843 if ( touch ) 5844 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; 5845 } 5846 } 5847 5848 5849 /*************************************************************************/ 5850 /* */ 5851 /* SHP[a]: SHift Point by the last point */ 5852 /* Opcode range: 0x32-0x33 */ 5853 /* Stack: uint32... --> */ 5854 /* */ 5855 static void 5856 Ins_SHP( INS_ARG ) 5857 { 5858 TT_GlyphZoneRec zp; 5859 FT_UShort refp; 5860 5861 FT_F26Dot6 dx, 5862 dy; 5863 FT_UShort point; 5864 5865 FT_UNUSED_ARG; 5866 5867 5868 if ( CUR.top < CUR.GS.loop ) 5869 { 5870 if ( CUR.pedantic_hinting ) 5871 CUR.error = FT_THROW( Invalid_Reference ); 5872 goto Fail; 5873 } 5874 5875 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 5876 return; 5877 5878 while ( CUR.GS.loop > 0 ) 5879 { 5880 CUR.args--; 5881 point = (FT_UShort)CUR.stack[CUR.args]; 5882 5883 if ( BOUNDS( point, CUR.zp2.n_points ) ) 5884 { 5885 if ( CUR.pedantic_hinting ) 5886 { 5887 CUR.error = FT_THROW( Invalid_Reference ); 5888 return; 5889 } 5890 } 5891 else 5892#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 5893 /* doesn't follow Cleartype spec but produces better result */ 5894 if ( SUBPIXEL_HINTING && 5895 CUR.ignore_x_mode ) 5896 MOVE_Zp2_Point( point, 0, dy, TRUE ); 5897 else 5898#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 5899 MOVE_Zp2_Point( point, dx, dy, TRUE ); 5900 5901 CUR.GS.loop--; 5902 } 5903 5904 Fail: 5905 CUR.GS.loop = 1; 5906 CUR.new_top = CUR.args; 5907 } 5908 5909 5910 /*************************************************************************/ 5911 /* */ 5912 /* SHC[a]: SHift Contour */ 5913 /* Opcode range: 0x34-35 */ 5914 /* Stack: uint32 --> */ 5915 /* */ 5916 /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */ 5917 /* contour in the twilight zone, namely contour number */ 5918 /* zero which includes all points of it. */ 5919 /* */ 5920 static void 5921 Ins_SHC( INS_ARG ) 5922 { 5923 TT_GlyphZoneRec zp; 5924 FT_UShort refp; 5925 FT_F26Dot6 dx, dy; 5926 5927 FT_Short contour, bounds; 5928 FT_UShort start, limit, i; 5929 5930 5931 contour = (FT_UShort)args[0]; 5932 bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours; 5933 5934 if ( BOUNDS( contour, bounds ) ) 5935 { 5936 if ( CUR.pedantic_hinting ) 5937 CUR.error = FT_THROW( Invalid_Reference ); 5938 return; 5939 } 5940 5941 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 5942 return; 5943 5944 if ( contour == 0 ) 5945 start = 0; 5946 else 5947 start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 - 5948 CUR.zp2.first_point ); 5949 5950 /* we use the number of points if in the twilight zone */ 5951 if ( CUR.GS.gep2 == 0 ) 5952 limit = CUR.zp2.n_points; 5953 else 5954 limit = (FT_UShort)( CUR.zp2.contours[contour] - 5955 CUR.zp2.first_point + 1 ); 5956 5957 for ( i = start; i < limit; i++ ) 5958 { 5959 if ( zp.cur != CUR.zp2.cur || refp != i ) 5960 MOVE_Zp2_Point( i, dx, dy, TRUE ); 5961 } 5962 } 5963 5964 5965 /*************************************************************************/ 5966 /* */ 5967 /* SHZ[a]: SHift Zone */ 5968 /* Opcode range: 0x36-37 */ 5969 /* Stack: uint32 --> */ 5970 /* */ 5971 static void 5972 Ins_SHZ( INS_ARG ) 5973 { 5974 TT_GlyphZoneRec zp; 5975 FT_UShort refp; 5976 FT_F26Dot6 dx, 5977 dy; 5978 5979 FT_UShort limit, i; 5980 5981 5982 if ( BOUNDS( args[0], 2 ) ) 5983 { 5984 if ( CUR.pedantic_hinting ) 5985 CUR.error = FT_THROW( Invalid_Reference ); 5986 return; 5987 } 5988 5989 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 5990 return; 5991 5992 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ 5993 /* Twilight zone has no real contours, so use `n_points'. */ 5994 /* Normal zone's `n_points' includes phantoms, so must */ 5995 /* use end of last contour. */ 5996 if ( CUR.GS.gep2 == 0 ) 5997 limit = (FT_UShort)CUR.zp2.n_points; 5998 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 ) { 5999 limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 ); 6000 if (limit >= CUR.zp2.n_points) /* XYQ 2010-10-01: security fix: validate last point index */ 6001 limit = CUR.zp2.n_points - 1; 6002 } 6003 else 6004 limit = 0; 6005 6006 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ 6007 for ( i = 0; i < limit; i++ ) 6008 { 6009 if ( zp.cur != CUR.zp2.cur || refp != i ) 6010 MOVE_Zp2_Point( i, dx, dy, FALSE ); 6011 } 6012 } 6013 6014 6015 /*************************************************************************/ 6016 /* */ 6017 /* SHPIX[]: SHift points by a PIXel amount */ 6018 /* Opcode range: 0x38 */ 6019 /* Stack: f26.6 uint32... --> */ 6020 /* */ 6021 static void 6022 Ins_SHPIX( INS_ARG ) 6023 { 6024 FT_F26Dot6 dx, dy; 6025 FT_UShort point; 6026#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6027 FT_Int B1, B2; 6028#endif 6029 6030 6031 if ( CUR.top < CUR.GS.loop + 1 ) 6032 { 6033 if ( CUR.pedantic_hinting ) 6034 CUR.error = FT_THROW( Invalid_Reference ); 6035 goto Fail; 6036 } 6037 6038#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING 6039 if ( CUR.face->unpatented_hinting ) 6040 { 6041 if ( CUR.GS.both_x_axis ) 6042 { 6043 dx = (FT_UInt32)args[0]; 6044 dy = 0; 6045 } 6046 else 6047 { 6048 dx = 0; 6049 dy = (FT_UInt32)args[0]; 6050 } 6051 } 6052 else 6053#endif 6054 { 6055 dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x ); 6056 dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y ); 6057 } 6058 6059 while ( CUR.GS.loop > 0 ) 6060 { 6061 CUR.args--; 6062 6063 point = (FT_UShort)CUR.stack[CUR.args]; 6064 6065 if ( BOUNDS( point, CUR.zp2.n_points ) ) 6066 { 6067 if ( CUR.pedantic_hinting ) 6068 { 6069 CUR.error = FT_THROW( Invalid_Reference ); 6070 return; 6071 } 6072 } 6073 else 6074#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6075 { 6076 /* If not using ignore_x_mode rendering, allow ZP2 move. */ 6077 /* If inline deltas aren't allowed, skip ZP2 move. */ 6078 /* If using ignore_x_mode rendering, allow ZP2 point move if: */ 6079 /* - freedom vector is y and sph_compatibility_mode is off */ 6080 /* - the glyph is composite and the move is in the Y direction */ 6081 /* - the glyph is specifically set to allow SHPIX moves */ 6082 /* - the move is on a previously Y-touched point */ 6083 6084 if ( SUBPIXEL_HINTING && 6085 CUR.ignore_x_mode ) 6086 { 6087 /* save point for later comparison */ 6088 if ( CUR.GS.freeVector.y != 0 ) 6089 B1 = CUR.zp2.cur[point].y; 6090 else 6091 B1 = CUR.zp2.cur[point].x; 6092 6093 if ( !CUR.face->sph_compatibility_mode && 6094 CUR.GS.freeVector.y != 0 ) 6095 { 6096 MOVE_Zp2_Point( point, dx, dy, TRUE ); 6097 6098 /* save new point */ 6099 if ( CUR.GS.freeVector.y != 0 ) 6100 { 6101 B2 = CUR.zp2.cur[point].y; 6102 6103 /* reverse any disallowed moves */ 6104 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && 6105 ( B1 & 63 ) != 0 && 6106 ( B2 & 63 ) != 0 && 6107 B1 != B2 ) 6108 MOVE_Zp2_Point( point, -dx, -dy, TRUE ); 6109 } 6110 } 6111 else if ( CUR.face->sph_compatibility_mode ) 6112 { 6113 if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) 6114 { 6115 dx = FT_PIX_ROUND( B1 + dx ) - B1; 6116 dy = FT_PIX_ROUND( B1 + dy ) - B1; 6117 } 6118 6119 /* skip post-iup deltas */ 6120 if ( CUR.iup_called && 6121 ( ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) || 6122 ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) ) 6123 goto Skip; 6124 6125 if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) && 6126 ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) || 6127 ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) || 6128 ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) ) 6129 MOVE_Zp2_Point( point, 0, dy, TRUE ); 6130 6131 /* save new point */ 6132 if ( CUR.GS.freeVector.y != 0 ) 6133 { 6134 B2 = CUR.zp2.cur[point].y; 6135 6136 /* reverse any disallowed moves */ 6137 if ( ( B1 & 63 ) == 0 && 6138 ( B2 & 63 ) != 0 && 6139 B1 != B2 ) 6140 MOVE_Zp2_Point( point, 0, -dy, TRUE ); 6141 } 6142 } 6143 else if ( CUR.sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL ) 6144 MOVE_Zp2_Point( point, dx, dy, TRUE ); 6145 } 6146 else 6147 MOVE_Zp2_Point( point, dx, dy, TRUE ); 6148 } 6149 6150 Skip: 6151 6152#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6153 6154 MOVE_Zp2_Point( point, dx, dy, TRUE ); 6155 6156#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6157 6158 CUR.GS.loop--; 6159 } 6160 6161 Fail: 6162 CUR.GS.loop = 1; 6163 CUR.new_top = CUR.args; 6164 } 6165 6166 6167 /*************************************************************************/ 6168 /* */ 6169 /* MSIRP[a]: Move Stack Indirect Relative Position */ 6170 /* Opcode range: 0x3A-0x3B */ 6171 /* Stack: f26.6 uint32 --> */ 6172 /* */ 6173 static void 6174 Ins_MSIRP( INS_ARG ) 6175 { 6176 FT_UShort point; 6177 FT_F26Dot6 distance; 6178 6179#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6180 FT_F26Dot6 control_value_cutin = 0; /* pacify compiler */ 6181 6182 6183 if ( SUBPIXEL_HINTING ) 6184 { 6185 control_value_cutin = CUR.GS.control_value_cutin; 6186 6187 if ( CUR.ignore_x_mode && 6188 CUR.GS.freeVector.x != 0 && 6189 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) 6190 control_value_cutin = 0; 6191 } 6192 6193#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6194 6195 point = (FT_UShort)args[0]; 6196 6197 if ( BOUNDS( point, CUR.zp1.n_points ) || 6198 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) 6199 { 6200 if ( CUR.pedantic_hinting ) 6201 CUR.error = FT_THROW( Invalid_Reference ); 6202 return; 6203 } 6204 6205 /* UNDOCUMENTED! The MS rasterizer does that with */ 6206 /* twilight points (confirmed by Greg Hitchcock) */ 6207 if ( CUR.GS.gep1 == 0 ) 6208 { 6209 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0]; 6210 CUR_Func_move_orig( &CUR.zp1, point, args[1] ); 6211 CUR.zp1.cur[point] = CUR.zp1.org[point]; 6212 } 6213 6214 distance = CUR_Func_project( CUR.zp1.cur + point, 6215 CUR.zp0.cur + CUR.GS.rp0 ); 6216 6217#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6218 /* subpixel hinting - make MSIRP respect CVT cut-in; */ 6219 if ( SUBPIXEL_HINTING && 6220 CUR.ignore_x_mode && 6221 CUR.GS.freeVector.x != 0 && 6222 FT_ABS( distance - args[1] ) >= control_value_cutin ) 6223 distance = args[1]; 6224#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6225 6226 CUR_Func_move( &CUR.zp1, point, args[1] - distance ); 6227 6228 CUR.GS.rp1 = CUR.GS.rp0; 6229 CUR.GS.rp2 = point; 6230 6231 if ( ( CUR.opcode & 1 ) != 0 ) 6232 CUR.GS.rp0 = point; 6233 } 6234 6235 6236 /*************************************************************************/ 6237 /* */ 6238 /* MDAP[a]: Move Direct Absolute Point */ 6239 /* Opcode range: 0x2E-0x2F */ 6240 /* Stack: uint32 --> */ 6241 /* */ 6242 static void 6243 Ins_MDAP( INS_ARG ) 6244 { 6245 FT_UShort point; 6246 FT_F26Dot6 cur_dist; 6247 FT_F26Dot6 distance; 6248 6249 6250 point = (FT_UShort)args[0]; 6251 6252 if ( BOUNDS( point, CUR.zp0.n_points ) ) 6253 { 6254 if ( CUR.pedantic_hinting ) 6255 CUR.error = FT_THROW( Invalid_Reference ); 6256 return; 6257 } 6258 6259 if ( ( CUR.opcode & 1 ) != 0 ) 6260 { 6261 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); 6262#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6263 if ( SUBPIXEL_HINTING && 6264 CUR.ignore_x_mode && 6265 CUR.GS.freeVector.x != 0 ) 6266 distance = ROUND_None( 6267 cur_dist, 6268 CUR.tt_metrics.compensations[0] ) - cur_dist; 6269 else 6270#endif 6271 distance = CUR_Func_round( 6272 cur_dist, 6273 CUR.tt_metrics.compensations[0] ) - cur_dist; 6274 } 6275 else 6276 distance = 0; 6277 6278 CUR_Func_move( &CUR.zp0, point, distance ); 6279 6280 CUR.GS.rp0 = point; 6281 CUR.GS.rp1 = point; 6282 } 6283 6284 6285 /*************************************************************************/ 6286 /* */ 6287 /* MIAP[a]: Move Indirect Absolute Point */ 6288 /* Opcode range: 0x3E-0x3F */ 6289 /* Stack: uint32 uint32 --> */ 6290 /* */ 6291 static void 6292 Ins_MIAP( INS_ARG ) 6293 { 6294 FT_ULong cvtEntry; 6295 FT_UShort point; 6296 FT_F26Dot6 distance; 6297 FT_F26Dot6 org_dist; 6298 FT_F26Dot6 control_value_cutin; 6299 6300 6301 control_value_cutin = CUR.GS.control_value_cutin; 6302 cvtEntry = (FT_ULong)args[1]; 6303 point = (FT_UShort)args[0]; 6304 6305#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6306 if ( SUBPIXEL_HINTING && 6307 CUR.ignore_x_mode && 6308 CUR.GS.freeVector.x != 0 && 6309 CUR.GS.freeVector.y == 0 && 6310 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) 6311 control_value_cutin = 0; 6312#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6313 6314 if ( BOUNDS( point, CUR.zp0.n_points ) || 6315 BOUNDSL( cvtEntry, CUR.cvtSize ) ) 6316 { 6317 if ( CUR.pedantic_hinting ) 6318 CUR.error = FT_THROW( Invalid_Reference ); 6319 goto Fail; 6320 } 6321 6322 /* UNDOCUMENTED! */ 6323 /* */ 6324 /* The behaviour of an MIAP instruction is quite different when used */ 6325 /* in the twilight zone. */ 6326 /* */ 6327 /* First, no control value cut-in test is performed as it would fail */ 6328 /* anyway. Second, the original point, i.e. (org_x,org_y) of */ 6329 /* zp0.point, is set to the absolute, unrounded distance found in the */ 6330 /* CVT. */ 6331 /* */ 6332 /* This is used in the CVT programs of the Microsoft fonts Arial, */ 6333 /* Times, etc., in order to re-adjust some key font heights. It */ 6334 /* allows the use of the IP instruction in the twilight zone, which */ 6335 /* otherwise would be invalid according to the specification. */ 6336 /* */ 6337 /* We implement it with a special sequence for the twilight zone. */ 6338 /* This is a bad hack, but it seems to work. */ 6339 /* */ 6340 /* Confirmed by Greg Hitchcock. */ 6341 6342 distance = CUR_Func_read_cvt( cvtEntry ); 6343 6344 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ 6345 { 6346#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6347 /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */ 6348 /* Determined via experimentation and may be incorrect... */ 6349 if ( !SUBPIXEL_HINTING || 6350 ( !CUR.ignore_x_mode || 6351 !CUR.face->sph_compatibility_mode ) ) 6352#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6353 CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, 6354 CUR.GS.freeVector.x ); 6355 CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance, 6356 CUR.GS.freeVector.y ), 6357 CUR.zp0.cur[point] = CUR.zp0.org[point]; 6358 } 6359#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6360 if ( SUBPIXEL_HINTING && 6361 CUR.ignore_x_mode && 6362 ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) && 6363 distance > 0 && 6364 CUR.GS.freeVector.y != 0 ) 6365 distance = 0; 6366#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6367 6368 org_dist = CUR_fast_project( &CUR.zp0.cur[point] ); 6369 6370 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ 6371 { 6372 if ( FT_ABS( distance - org_dist ) > control_value_cutin ) 6373 distance = org_dist; 6374 6375#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6376 if ( SUBPIXEL_HINTING && 6377 CUR.ignore_x_mode && 6378 CUR.GS.freeVector.x != 0 ) 6379 distance = ROUND_None( distance, 6380 CUR.tt_metrics.compensations[0] ); 6381 else 6382#endif 6383 distance = CUR_Func_round( distance, 6384 CUR.tt_metrics.compensations[0] ); 6385 } 6386 6387 CUR_Func_move( &CUR.zp0, point, distance - org_dist ); 6388 6389 Fail: 6390 CUR.GS.rp0 = point; 6391 CUR.GS.rp1 = point; 6392 } 6393 6394 6395 /*************************************************************************/ 6396 /* */ 6397 /* MDRP[abcde]: Move Direct Relative Point */ 6398 /* Opcode range: 0xC0-0xDF */ 6399 /* Stack: uint32 --> */ 6400 /* */ 6401 static void 6402 Ins_MDRP( INS_ARG ) 6403 { 6404 FT_UShort point; 6405 FT_F26Dot6 org_dist, distance, minimum_distance; 6406 6407 6408 minimum_distance = CUR.GS.minimum_distance; 6409 6410#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6411 if ( SUBPIXEL_HINTING && 6412 CUR.ignore_x_mode && 6413 CUR.GS.freeVector.x != 0 && 6414 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) 6415 minimum_distance = 0; 6416#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6417 6418 point = (FT_UShort)args[0]; 6419 6420 if ( BOUNDS( point, CUR.zp1.n_points ) || 6421 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) 6422 { 6423 if ( CUR.pedantic_hinting ) 6424 CUR.error = FT_THROW( Invalid_Reference ); 6425 goto Fail; 6426 } 6427 6428 /* XXX: Is there some undocumented feature while in the */ 6429 /* twilight zone? */ 6430 6431 /* XXX: UNDOCUMENTED: twilight zone special case */ 6432 6433 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 ) 6434 { 6435 FT_Vector* vec1 = &CUR.zp1.org[point]; 6436 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0]; 6437 6438 6439 org_dist = CUR_Func_dualproj( vec1, vec2 ); 6440 } 6441 else 6442 { 6443 FT_Vector* vec1 = &CUR.zp1.orus[point]; 6444 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0]; 6445 6446 6447 if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) 6448 { 6449 /* this should be faster */ 6450 org_dist = CUR_Func_dualproj( vec1, vec2 ); 6451 org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale ); 6452 } 6453 else 6454 { 6455 FT_Vector vec; 6456 6457 6458 vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale ); 6459 vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale ); 6460 6461 org_dist = CUR_fast_dualproj( &vec ); 6462 } 6463 } 6464 6465 /* single width cut-in test */ 6466 6467 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) < 6468 CUR.GS.single_width_cutin ) 6469 { 6470 if ( org_dist >= 0 ) 6471 org_dist = CUR.GS.single_width_value; 6472 else 6473 org_dist = -CUR.GS.single_width_value; 6474 } 6475 6476 /* round flag */ 6477 6478 if ( ( CUR.opcode & 4 ) != 0 ) 6479 { 6480#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6481 if ( SUBPIXEL_HINTING && 6482 CUR.ignore_x_mode && 6483 CUR.GS.freeVector.x != 0 ) 6484 distance = ROUND_None( 6485 org_dist, 6486 CUR.tt_metrics.compensations[CUR.opcode & 3] ); 6487 else 6488#endif 6489 distance = CUR_Func_round( 6490 org_dist, 6491 CUR.tt_metrics.compensations[CUR.opcode & 3] ); 6492 } 6493 else 6494 distance = ROUND_None( 6495 org_dist, 6496 CUR.tt_metrics.compensations[CUR.opcode & 3] ); 6497 6498 /* minimum distance flag */ 6499 6500 if ( ( CUR.opcode & 8 ) != 0 ) 6501 { 6502 if ( org_dist >= 0 ) 6503 { 6504 if ( distance < minimum_distance ) 6505 distance = minimum_distance; 6506 } 6507 else 6508 { 6509 if ( distance > -minimum_distance ) 6510 distance = -minimum_distance; 6511 } 6512 } 6513 6514 /* now move the point */ 6515 6516 org_dist = CUR_Func_project( CUR.zp1.cur + point, 6517 CUR.zp0.cur + CUR.GS.rp0 ); 6518 6519 CUR_Func_move( &CUR.zp1, point, distance - org_dist ); 6520 6521 Fail: 6522 CUR.GS.rp1 = CUR.GS.rp0; 6523 CUR.GS.rp2 = point; 6524 6525 if ( ( CUR.opcode & 16 ) != 0 ) 6526 CUR.GS.rp0 = point; 6527 } 6528 6529 6530 /*************************************************************************/ 6531 /* */ 6532 /* MIRP[abcde]: Move Indirect Relative Point */ 6533 /* Opcode range: 0xE0-0xFF */ 6534 /* Stack: int32? uint32 --> */ 6535 /* */ 6536 static void 6537 Ins_MIRP( INS_ARG ) 6538 { 6539 FT_UShort point; 6540 FT_ULong cvtEntry; 6541 6542 FT_F26Dot6 cvt_dist, 6543 distance, 6544 cur_dist, 6545 org_dist, 6546 control_value_cutin, 6547 minimum_distance; 6548#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6549 FT_Int B1 = 0; /* pacify compiler */ 6550 FT_Int B2 = 0; 6551 FT_Bool reverse_move = FALSE; 6552#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6553 6554 6555 minimum_distance = CUR.GS.minimum_distance; 6556 control_value_cutin = CUR.GS.control_value_cutin; 6557 point = (FT_UShort)args[0]; 6558 cvtEntry = (FT_ULong)( args[1] + 1 ); 6559 6560#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6561 if ( SUBPIXEL_HINTING && 6562 CUR.ignore_x_mode && 6563 CUR.GS.freeVector.x != 0 && 6564 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) 6565 control_value_cutin = minimum_distance = 0; 6566#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6567 6568 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ 6569 /* Security fix: Google 07_oobread4.pdf page #1, cvtEntry > CUR.cvtSize + 1 will cause array index oob. */ 6570 if ( BOUNDS( point, CUR.zp1.n_points ) || 6571 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) || 6572 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) 6573 { 6574 if ( CUR.pedantic_hinting ) 6575 CUR.error = FT_THROW( Invalid_Reference ); 6576 goto Fail; 6577 } 6578 6579 if ( !cvtEntry ) 6580 cvt_dist = 0; 6581 else 6582 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 ); 6583 6584 /* single width test */ 6585 6586 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) < 6587 CUR.GS.single_width_cutin ) 6588 { 6589 if ( cvt_dist >= 0 ) 6590 cvt_dist = CUR.GS.single_width_value; 6591 else 6592 cvt_dist = -CUR.GS.single_width_value; 6593 } 6594 6595 /* UNDOCUMENTED! The MS rasterizer does that with */ 6596 /* twilight points (confirmed by Greg Hitchcock) */ 6597 if ( CUR.GS.gep1 == 0 ) 6598 { 6599 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x + 6600 TT_MulFix14( (FT_UInt32)cvt_dist, 6601 CUR.GS.freeVector.x ); 6602 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + 6603 TT_MulFix14( (FT_UInt32)cvt_dist, 6604 CUR.GS.freeVector.y ); 6605 CUR.zp1.cur[point] = CUR.zp1.org[point]; 6606 } 6607 6608 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point], 6609 &CUR.zp0.org[CUR.GS.rp0] ); 6610 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point], 6611 &CUR.zp0.cur[CUR.GS.rp0] ); 6612 6613 /* auto-flip test */ 6614 6615 if ( CUR.GS.auto_flip ) 6616 { 6617 if ( ( org_dist ^ cvt_dist ) < 0 ) 6618 cvt_dist = -cvt_dist; 6619 } 6620 6621#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6622 if ( SUBPIXEL_HINTING && 6623 CUR.ignore_x_mode && 6624 CUR.GS.freeVector.y != 0 && 6625 ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) ) 6626 { 6627 if ( cur_dist < -64 ) 6628 cvt_dist -= 16; 6629 else if ( cur_dist > 64 && cur_dist < 84 ) 6630 cvt_dist += 32; 6631 } 6632#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6633 6634 /* control value cut-in and round */ 6635 6636 if ( ( CUR.opcode & 4 ) != 0 ) 6637 { 6638 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ 6639 /* refer to the same zone. */ 6640 6641 if ( CUR.GS.gep0 == CUR.GS.gep1 ) 6642 { 6643 /* XXX: According to Greg Hitchcock, the following wording is */ 6644 /* the right one: */ 6645 /* */ 6646 /* When the absolute difference between the value in */ 6647 /* the table [CVT] and the measurement directly from */ 6648 /* the outline is _greater_ than the cut_in value, the */ 6649 /* outline measurement is used. */ 6650 /* */ 6651 /* This is from `instgly.doc'. The description in */ 6652 /* `ttinst2.doc', version 1.66, is thus incorrect since */ 6653 /* it implies `>=' instead of `>'. */ 6654 6655 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) 6656 cvt_dist = org_dist; 6657 } 6658 6659 distance = CUR_Func_round( 6660 cvt_dist, 6661 CUR.tt_metrics.compensations[CUR.opcode & 3] ); 6662 } 6663 else 6664 { 6665 6666#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6667 /* do cvt cut-in always in MIRP for sph */ 6668 if ( SUBPIXEL_HINTING && 6669 CUR.ignore_x_mode && 6670 CUR.GS.gep0 == CUR.GS.gep1 ) 6671 { 6672 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) 6673 cvt_dist = org_dist; 6674 } 6675#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6676 6677 distance = ROUND_None( 6678 cvt_dist, 6679 CUR.tt_metrics.compensations[CUR.opcode & 3] ); 6680 } 6681 6682 /* minimum distance test */ 6683 6684 if ( ( CUR.opcode & 8 ) != 0 ) 6685 { 6686 if ( org_dist >= 0 ) 6687 { 6688 if ( distance < minimum_distance ) 6689 distance = minimum_distance; 6690 } 6691 else 6692 { 6693 if ( distance > -minimum_distance ) 6694 distance = -minimum_distance; 6695 } 6696 } 6697 6698#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6699 if ( SUBPIXEL_HINTING ) 6700 { 6701 B1 = CUR.zp1.cur[point].y; 6702 6703 /* Round moves if necessary */ 6704 if ( CUR.ignore_x_mode && 6705 CUR.GS.freeVector.y != 0 && 6706 ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) ) 6707 distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist; 6708 6709 if ( CUR.ignore_x_mode && 6710 CUR.GS.freeVector.y != 0 && 6711 ( CUR.opcode & 16 ) == 0 && 6712 ( CUR.opcode & 8 ) == 0 && 6713 ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) ) 6714 distance += 64; 6715 } 6716#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6717 6718 CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); 6719 6720#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6721 if ( SUBPIXEL_HINTING ) 6722 { 6723 B2 = CUR.zp1.cur[point].y; 6724 6725 /* Reverse move if necessary */ 6726 if ( CUR.ignore_x_mode ) 6727 { 6728 if ( CUR.face->sph_compatibility_mode && 6729 CUR.GS.freeVector.y != 0 && 6730 ( B1 & 63 ) == 0 && 6731 ( B2 & 63 ) != 0 ) 6732 reverse_move = TRUE; 6733 6734 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && 6735 CUR.GS.freeVector.y != 0 && 6736 ( B2 & 63 ) != 0 && 6737 ( B1 & 63 ) != 0 ) 6738 reverse_move = TRUE; 6739 } 6740 6741 if ( reverse_move ) 6742 CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) ); 6743 } 6744 6745#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6746 6747 Fail: 6748 CUR.GS.rp1 = CUR.GS.rp0; 6749 6750 if ( ( CUR.opcode & 16 ) != 0 ) 6751 CUR.GS.rp0 = point; 6752 6753 CUR.GS.rp2 = point; 6754 } 6755 6756 6757 /*************************************************************************/ 6758 /* */ 6759 /* ALIGNRP[]: ALIGN Relative Point */ 6760 /* Opcode range: 0x3C */ 6761 /* Stack: uint32 uint32... --> */ 6762 /* */ 6763 static void 6764 Ins_ALIGNRP( INS_ARG ) 6765 { 6766 FT_UShort point; 6767 FT_F26Dot6 distance; 6768 6769 FT_UNUSED_ARG; 6770 6771 6772#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 6773 if ( SUBPIXEL_HINTING && 6774 CUR.ignore_x_mode && 6775 CUR.iup_called && 6776 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) ) 6777 { 6778 CUR.error = FT_THROW( Invalid_Reference ); 6779 goto Fail; 6780 } 6781#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 6782 6783 if ( CUR.top < CUR.GS.loop || 6784 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) 6785 { 6786 if ( CUR.pedantic_hinting ) 6787 CUR.error = FT_THROW( Invalid_Reference ); 6788 goto Fail; 6789 } 6790 6791 while ( CUR.GS.loop > 0 ) 6792 { 6793 CUR.args--; 6794 6795 point = (FT_UShort)CUR.stack[CUR.args]; 6796 6797 if ( BOUNDS( point, CUR.zp1.n_points ) ) 6798 { 6799 if ( CUR.pedantic_hinting ) 6800 { 6801 CUR.error = FT_THROW( Invalid_Reference ); 6802 return; 6803 } 6804 } 6805 else 6806 { 6807 distance = CUR_Func_project( CUR.zp1.cur + point, 6808 CUR.zp0.cur + CUR.GS.rp0 ); 6809 6810 CUR_Func_move( &CUR.zp1, point, -distance ); 6811 } 6812 6813 CUR.GS.loop--; 6814 } 6815 6816 Fail: 6817 CUR.GS.loop = 1; 6818 CUR.new_top = CUR.args; 6819 } 6820 6821 6822 /*************************************************************************/ 6823 /* */ 6824 /* ISECT[]: moves point to InterSECTion */ 6825 /* Opcode range: 0x0F */ 6826 /* Stack: 5 * uint32 --> */ 6827 /* */ 6828 static void 6829 Ins_ISECT( INS_ARG ) 6830 { 6831 FT_UShort point, 6832 a0, a1, 6833 b0, b1; 6834 6835 FT_F26Dot6 discriminant, dotproduct; 6836 6837 FT_F26Dot6 dx, dy, 6838 dax, day, 6839 dbx, dby; 6840 6841 FT_F26Dot6 val; 6842 6843 FT_Vector R; 6844 6845 6846 point = (FT_UShort)args[0]; 6847 6848 a0 = (FT_UShort)args[1]; 6849 a1 = (FT_UShort)args[2]; 6850 b0 = (FT_UShort)args[3]; 6851 b1 = (FT_UShort)args[4]; 6852 6853 if ( BOUNDS( b0, CUR.zp0.n_points ) || 6854 BOUNDS( b1, CUR.zp0.n_points ) || 6855 BOUNDS( a0, CUR.zp1.n_points ) || 6856 BOUNDS( a1, CUR.zp1.n_points ) || 6857 BOUNDS( point, CUR.zp2.n_points ) ) 6858 { 6859 if ( CUR.pedantic_hinting ) 6860 CUR.error = FT_THROW( Invalid_Reference ); 6861 return; 6862 } 6863 6864 /* Cramer's rule */ 6865 6866 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x; 6867 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y; 6868 6869 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x; 6870 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y; 6871 6872 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x; 6873 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y; 6874 6875 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; 6876 6877 discriminant = FT_MulDiv( dax, -dby, 0x40 ) + 6878 FT_MulDiv( day, dbx, 0x40 ); 6879 dotproduct = FT_MulDiv( dax, dbx, 0x40 ) + 6880 FT_MulDiv( day, dby, 0x40 ); 6881 6882 /* The discriminant above is actually a cross product of vectors */ 6883 /* da and db. Together with the dot product, they can be used as */ 6884 /* surrogates for sine and cosine of the angle between the vectors. */ 6885 /* Indeed, */ 6886 /* dotproduct = |da||db|cos(angle) */ 6887 /* discriminant = |da||db|sin(angle) . */ 6888 /* We use these equations to reject grazing intersections by */ 6889 /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */ 6890 if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) ) 6891 { 6892 val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 ); 6893 6894 R.x = FT_MulDiv( val, dax, discriminant ); 6895 R.y = FT_MulDiv( val, day, discriminant ); 6896 6897 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x; 6898 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y; 6899 } 6900 else 6901 { 6902 /* else, take the middle of the middles of A and B */ 6903 6904 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x + 6905 CUR.zp1.cur[a1].x + 6906 CUR.zp0.cur[b0].x + 6907 CUR.zp0.cur[b1].x ) / 4; 6908 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y + 6909 CUR.zp1.cur[a1].y + 6910 CUR.zp0.cur[b0].y + 6911 CUR.zp0.cur[b1].y ) / 4; 6912 } 6913 } 6914 6915 6916 /*************************************************************************/ 6917 /* */ 6918 /* ALIGNPTS[]: ALIGN PoinTS */ 6919 /* Opcode range: 0x27 */ 6920 /* Stack: uint32 uint32 --> */ 6921 /* */ 6922 static void 6923 Ins_ALIGNPTS( INS_ARG ) 6924 { 6925 FT_UShort p1, p2; 6926 FT_F26Dot6 distance; 6927 6928 6929 p1 = (FT_UShort)args[0]; 6930 p2 = (FT_UShort)args[1]; 6931 6932 if ( BOUNDS( p1, CUR.zp1.n_points ) || 6933 BOUNDS( p2, CUR.zp0.n_points ) ) 6934 { 6935 if ( CUR.pedantic_hinting ) 6936 CUR.error = FT_THROW( Invalid_Reference ); 6937 return; 6938 } 6939 6940 distance = CUR_Func_project( CUR.zp0.cur + p2, 6941 CUR.zp1.cur + p1 ) / 2; 6942 6943 CUR_Func_move( &CUR.zp1, p1, distance ); 6944 CUR_Func_move( &CUR.zp0, p2, -distance ); 6945 } 6946 6947 6948 /*************************************************************************/ 6949 /* */ 6950 /* IP[]: Interpolate Point */ 6951 /* Opcode range: 0x39 */ 6952 /* Stack: uint32... --> */ 6953 /* */ 6954 6955 /* SOMETIMES, DUMBER CODE IS BETTER CODE */ 6956 6957 static void 6958 Ins_IP( INS_ARG ) 6959 { 6960 FT_F26Dot6 old_range, cur_range; 6961 FT_Vector* orus_base; 6962 FT_Vector* cur_base; 6963 FT_Int twilight; 6964 6965 FT_UNUSED_ARG; 6966 6967 6968 if ( CUR.top < CUR.GS.loop ) 6969 { 6970 if ( CUR.pedantic_hinting ) 6971 CUR.error = FT_THROW( Invalid_Reference ); 6972 goto Fail; 6973 } 6974 6975 /* 6976 * We need to deal in a special way with the twilight zone. 6977 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0), 6978 * for every n. 6979 */ 6980 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0; 6981 6982 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ) 6983 { 6984 if ( CUR.pedantic_hinting ) 6985 CUR.error = FT_THROW( Invalid_Reference ); 6986 goto Fail; 6987 } 6988 6989 if ( twilight ) 6990 orus_base = &CUR.zp0.org[CUR.GS.rp1]; 6991 else 6992 orus_base = &CUR.zp0.orus[CUR.GS.rp1]; 6993 6994 cur_base = &CUR.zp0.cur[CUR.GS.rp1]; 6995 6996 /* XXX: There are some glyphs in some braindead but popular */ 6997 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ 6998 /* calling IP[] with bad values of rp[12]. */ 6999 /* Do something sane when this odd thing happens. */ 7000 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) || 7001 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) ) 7002 { 7003 old_range = 0; 7004 cur_range = 0; 7005 } 7006 else 7007 { 7008 if ( twilight ) 7009 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2], 7010 orus_base ); 7011 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) 7012 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2], 7013 orus_base ); 7014 else 7015 { 7016 FT_Vector vec; 7017 7018 7019 vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x, 7020 CUR.metrics.x_scale ); 7021 vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y, 7022 CUR.metrics.y_scale ); 7023 7024 old_range = CUR_fast_dualproj( &vec ); 7025 } 7026 7027 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base ); 7028 } 7029 7030 for ( ; CUR.GS.loop > 0; --CUR.GS.loop ) 7031 { 7032 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args]; 7033 FT_F26Dot6 org_dist, cur_dist, new_dist; 7034 7035 7036 /* check point bounds */ 7037 if ( BOUNDS( point, CUR.zp2.n_points ) ) 7038 { 7039 if ( CUR.pedantic_hinting ) 7040 { 7041 CUR.error = FT_THROW( Invalid_Reference ); 7042 return; 7043 } 7044 continue; 7045 } 7046 7047 if ( twilight ) 7048 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base ); 7049 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) 7050 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base ); 7051 else 7052 { 7053 FT_Vector vec; 7054 7055 7056 vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x, 7057 CUR.metrics.x_scale ); 7058 vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y, 7059 CUR.metrics.y_scale ); 7060 7061 org_dist = CUR_fast_dualproj( &vec ); 7062 } 7063 7064 cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base ); 7065 7066 if ( org_dist ) 7067 { 7068 if ( old_range ) 7069 new_dist = FT_MulDiv( org_dist, cur_range, old_range ); 7070 else 7071 { 7072 /* This is the same as what MS does for the invalid case: */ 7073 /* */ 7074 /* delta = (Original_Pt - Original_RP1) - */ 7075 /* (Current_Pt - Current_RP1) */ 7076 /* */ 7077 /* In FreeType speak: */ 7078 /* */ 7079 /* new_dist = cur_dist - */ 7080 /* org_dist - cur_dist; */ 7081 7082 new_dist = -org_dist; 7083 } 7084 } 7085 else 7086 new_dist = 0; 7087 7088 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist ); 7089 } 7090 7091 Fail: 7092 CUR.GS.loop = 1; 7093 CUR.new_top = CUR.args; 7094 } 7095 7096 7097 /*************************************************************************/ 7098 /* */ 7099 /* UTP[a]: UnTouch Point */ 7100 /* Opcode range: 0x29 */ 7101 /* Stack: uint32 --> */ 7102 /* */ 7103 static void 7104 Ins_UTP( INS_ARG ) 7105 { 7106 FT_UShort point; 7107 FT_Byte mask; 7108 7109 7110 point = (FT_UShort)args[0]; 7111 7112 if ( BOUNDS( point, CUR.zp0.n_points ) ) 7113 { 7114 if ( CUR.pedantic_hinting ) 7115 CUR.error = FT_THROW( Invalid_Reference ); 7116 return; 7117 } 7118 7119 mask = 0xFF; 7120 7121 if ( CUR.GS.freeVector.x != 0 ) 7122 mask &= ~FT_CURVE_TAG_TOUCH_X; 7123 7124 if ( CUR.GS.freeVector.y != 0 ) 7125 mask &= ~FT_CURVE_TAG_TOUCH_Y; 7126 7127 CUR.zp0.tags[point] &= mask; 7128 } 7129 7130 7131 /* Local variables for Ins_IUP: */ 7132 typedef struct IUP_WorkerRec_ 7133 { 7134 FT_Vector* orgs; /* original and current coordinate */ 7135 FT_Vector* curs; /* arrays */ 7136 FT_Vector* orus; 7137 FT_UInt max_points; 7138 7139 } IUP_WorkerRec, *IUP_Worker; 7140 7141 7142 static void 7143 _iup_worker_shift( IUP_Worker worker, 7144 FT_UInt p1, 7145 FT_UInt p2, 7146 FT_UInt p ) 7147 { 7148 FT_UInt i; 7149 FT_F26Dot6 dx; 7150 7151 7152 dx = worker->curs[p].x - worker->orgs[p].x; 7153 if ( dx != 0 ) 7154 { 7155 for ( i = p1; i < p; i++ ) 7156 worker->curs[i].x += dx; 7157 7158 for ( i = p + 1; i <= p2; i++ ) 7159 worker->curs[i].x += dx; 7160 } 7161 } 7162 7163 7164 static void 7165 _iup_worker_interpolate( IUP_Worker worker, 7166 FT_UInt p1, 7167 FT_UInt p2, 7168 FT_UInt ref1, 7169 FT_UInt ref2 ) 7170 { 7171 FT_UInt i; 7172 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2; 7173 7174 7175 if ( p1 > p2 ) 7176 return; 7177 7178 if ( BOUNDS( ref1, worker->max_points ) || 7179 BOUNDS( ref2, worker->max_points ) ) 7180 return; 7181 7182 orus1 = worker->orus[ref1].x; 7183 orus2 = worker->orus[ref2].x; 7184 7185 if ( orus1 > orus2 ) 7186 { 7187 FT_F26Dot6 tmp_o; 7188 FT_UInt tmp_r; 7189 7190 7191 tmp_o = orus1; 7192 orus1 = orus2; 7193 orus2 = tmp_o; 7194 7195 tmp_r = ref1; 7196 ref1 = ref2; 7197 ref2 = tmp_r; 7198 } 7199 7200 org1 = worker->orgs[ref1].x; 7201 org2 = worker->orgs[ref2].x; 7202 delta1 = worker->curs[ref1].x - org1; 7203 delta2 = worker->curs[ref2].x - org2; 7204 7205 if ( orus1 == orus2 ) 7206 { 7207 /* simple shift of untouched points */ 7208 for ( i = p1; i <= p2; i++ ) 7209 { 7210 FT_F26Dot6 x = worker->orgs[i].x; 7211 7212 7213 if ( x <= org1 ) 7214 x += delta1; 7215 else 7216 x += delta2; 7217 7218 worker->curs[i].x = x; 7219 } 7220 } 7221 else 7222 { 7223 FT_Fixed scale = 0; 7224 FT_Bool scale_valid = 0; 7225 7226 7227 /* interpolation */ 7228 for ( i = p1; i <= p2; i++ ) 7229 { 7230 FT_F26Dot6 x = worker->orgs[i].x; 7231 7232 7233 if ( x <= org1 ) 7234 x += delta1; 7235 7236 else if ( x >= org2 ) 7237 x += delta2; 7238 7239 else 7240 { 7241 if ( !scale_valid ) 7242 { 7243 scale_valid = 1; 7244 scale = FT_DivFix( org2 + delta2 - ( org1 + delta1 ), 7245 orus2 - orus1 ); 7246 } 7247 7248 x = ( org1 + delta1 ) + 7249 FT_MulFix( worker->orus[i].x - orus1, scale ); 7250 } 7251 worker->curs[i].x = x; 7252 } 7253 } 7254 } 7255 7256 7257 /*************************************************************************/ 7258 /* */ 7259 /* IUP[a]: Interpolate Untouched Points */ 7260 /* Opcode range: 0x30-0x31 */ 7261 /* Stack: --> */ 7262 /* */ 7263 static void 7264 Ins_IUP( INS_ARG ) 7265 { 7266 IUP_WorkerRec V; 7267 FT_Byte mask; 7268 7269 FT_UInt first_point; /* first point of contour */ 7270 FT_UInt end_point; /* end point (last+1) of contour */ 7271 7272 FT_UInt first_touched; /* first touched point in contour */ 7273 FT_UInt cur_touched; /* current touched point in contour */ 7274 7275 FT_UInt point; /* current point */ 7276 FT_Short contour; /* current contour */ 7277 7278 FT_UNUSED_ARG; 7279 7280 7281 /* ignore empty outlines */ 7282 if ( CUR.pts.n_contours == 0 ) 7283 return; 7284 7285 if ( CUR.opcode & 1 ) 7286 { 7287 mask = FT_CURVE_TAG_TOUCH_X; 7288 V.orgs = CUR.pts.org; 7289 V.curs = CUR.pts.cur; 7290 V.orus = CUR.pts.orus; 7291 } 7292 else 7293 { 7294 mask = FT_CURVE_TAG_TOUCH_Y; 7295 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 ); 7296 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 ); 7297 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 ); 7298 } 7299 V.max_points = CUR.pts.n_points; 7300 7301 contour = 0; 7302 point = 0; 7303 7304#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 7305 if ( SUBPIXEL_HINTING && 7306 CUR.ignore_x_mode ) 7307 { 7308 CUR.iup_called = TRUE; 7309 if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP ) 7310 return; 7311 } 7312#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 7313 7314 do 7315 { 7316 end_point = CUR.pts.contours[contour] - CUR.pts.first_point; 7317 first_point = point; 7318 7319 if ( BOUNDS ( end_point, CUR.pts.n_points ) ) 7320 end_point = CUR.pts.n_points - 1; 7321 7322 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 ) 7323 point++; 7324 7325 if ( point <= end_point ) 7326 { 7327 first_touched = point; 7328 cur_touched = point; 7329 7330 point++; 7331 7332 while ( point <= end_point ) 7333 { 7334 if ( ( CUR.pts.tags[point] & mask ) != 0 ) 7335 { 7336 _iup_worker_interpolate( &V, 7337 cur_touched + 1, 7338 point - 1, 7339 cur_touched, 7340 point ); 7341 cur_touched = point; 7342 } 7343 7344 point++; 7345 } 7346 7347 if ( cur_touched == first_touched ) 7348 _iup_worker_shift( &V, first_point, end_point, cur_touched ); 7349 else 7350 { 7351 _iup_worker_interpolate( &V, 7352 (FT_UShort)( cur_touched + 1 ), 7353 end_point, 7354 cur_touched, 7355 first_touched ); 7356 7357 if ( first_touched > 0 ) 7358 _iup_worker_interpolate( &V, 7359 first_point, 7360 first_touched - 1, 7361 cur_touched, 7362 first_touched ); 7363 } 7364 } 7365 contour++; 7366 } while ( contour < CUR.pts.n_contours ); 7367 } 7368 7369 7370 /*************************************************************************/ 7371 /* */ 7372 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */ 7373 /* Opcode range: 0x5D,0x71,0x72 */ 7374 /* Stack: uint32 (2 * uint32)... --> */ 7375 /* */ 7376 static void 7377 Ins_DELTAP( INS_ARG ) 7378 { 7379 FT_ULong k, nump; 7380 FT_UShort A; 7381 FT_ULong C; 7382 FT_Long B; 7383#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 7384 FT_UShort B1, B2; 7385 7386 7387 if ( SUBPIXEL_HINTING && 7388 CUR.ignore_x_mode && 7389 CUR.iup_called && 7390 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) 7391 goto Fail; 7392#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 7393 7394 7395#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING 7396 /* Delta hinting is covered by US Patent 5159668. */ 7397 if ( CUR.face->unpatented_hinting ) 7398 { 7399 FT_Long n = args[0] * 2; 7400 7401 7402 if ( CUR.args < n ) 7403 { 7404 if ( CUR.pedantic_hinting ) 7405 CUR.error = FT_THROW( Too_Few_Arguments ); 7406 n = CUR.args; 7407 } 7408 7409 CUR.args -= n; 7410 CUR.new_top = CUR.args; 7411 return; 7412 } 7413#endif 7414 7415 nump = (FT_ULong)args[0]; /* some points theoretically may occur more 7416 than once, thus UShort isn't enough */ 7417 7418 for ( k = 1; k <= nump; k++ ) 7419 { 7420 if ( CUR.args < 2 ) 7421 { 7422 if ( CUR.pedantic_hinting ) 7423 CUR.error = FT_THROW( Too_Few_Arguments ); 7424 CUR.args = 0; 7425 goto Fail; 7426 } 7427 7428 CUR.args -= 2; 7429 7430 A = (FT_UShort)CUR.stack[CUR.args + 1]; 7431 B = CUR.stack[CUR.args]; 7432 7433 /* XXX: Because some popular fonts contain some invalid DeltaP */ 7434 /* instructions, we simply ignore them when the stacked */ 7435 /* point reference is off limit, rather than returning an */ 7436 /* error. As a delta instruction doesn't change a glyph */ 7437 /* in great ways, this shouldn't be a problem. */ 7438 7439 if ( !BOUNDS( A, CUR.zp0.n_points ) ) 7440 { 7441 C = ( (FT_ULong)B & 0xF0 ) >> 4; 7442 7443 switch ( CUR.opcode ) 7444 { 7445 case 0x5D: 7446 break; 7447 7448 case 0x71: 7449 C += 16; 7450 break; 7451 7452 case 0x72: 7453 C += 32; 7454 break; 7455 } 7456 7457 C += CUR.GS.delta_base; 7458 7459 if ( CURRENT_Ppem() == (FT_Long)C ) 7460 { 7461 B = ( (FT_ULong)B & 0xF ) - 8; 7462 if ( B >= 0 ) 7463 B++; 7464 B = B * 64 / ( 1L << CUR.GS.delta_shift ); 7465 7466#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 7467 7468 if ( SUBPIXEL_HINTING ) 7469 { 7470 /* 7471 * Allow delta move if 7472 * 7473 * - not using ignore_x_mode rendering 7474 * - glyph is specifically set to allow it 7475 * - glyph is composite and freedom vector is not subpixel 7476 * vector 7477 */ 7478 if ( !CUR.ignore_x_mode || 7479 ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) || 7480 ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ) 7481 CUR_Func_move( &CUR.zp0, A, B ); 7482 7483 /* Otherwise apply subpixel hinting and */ 7484 /* compatibility mode rules */ 7485 else if ( CUR.ignore_x_mode ) 7486 { 7487 if ( CUR.GS.freeVector.y != 0 ) 7488 B1 = CUR.zp0.cur[A].y; 7489 else 7490 B1 = CUR.zp0.cur[A].x; 7491 7492#if 0 7493 /* Standard Subpixel Hinting: Allow y move. */ 7494 /* This messes up dejavu and may not be needed... */ 7495 if ( !CUR.face->sph_compatibility_mode && 7496 CUR.GS.freeVector.y != 0 ) 7497 CUR_Func_move( &CUR.zp0, A, B ); 7498 else 7499#endif /* 0 */ 7500 7501 /* Compatibility Mode: Allow x or y move if point touched in */ 7502 /* Y direction. */ 7503 if ( CUR.face->sph_compatibility_mode && 7504 !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) ) 7505 { 7506 /* save the y value of the point now; compare after move */ 7507 B1 = CUR.zp0.cur[A].y; 7508 7509 if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) 7510 B = FT_PIX_ROUND( B1 + B ) - B1; 7511 7512 /* Allow delta move if using sph_compatibility_mode, */ 7513 /* IUP has not been called, and point is touched on Y. */ 7514 if ( !CUR.iup_called && 7515 ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) 7516 CUR_Func_move( &CUR.zp0, A, B ); 7517 } 7518 7519 B2 = CUR.zp0.cur[A].y; 7520 7521 /* Reverse this move if it results in a disallowed move */ 7522 if ( CUR.GS.freeVector.y != 0 && 7523 ( ( CUR.face->sph_compatibility_mode && 7524 ( B1 & 63 ) == 0 && 7525 ( B2 & 63 ) != 0 ) || 7526 ( ( CUR.sph_tweak_flags & 7527 SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) && 7528 ( B1 & 63 ) != 0 && 7529 ( B2 & 63 ) != 0 ) ) ) 7530 CUR_Func_move( &CUR.zp0, A, -B ); 7531 } 7532 } 7533 else 7534#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 7535 7536 CUR_Func_move( &CUR.zp0, A, B ); 7537 } 7538 } 7539 else 7540 if ( CUR.pedantic_hinting ) 7541 CUR.error = FT_THROW( Invalid_Reference ); 7542 } 7543 7544 Fail: 7545 CUR.new_top = CUR.args; 7546 } 7547 7548 7549 /*************************************************************************/ 7550 /* */ 7551 /* DELTACn[]: DELTA exceptions C1, C2, C3 */ 7552 /* Opcode range: 0x73,0x74,0x75 */ 7553 /* Stack: uint32 (2 * uint32)... --> */ 7554 /* */ 7555 static void 7556 Ins_DELTAC( INS_ARG ) 7557 { 7558 FT_ULong nump, k; 7559 FT_ULong A, C; 7560 FT_Long B; 7561 7562 7563#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING 7564 /* Delta hinting is covered by US Patent 5159668. */ 7565 if ( CUR.face->unpatented_hinting ) 7566 { 7567 FT_Long n = args[0] * 2; 7568 7569 7570 if ( CUR.args < n ) 7571 { 7572 if ( CUR.pedantic_hinting ) 7573 CUR.error = FT_THROW( Too_Few_Arguments ); 7574 n = CUR.args; 7575 } 7576 7577 CUR.args -= n; 7578 CUR.new_top = CUR.args; 7579 return; 7580 } 7581#endif 7582 7583 nump = (FT_ULong)args[0]; 7584 7585 for ( k = 1; k <= nump; k++ ) 7586 { 7587 if ( CUR.args < 2 ) 7588 { 7589 if ( CUR.pedantic_hinting ) 7590 CUR.error = FT_THROW( Too_Few_Arguments ); 7591 CUR.args = 0; 7592 goto Fail; 7593 } 7594 7595 CUR.args -= 2; 7596 7597 A = (FT_ULong)CUR.stack[CUR.args + 1]; 7598 B = CUR.stack[CUR.args]; 7599 7600 if ( BOUNDSL( A, CUR.cvtSize ) ) 7601 { 7602 if ( CUR.pedantic_hinting ) 7603 { 7604 CUR.error = FT_THROW( Invalid_Reference ); 7605 return; 7606 } 7607 } 7608 else 7609 { 7610 C = ( (FT_ULong)B & 0xF0 ) >> 4; 7611 7612 switch ( CUR.opcode ) 7613 { 7614 case 0x73: 7615 break; 7616 7617 case 0x74: 7618 C += 16; 7619 break; 7620 7621 case 0x75: 7622 C += 32; 7623 break; 7624 } 7625 7626 C += CUR.GS.delta_base; 7627 7628 if ( CURRENT_Ppem() == (FT_Long)C ) 7629 { 7630 B = ( (FT_ULong)B & 0xF ) - 8; 7631 if ( B >= 0 ) 7632 B++; 7633 B = B * 64 / ( 1L << CUR.GS.delta_shift ); 7634 7635 CUR_Func_move_cvt( A, B ); 7636 } 7637 } 7638 } 7639 7640 Fail: 7641 CUR.new_top = CUR.args; 7642 } 7643 7644 7645 /*************************************************************************/ 7646 /* */ 7647 /* MISC. INSTRUCTIONS */ 7648 /* */ 7649 /*************************************************************************/ 7650 7651 7652 /*************************************************************************/ 7653 /* */ 7654 /* GETINFO[]: GET INFOrmation */ 7655 /* Opcode range: 0x88 */ 7656 /* Stack: uint32 --> uint32 */ 7657 /* */ 7658 static void 7659 Ins_GETINFO( INS_ARG ) 7660 { 7661 FT_Long K; 7662 7663 7664 K = 0; 7665 7666#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 7667 /********************************/ 7668 /* RASTERIZER VERSION */ 7669 /* Selector Bit: 0 */ 7670 /* Return Bit(s): 0-7 */ 7671 /* */ 7672 if ( SUBPIXEL_HINTING && 7673 ( args[0] & 1 ) != 0 && 7674 CUR.ignore_x_mode ) 7675 { 7676 K = CUR.rasterizer_version; 7677 FT_TRACE7(( "Setting rasterizer version %d\n", 7678 CUR.rasterizer_version )); 7679 } 7680 else 7681#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 7682 if ( ( args[0] & 1 ) != 0 ) 7683 K = TT_INTERPRETER_VERSION_35; 7684 7685 /********************************/ 7686 /* GLYPH ROTATED */ 7687 /* Selector Bit: 1 */ 7688 /* Return Bit(s): 8 */ 7689 /* */ 7690 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated ) 7691 K |= 0x80; 7692 7693 /********************************/ 7694 /* GLYPH STRETCHED */ 7695 /* Selector Bit: 2 */ 7696 /* Return Bit(s): 9 */ 7697 /* */ 7698 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched ) 7699 K |= 1 << 8; 7700 7701 /********************************/ 7702 /* HINTING FOR GRAYSCALE */ 7703 /* Selector Bit: 5 */ 7704 /* Return Bit(s): 12 */ 7705 /* */ 7706 if ( ( args[0] & 32 ) != 0 && CUR.grayscale ) 7707 K |= 1 << 12; 7708 7709#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 7710 7711 if ( SUBPIXEL_HINTING && 7712 CUR.ignore_x_mode && 7713 CUR.rasterizer_version >= TT_INTERPRETER_VERSION_35 ) 7714 { 7715 /********************************/ 7716 /* HINTING FOR GRAYSCALE */ 7717 /* Selector Bit: 5 */ 7718 /* Return Bit(s): 12 */ 7719 /* */ 7720 if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting ) 7721 K |= 1 << 12; 7722 7723 /********************************/ 7724 /* HINTING FOR SUBPIXEL */ 7725 /* Selector Bit: 6 */ 7726 /* Return Bit(s): 13 */ 7727 /* */ 7728 if ( ( args[0] & 64 ) != 0 && 7729 CUR.subpixel_hinting && 7730 CUR.rasterizer_version >= 37 ) 7731 { 7732 K |= 1 << 13; 7733 7734 /* the stuff below is irrelevant if subpixel_hinting is not set */ 7735 7736 /********************************/ 7737 /* COMPATIBLE WIDTHS ENABLED */ 7738 /* Selector Bit: 7 */ 7739 /* Return Bit(s): 14 */ 7740 /* */ 7741 /* Functionality still needs to be added */ 7742 if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths ) 7743 K |= 1 << 14; 7744 7745 /********************************/ 7746 /* SYMMETRICAL SMOOTHING */ 7747 /* Selector Bit: 8 */ 7748 /* Return Bit(s): 15 */ 7749 /* */ 7750 /* Functionality still needs to be added */ 7751 if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing ) 7752 K |= 1 << 15; 7753 7754 /********************************/ 7755 /* HINTING FOR BGR? */ 7756 /* Selector Bit: 9 */ 7757 /* Return Bit(s): 16 */ 7758 /* */ 7759 /* Functionality still needs to be added */ 7760 if ( ( args[0] & 512 ) != 0 && CUR.bgr ) 7761 K |= 1 << 16; 7762 7763 if ( CUR.rasterizer_version >= 38 ) 7764 { 7765 /********************************/ 7766 /* SUBPIXEL POSITIONED? */ 7767 /* Selector Bit: 10 */ 7768 /* Return Bit(s): 17 */ 7769 /* */ 7770 /* Functionality still needs to be added */ 7771 if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned ) 7772 K |= 1 << 17; 7773 } 7774 } 7775 } 7776 7777#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 7778 7779 args[0] = K; 7780 } 7781 7782 7783 static void 7784 Ins_UNKNOWN( INS_ARG ) 7785 { 7786 TT_DefRecord* def = CUR.IDefs; 7787 TT_DefRecord* limit = def + CUR.numIDefs; 7788 7789 FT_UNUSED_ARG; 7790 7791 7792 for ( ; def < limit; def++ ) 7793 { 7794 if ( (FT_Byte)def->opc == CUR.opcode && def->active ) 7795 { 7796 TT_CallRec* call; 7797 7798 7799 if ( CUR.callTop >= CUR.callSize ) 7800 { 7801 CUR.error = FT_THROW( Stack_Overflow ); 7802 return; 7803 } 7804 7805 call = CUR.callStack + CUR.callTop++; 7806 7807 call->Caller_Range = CUR.curRange; 7808 call->Caller_IP = CUR.IP + 1; 7809 call->Cur_Count = 1; 7810 call->Cur_Restart = def->start; 7811 call->Cur_End = def->end; 7812 7813 INS_Goto_CodeRange( def->range, def->start ); 7814 7815 CUR.step_ins = FALSE; 7816 return; 7817 } 7818 } 7819 7820 CUR.error = FT_THROW( Invalid_Opcode ); 7821 } 7822 7823 7824#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH 7825 7826 7827 static 7828 TInstruction_Function Instruct_Dispatch[256] = 7829 { 7830 /* Opcodes are gathered in groups of 16. */ 7831 /* Please keep the spaces as they are. */ 7832 7833 /* SVTCA y */ Ins_SVTCA, 7834 /* SVTCA x */ Ins_SVTCA, 7835 /* SPvTCA y */ Ins_SPVTCA, 7836 /* SPvTCA x */ Ins_SPVTCA, 7837 /* SFvTCA y */ Ins_SFVTCA, 7838 /* SFvTCA x */ Ins_SFVTCA, 7839 /* SPvTL // */ Ins_SPVTL, 7840 /* SPvTL + */ Ins_SPVTL, 7841 /* SFvTL // */ Ins_SFVTL, 7842 /* SFvTL + */ Ins_SFVTL, 7843 /* SPvFS */ Ins_SPVFS, 7844 /* SFvFS */ Ins_SFVFS, 7845 /* GPV */ Ins_GPV, 7846 /* GFV */ Ins_GFV, 7847 /* SFvTPv */ Ins_SFVTPV, 7848 /* ISECT */ Ins_ISECT, 7849 7850 /* SRP0 */ Ins_SRP0, 7851 /* SRP1 */ Ins_SRP1, 7852 /* SRP2 */ Ins_SRP2, 7853 /* SZP0 */ Ins_SZP0, 7854 /* SZP1 */ Ins_SZP1, 7855 /* SZP2 */ Ins_SZP2, 7856 /* SZPS */ Ins_SZPS, 7857 /* SLOOP */ Ins_SLOOP, 7858 /* RTG */ Ins_RTG, 7859 /* RTHG */ Ins_RTHG, 7860 /* SMD */ Ins_SMD, 7861 /* ELSE */ Ins_ELSE, 7862 /* JMPR */ Ins_JMPR, 7863 /* SCvTCi */ Ins_SCVTCI, 7864 /* SSwCi */ Ins_SSWCI, 7865 /* SSW */ Ins_SSW, 7866 7867 /* DUP */ Ins_DUP, 7868 /* POP */ Ins_POP, 7869 /* CLEAR */ Ins_CLEAR, 7870 /* SWAP */ Ins_SWAP, 7871 /* DEPTH */ Ins_DEPTH, 7872 /* CINDEX */ Ins_CINDEX, 7873 /* MINDEX */ Ins_MINDEX, 7874 /* AlignPTS */ Ins_ALIGNPTS, 7875 /* INS_0x28 */ Ins_UNKNOWN, 7876 /* UTP */ Ins_UTP, 7877 /* LOOPCALL */ Ins_LOOPCALL, 7878 /* CALL */ Ins_CALL, 7879 /* FDEF */ Ins_FDEF, 7880 /* ENDF */ Ins_ENDF, 7881 /* MDAP[0] */ Ins_MDAP, 7882 /* MDAP[1] */ Ins_MDAP, 7883 7884 /* IUP[0] */ Ins_IUP, 7885 /* IUP[1] */ Ins_IUP, 7886 /* SHP[0] */ Ins_SHP, 7887 /* SHP[1] */ Ins_SHP, 7888 /* SHC[0] */ Ins_SHC, 7889 /* SHC[1] */ Ins_SHC, 7890 /* SHZ[0] */ Ins_SHZ, 7891 /* SHZ[1] */ Ins_SHZ, 7892 /* SHPIX */ Ins_SHPIX, 7893 /* IP */ Ins_IP, 7894 /* MSIRP[0] */ Ins_MSIRP, 7895 /* MSIRP[1] */ Ins_MSIRP, 7896 /* AlignRP */ Ins_ALIGNRP, 7897 /* RTDG */ Ins_RTDG, 7898 /* MIAP[0] */ Ins_MIAP, 7899 /* MIAP[1] */ Ins_MIAP, 7900 7901 /* NPushB */ Ins_NPUSHB, 7902 /* NPushW */ Ins_NPUSHW, 7903 /* WS */ Ins_WS, 7904 /* RS */ Ins_RS, 7905 /* WCvtP */ Ins_WCVTP, 7906 /* RCvt */ Ins_RCVT, 7907 /* GC[0] */ Ins_GC, 7908 /* GC[1] */ Ins_GC, 7909 /* SCFS */ Ins_SCFS, 7910 /* MD[0] */ Ins_MD, 7911 /* MD[1] */ Ins_MD, 7912 /* MPPEM */ Ins_MPPEM, 7913 /* MPS */ Ins_MPS, 7914 /* FlipON */ Ins_FLIPON, 7915 /* FlipOFF */ Ins_FLIPOFF, 7916 /* DEBUG */ Ins_DEBUG, 7917 7918 /* LT */ Ins_LT, 7919 /* LTEQ */ Ins_LTEQ, 7920 /* GT */ Ins_GT, 7921 /* GTEQ */ Ins_GTEQ, 7922 /* EQ */ Ins_EQ, 7923 /* NEQ */ Ins_NEQ, 7924 /* ODD */ Ins_ODD, 7925 /* EVEN */ Ins_EVEN, 7926 /* IF */ Ins_IF, 7927 /* EIF */ Ins_EIF, 7928 /* AND */ Ins_AND, 7929 /* OR */ Ins_OR, 7930 /* NOT */ Ins_NOT, 7931 /* DeltaP1 */ Ins_DELTAP, 7932 /* SDB */ Ins_SDB, 7933 /* SDS */ Ins_SDS, 7934 7935 /* ADD */ Ins_ADD, 7936 /* SUB */ Ins_SUB, 7937 /* DIV */ Ins_DIV, 7938 /* MUL */ Ins_MUL, 7939 /* ABS */ Ins_ABS, 7940 /* NEG */ Ins_NEG, 7941 /* FLOOR */ Ins_FLOOR, 7942 /* CEILING */ Ins_CEILING, 7943 /* ROUND[0] */ Ins_ROUND, 7944 /* ROUND[1] */ Ins_ROUND, 7945 /* ROUND[2] */ Ins_ROUND, 7946 /* ROUND[3] */ Ins_ROUND, 7947 /* NROUND[0] */ Ins_NROUND, 7948 /* NROUND[1] */ Ins_NROUND, 7949 /* NROUND[2] */ Ins_NROUND, 7950 /* NROUND[3] */ Ins_NROUND, 7951 7952 /* WCvtF */ Ins_WCVTF, 7953 /* DeltaP2 */ Ins_DELTAP, 7954 /* DeltaP3 */ Ins_DELTAP, 7955 /* DeltaCn[0] */ Ins_DELTAC, 7956 /* DeltaCn[1] */ Ins_DELTAC, 7957 /* DeltaCn[2] */ Ins_DELTAC, 7958 /* SROUND */ Ins_SROUND, 7959 /* S45Round */ Ins_S45ROUND, 7960 /* JROT */ Ins_JROT, 7961 /* JROF */ Ins_JROF, 7962 /* ROFF */ Ins_ROFF, 7963 /* INS_0x7B */ Ins_UNKNOWN, 7964 /* RUTG */ Ins_RUTG, 7965 /* RDTG */ Ins_RDTG, 7966 /* SANGW */ Ins_SANGW, 7967 /* AA */ Ins_AA, 7968 7969 /* FlipPT */ Ins_FLIPPT, 7970 /* FlipRgON */ Ins_FLIPRGON, 7971 /* FlipRgOFF */ Ins_FLIPRGOFF, 7972 /* INS_0x83 */ Ins_UNKNOWN, 7973 /* INS_0x84 */ Ins_UNKNOWN, 7974 /* ScanCTRL */ Ins_SCANCTRL, 7975 /* SDPVTL[0] */ Ins_SDPVTL, 7976 /* SDPVTL[1] */ Ins_SDPVTL, 7977 /* GetINFO */ Ins_GETINFO, 7978 /* IDEF */ Ins_IDEF, 7979 /* ROLL */ Ins_ROLL, 7980 /* MAX */ Ins_MAX, 7981 /* MIN */ Ins_MIN, 7982 /* ScanTYPE */ Ins_SCANTYPE, 7983 /* InstCTRL */ Ins_INSTCTRL, 7984 /* INS_0x8F */ Ins_UNKNOWN, 7985 7986 /* INS_0x90 */ Ins_UNKNOWN, 7987 /* INS_0x91 */ Ins_UNKNOWN, 7988 /* INS_0x92 */ Ins_UNKNOWN, 7989 /* INS_0x93 */ Ins_UNKNOWN, 7990 /* INS_0x94 */ Ins_UNKNOWN, 7991 /* INS_0x95 */ Ins_UNKNOWN, 7992 /* INS_0x96 */ Ins_UNKNOWN, 7993 /* INS_0x97 */ Ins_UNKNOWN, 7994 /* INS_0x98 */ Ins_UNKNOWN, 7995 /* INS_0x99 */ Ins_UNKNOWN, 7996 /* INS_0x9A */ Ins_UNKNOWN, 7997 /* INS_0x9B */ Ins_UNKNOWN, 7998 /* INS_0x9C */ Ins_UNKNOWN, 7999 /* INS_0x9D */ Ins_UNKNOWN, 8000 /* INS_0x9E */ Ins_UNKNOWN, 8001 /* INS_0x9F */ Ins_UNKNOWN, 8002 8003 /* INS_0xA0 */ Ins_UNKNOWN, 8004 /* INS_0xA1 */ Ins_UNKNOWN, 8005 /* INS_0xA2 */ Ins_UNKNOWN, 8006 /* INS_0xA3 */ Ins_UNKNOWN, 8007 /* INS_0xA4 */ Ins_UNKNOWN, 8008 /* INS_0xA5 */ Ins_UNKNOWN, 8009 /* INS_0xA6 */ Ins_UNKNOWN, 8010 /* INS_0xA7 */ Ins_UNKNOWN, 8011 /* INS_0xA8 */ Ins_UNKNOWN, 8012 /* INS_0xA9 */ Ins_UNKNOWN, 8013 /* INS_0xAA */ Ins_UNKNOWN, 8014 /* INS_0xAB */ Ins_UNKNOWN, 8015 /* INS_0xAC */ Ins_UNKNOWN, 8016 /* INS_0xAD */ Ins_UNKNOWN, 8017 /* INS_0xAE */ Ins_UNKNOWN, 8018 /* INS_0xAF */ Ins_UNKNOWN, 8019 8020 /* PushB[0] */ Ins_PUSHB, 8021 /* PushB[1] */ Ins_PUSHB, 8022 /* PushB[2] */ Ins_PUSHB, 8023 /* PushB[3] */ Ins_PUSHB, 8024 /* PushB[4] */ Ins_PUSHB, 8025 /* PushB[5] */ Ins_PUSHB, 8026 /* PushB[6] */ Ins_PUSHB, 8027 /* PushB[7] */ Ins_PUSHB, 8028 /* PushW[0] */ Ins_PUSHW, 8029 /* PushW[1] */ Ins_PUSHW, 8030 /* PushW[2] */ Ins_PUSHW, 8031 /* PushW[3] */ Ins_PUSHW, 8032 /* PushW[4] */ Ins_PUSHW, 8033 /* PushW[5] */ Ins_PUSHW, 8034 /* PushW[6] */ Ins_PUSHW, 8035 /* PushW[7] */ Ins_PUSHW, 8036 8037 /* MDRP[00] */ Ins_MDRP, 8038 /* MDRP[01] */ Ins_MDRP, 8039 /* MDRP[02] */ Ins_MDRP, 8040 /* MDRP[03] */ Ins_MDRP, 8041 /* MDRP[04] */ Ins_MDRP, 8042 /* MDRP[05] */ Ins_MDRP, 8043 /* MDRP[06] */ Ins_MDRP, 8044 /* MDRP[07] */ Ins_MDRP, 8045 /* MDRP[08] */ Ins_MDRP, 8046 /* MDRP[09] */ Ins_MDRP, 8047 /* MDRP[10] */ Ins_MDRP, 8048 /* MDRP[11] */ Ins_MDRP, 8049 /* MDRP[12] */ Ins_MDRP, 8050 /* MDRP[13] */ Ins_MDRP, 8051 /* MDRP[14] */ Ins_MDRP, 8052 /* MDRP[15] */ Ins_MDRP, 8053 8054 /* MDRP[16] */ Ins_MDRP, 8055 /* MDRP[17] */ Ins_MDRP, 8056 /* MDRP[18] */ Ins_MDRP, 8057 /* MDRP[19] */ Ins_MDRP, 8058 /* MDRP[20] */ Ins_MDRP, 8059 /* MDRP[21] */ Ins_MDRP, 8060 /* MDRP[22] */ Ins_MDRP, 8061 /* MDRP[23] */ Ins_MDRP, 8062 /* MDRP[24] */ Ins_MDRP, 8063 /* MDRP[25] */ Ins_MDRP, 8064 /* MDRP[26] */ Ins_MDRP, 8065 /* MDRP[27] */ Ins_MDRP, 8066 /* MDRP[28] */ Ins_MDRP, 8067 /* MDRP[29] */ Ins_MDRP, 8068 /* MDRP[30] */ Ins_MDRP, 8069 /* MDRP[31] */ Ins_MDRP, 8070 8071 /* MIRP[00] */ Ins_MIRP, 8072 /* MIRP[01] */ Ins_MIRP, 8073 /* MIRP[02] */ Ins_MIRP, 8074 /* MIRP[03] */ Ins_MIRP, 8075 /* MIRP[04] */ Ins_MIRP, 8076 /* MIRP[05] */ Ins_MIRP, 8077 /* MIRP[06] */ Ins_MIRP, 8078 /* MIRP[07] */ Ins_MIRP, 8079 /* MIRP[08] */ Ins_MIRP, 8080 /* MIRP[09] */ Ins_MIRP, 8081 /* MIRP[10] */ Ins_MIRP, 8082 /* MIRP[11] */ Ins_MIRP, 8083 /* MIRP[12] */ Ins_MIRP, 8084 /* MIRP[13] */ Ins_MIRP, 8085 /* MIRP[14] */ Ins_MIRP, 8086 /* MIRP[15] */ Ins_MIRP, 8087 8088 /* MIRP[16] */ Ins_MIRP, 8089 /* MIRP[17] */ Ins_MIRP, 8090 /* MIRP[18] */ Ins_MIRP, 8091 /* MIRP[19] */ Ins_MIRP, 8092 /* MIRP[20] */ Ins_MIRP, 8093 /* MIRP[21] */ Ins_MIRP, 8094 /* MIRP[22] */ Ins_MIRP, 8095 /* MIRP[23] */ Ins_MIRP, 8096 /* MIRP[24] */ Ins_MIRP, 8097 /* MIRP[25] */ Ins_MIRP, 8098 /* MIRP[26] */ Ins_MIRP, 8099 /* MIRP[27] */ Ins_MIRP, 8100 /* MIRP[28] */ Ins_MIRP, 8101 /* MIRP[29] */ Ins_MIRP, 8102 /* MIRP[30] */ Ins_MIRP, 8103 /* MIRP[31] */ Ins_MIRP 8104 }; 8105 8106 8107#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */ 8108 8109 8110 /*************************************************************************/ 8111 /* */ 8112 /* RUN */ 8113 /* */ 8114 /* This function executes a run of opcodes. It will exit in the */ 8115 /* following cases: */ 8116 /* */ 8117 /* - Errors (in which case it returns FALSE). */ 8118 /* */ 8119 /* - Reaching the end of the main code range (returns TRUE). */ 8120 /* Reaching the end of a code range within a function call is an */ 8121 /* error. */ 8122 /* */ 8123 /* - After executing one single opcode, if the flag `Instruction_Trap' */ 8124 /* is set to TRUE (returns TRUE). */ 8125 /* */ 8126 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */ 8127 /* an instruction trap or a normal termination. */ 8128 /* */ 8129 /* */ 8130 /* Note: The documented DEBUG opcode pops a value from the stack. This */ 8131 /* behaviour is unsupported; here a DEBUG opcode is always an */ 8132 /* error. */ 8133 /* */ 8134 /* */ 8135 /* THIS IS THE INTERPRETER'S MAIN LOOP. */ 8136 /* */ 8137 /* Instructions appear in the specification's order. */ 8138 /* */ 8139 /*************************************************************************/ 8140 8141 8142 /* documentation is in ttinterp.h */ 8143 8144 FT_EXPORT_DEF( FT_Error ) 8145 TT_RunIns( TT_ExecContext exc ) 8146 { 8147 FT_Long ins_counter = 0; /* executed instructions counter */ 8148 FT_UShort i; 8149 8150#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 8151 FT_Byte opcode_pattern[1][2] = { 8152 /* #8 TypeMan Talk Align */ 8153 { 8154 0x06, /* SPVTL */ 8155 0x7D, /* RDTG */ 8156 }, 8157 }; 8158 FT_UShort opcode_patterns = 1; 8159 FT_UShort opcode_pointer[1] = { 0 }; 8160 FT_UShort opcode_size[1] = { 1 }; 8161#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 8162 8163 8164#ifdef TT_CONFIG_OPTION_STATIC_RASTER 8165 cur = *exc; 8166#endif 8167 8168#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 8169 CUR.iup_called = FALSE; 8170#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 8171 8172 /* set CVT functions */ 8173 CUR.tt_metrics.ratio = 0; 8174 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) 8175 { 8176 /* non-square pixels, use the stretched routines */ 8177 CUR.func_read_cvt = Read_CVT_Stretched; 8178 CUR.func_write_cvt = Write_CVT_Stretched; 8179 CUR.func_move_cvt = Move_CVT_Stretched; 8180 } 8181 else 8182 { 8183 /* square pixels, use normal routines */ 8184 CUR.func_read_cvt = Read_CVT; 8185 CUR.func_write_cvt = Write_CVT; 8186 CUR.func_move_cvt = Move_CVT; 8187 } 8188 8189 COMPUTE_Funcs(); 8190 COMPUTE_Round( (FT_Byte)exc->GS.round_state ); 8191 8192 do 8193 { 8194 CUR.opcode = CUR.code[CUR.IP]; 8195 8196 FT_TRACE7(( " " )); 8197 FT_TRACE7(( opcode_name[CUR.opcode] )); 8198 FT_TRACE7(( "\n" )); 8199 8200 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 ) 8201 { 8202 if ( CUR.IP + 1 >= CUR.codeSize ) 8203 goto LErrorCodeOverflow_; 8204 8205 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; 8206 } 8207 8208 if ( CUR.IP + CUR.length > CUR.codeSize ) 8209 goto LErrorCodeOverflow_; 8210 8211 /* First, let's check for empty stack and overflow */ 8212 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 ); 8213 8214 /* `args' is the top of the stack once arguments have been popped. */ 8215 /* One can also interpret it as the index of the last argument. */ 8216 if ( CUR.args < 0 ) 8217 { 8218 if ( CUR.pedantic_hinting ) 8219 { 8220 CUR.error = FT_THROW( Too_Few_Arguments ); 8221 goto LErrorLabel_; 8222 } 8223 8224 /* push zeroes onto the stack */ 8225 for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ ) 8226 CUR.stack[i] = 0; 8227 CUR.args = 0; 8228 } 8229 8230 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 ); 8231 8232 /* `new_top' is the new top of the stack, after the instruction's */ 8233 /* execution. `top' will be set to `new_top' after the `switch' */ 8234 /* statement. */ 8235 if ( CUR.new_top > CUR.stackSize ) 8236 { 8237 CUR.error = FT_THROW( Stack_Overflow ); 8238 goto LErrorLabel_; 8239 } 8240 8241 CUR.step_ins = TRUE; 8242 CUR.error = FT_Err_Ok; 8243 8244#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING 8245 8246 if ( SUBPIXEL_HINTING ) 8247 { 8248 for ( i = 0; i < opcode_patterns; i++ ) 8249 { 8250 if ( opcode_pointer[i] < opcode_size[i] && 8251 CUR.opcode == opcode_pattern[i][opcode_pointer[i]] ) 8252 { 8253 opcode_pointer[i] += 1; 8254 8255 if ( opcode_pointer[i] == opcode_size[i] ) 8256 { 8257 FT_TRACE7(( "sph: opcode ptrn: %d, %s %s\n", 8258 i, 8259 CUR.face->root.family_name, 8260 CUR.face->root.style_name )); 8261 8262 switch ( i ) 8263 { 8264 case 0: 8265 break; 8266 } 8267 opcode_pointer[i] = 0; 8268 } 8269 } 8270 else 8271 opcode_pointer[i] = 0; 8272 } 8273 } 8274 8275#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ 8276 8277#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH 8278 8279 { 8280 FT_Long* args = CUR.stack + CUR.args; 8281 FT_Byte opcode = CUR.opcode; 8282 8283 8284#undef ARRAY_BOUND_ERROR 8285#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref 8286 8287 8288 switch ( opcode ) 8289 { 8290 case 0x00: /* SVTCA y */ 8291 case 0x01: /* SVTCA x */ 8292 case 0x02: /* SPvTCA y */ 8293 case 0x03: /* SPvTCA x */ 8294 case 0x04: /* SFvTCA y */ 8295 case 0x05: /* SFvTCA x */ 8296 { 8297 FT_Short AA, BB; 8298 8299 8300 AA = (FT_Short)( ( opcode & 1 ) << 14 ); 8301 BB = (FT_Short)( AA ^ 0x4000 ); 8302 8303 if ( opcode < 4 ) 8304 { 8305 CUR.GS.projVector.x = AA; 8306 CUR.GS.projVector.y = BB; 8307 8308 CUR.GS.dualVector.x = AA; 8309 CUR.GS.dualVector.y = BB; 8310 } 8311 else 8312 { 8313 GUESS_VECTOR( projVector ); 8314 } 8315 8316 if ( ( opcode & 2 ) == 0 ) 8317 { 8318 CUR.GS.freeVector.x = AA; 8319 CUR.GS.freeVector.y = BB; 8320 } 8321 else 8322 { 8323 GUESS_VECTOR( freeVector ); 8324 } 8325 8326 COMPUTE_Funcs(); 8327 } 8328 break; 8329 8330 case 0x06: /* SPvTL // */ 8331 case 0x07: /* SPvTL + */ 8332 DO_SPVTL 8333 break; 8334 8335 case 0x08: /* SFvTL // */ 8336 case 0x09: /* SFvTL + */ 8337 DO_SFVTL 8338 break; 8339 8340 case 0x0A: /* SPvFS */ 8341 DO_SPVFS 8342 break; 8343 8344 case 0x0B: /* SFvFS */ 8345 DO_SFVFS 8346 break; 8347 8348 case 0x0C: /* GPV */ 8349 DO_GPV 8350 break; 8351 8352 case 0x0D: /* GFV */ 8353 DO_GFV 8354 break; 8355 8356 case 0x0E: /* SFvTPv */ 8357 DO_SFVTPV 8358 break; 8359 8360 case 0x0F: /* ISECT */ 8361 Ins_ISECT( EXEC_ARG_ args ); 8362 break; 8363 8364 case 0x10: /* SRP0 */ 8365 DO_SRP0 8366 break; 8367 8368 case 0x11: /* SRP1 */ 8369 DO_SRP1 8370 break; 8371 8372 case 0x12: /* SRP2 */ 8373 DO_SRP2 8374 break; 8375 8376 case 0x13: /* SZP0 */ 8377 Ins_SZP0( EXEC_ARG_ args ); 8378 break; 8379 8380 case 0x14: /* SZP1 */ 8381 Ins_SZP1( EXEC_ARG_ args ); 8382 break; 8383 8384 case 0x15: /* SZP2 */ 8385 Ins_SZP2( EXEC_ARG_ args ); 8386 break; 8387 8388 case 0x16: /* SZPS */ 8389 Ins_SZPS( EXEC_ARG_ args ); 8390 break; 8391 8392 case 0x17: /* SLOOP */ 8393 DO_SLOOP 8394 break; 8395 8396 case 0x18: /* RTG */ 8397 DO_RTG 8398 break; 8399 8400 case 0x19: /* RTHG */ 8401 DO_RTHG 8402 break; 8403 8404 case 0x1A: /* SMD */ 8405 DO_SMD 8406 break; 8407 8408 case 0x1B: /* ELSE */ 8409 Ins_ELSE( EXEC_ARG_ args ); 8410 break; 8411 8412 case 0x1C: /* JMPR */ 8413 DO_JMPR 8414 break; 8415 8416 case 0x1D: /* SCVTCI */ 8417 DO_SCVTCI 8418 break; 8419 8420 case 0x1E: /* SSWCI */ 8421 DO_SSWCI 8422 break; 8423 8424 case 0x1F: /* SSW */ 8425 DO_SSW 8426 break; 8427 8428 case 0x20: /* DUP */ 8429 DO_DUP 8430 break; 8431 8432 case 0x21: /* POP */ 8433 /* nothing :-) */ 8434 break; 8435 8436 case 0x22: /* CLEAR */ 8437 DO_CLEAR 8438 break; 8439 8440 case 0x23: /* SWAP */ 8441 DO_SWAP 8442 break; 8443 8444 case 0x24: /* DEPTH */ 8445 DO_DEPTH 8446 break; 8447 8448 case 0x25: /* CINDEX */ 8449 DO_CINDEX 8450 break; 8451 8452 case 0x26: /* MINDEX */ 8453 Ins_MINDEX( EXEC_ARG_ args ); 8454 break; 8455 8456 case 0x27: /* ALIGNPTS */ 8457 Ins_ALIGNPTS( EXEC_ARG_ args ); 8458 break; 8459 8460 case 0x28: /* ???? */ 8461 Ins_UNKNOWN( EXEC_ARG_ args ); 8462 break; 8463 8464 case 0x29: /* UTP */ 8465 Ins_UTP( EXEC_ARG_ args ); 8466 break; 8467 8468 case 0x2A: /* LOOPCALL */ 8469 Ins_LOOPCALL( EXEC_ARG_ args ); 8470 break; 8471 8472 case 0x2B: /* CALL */ 8473 Ins_CALL( EXEC_ARG_ args ); 8474 break; 8475 8476 case 0x2C: /* FDEF */ 8477 Ins_FDEF( EXEC_ARG_ args ); 8478 break; 8479 8480 case 0x2D: /* ENDF */ 8481 Ins_ENDF( EXEC_ARG_ args ); 8482 break; 8483 8484 case 0x2E: /* MDAP */ 8485 case 0x2F: /* MDAP */ 8486 Ins_MDAP( EXEC_ARG_ args ); 8487 break; 8488 8489 case 0x30: /* IUP */ 8490 case 0x31: /* IUP */ 8491 Ins_IUP( EXEC_ARG_ args ); 8492 break; 8493 8494 case 0x32: /* SHP */ 8495 case 0x33: /* SHP */ 8496 Ins_SHP( EXEC_ARG_ args ); 8497 break; 8498 8499 case 0x34: /* SHC */ 8500 case 0x35: /* SHC */ 8501 Ins_SHC( EXEC_ARG_ args ); 8502 break; 8503 8504 case 0x36: /* SHZ */ 8505 case 0x37: /* SHZ */ 8506 Ins_SHZ( EXEC_ARG_ args ); 8507 break; 8508 8509 case 0x38: /* SHPIX */ 8510 Ins_SHPIX( EXEC_ARG_ args ); 8511 break; 8512 8513 case 0x39: /* IP */ 8514 Ins_IP( EXEC_ARG_ args ); 8515 break; 8516 8517 case 0x3A: /* MSIRP */ 8518 case 0x3B: /* MSIRP */ 8519 Ins_MSIRP( EXEC_ARG_ args ); 8520 break; 8521 8522 case 0x3C: /* AlignRP */ 8523 Ins_ALIGNRP( EXEC_ARG_ args ); 8524 break; 8525 8526 case 0x3D: /* RTDG */ 8527 DO_RTDG 8528 break; 8529 8530 case 0x3E: /* MIAP */ 8531 case 0x3F: /* MIAP */ 8532 Ins_MIAP( EXEC_ARG_ args ); 8533 break; 8534 8535 case 0x40: /* NPUSHB */ 8536 Ins_NPUSHB( EXEC_ARG_ args ); 8537 break; 8538 8539 case 0x41: /* NPUSHW */ 8540 Ins_NPUSHW( EXEC_ARG_ args ); 8541 break; 8542 8543 case 0x42: /* WS */ 8544 DO_WS 8545 break; 8546 8547 Set_Invalid_Ref: 8548 CUR.error = FT_THROW( Invalid_Reference ); 8549 break; 8550 8551 case 0x43: /* RS */ 8552 DO_RS 8553 break; 8554 8555 case 0x44: /* WCVTP */ 8556 DO_WCVTP 8557 break; 8558 8559 case 0x45: /* RCVT */ 8560 DO_RCVT 8561 break; 8562 8563 case 0x46: /* GC */ 8564 case 0x47: /* GC */ 8565 Ins_GC( EXEC_ARG_ args ); 8566 break; 8567 8568 case 0x48: /* SCFS */ 8569 Ins_SCFS( EXEC_ARG_ args ); 8570 break; 8571 8572 case 0x49: /* MD */ 8573 case 0x4A: /* MD */ 8574 Ins_MD( EXEC_ARG_ args ); 8575 break; 8576 8577 case 0x4B: /* MPPEM */ 8578 DO_MPPEM 8579 break; 8580 8581 case 0x4C: /* MPS */ 8582 DO_MPS 8583 break; 8584 8585 case 0x4D: /* FLIPON */ 8586 DO_FLIPON 8587 break; 8588 8589 case 0x4E: /* FLIPOFF */ 8590 DO_FLIPOFF 8591 break; 8592 8593 case 0x4F: /* DEBUG */ 8594 DO_DEBUG 8595 break; 8596 8597 case 0x50: /* LT */ 8598 DO_LT 8599 break; 8600 8601 case 0x51: /* LTEQ */ 8602 DO_LTEQ 8603 break; 8604 8605 case 0x52: /* GT */ 8606 DO_GT 8607 break; 8608 8609 case 0x53: /* GTEQ */ 8610 DO_GTEQ 8611 break; 8612 8613 case 0x54: /* EQ */ 8614 DO_EQ 8615 break; 8616 8617 case 0x55: /* NEQ */ 8618 DO_NEQ 8619 break; 8620 8621 case 0x56: /* ODD */ 8622 DO_ODD 8623 break; 8624 8625 case 0x57: /* EVEN */ 8626 DO_EVEN 8627 break; 8628 8629 case 0x58: /* IF */ 8630 Ins_IF( EXEC_ARG_ args ); 8631 break; 8632 8633 case 0x59: /* EIF */ 8634 /* do nothing */ 8635 break; 8636 8637 case 0x5A: /* AND */ 8638 DO_AND 8639 break; 8640 8641 case 0x5B: /* OR */ 8642 DO_OR 8643 break; 8644 8645 case 0x5C: /* NOT */ 8646 DO_NOT 8647 break; 8648 8649 case 0x5D: /* DELTAP1 */ 8650 Ins_DELTAP( EXEC_ARG_ args ); 8651 break; 8652 8653 case 0x5E: /* SDB */ 8654 DO_SDB 8655 break; 8656 8657 case 0x5F: /* SDS */ 8658 DO_SDS 8659 break; 8660 8661 case 0x60: /* ADD */ 8662 DO_ADD 8663 break; 8664 8665 case 0x61: /* SUB */ 8666 DO_SUB 8667 break; 8668 8669 case 0x62: /* DIV */ 8670 DO_DIV 8671 break; 8672 8673 case 0x63: /* MUL */ 8674 DO_MUL 8675 break; 8676 8677 case 0x64: /* ABS */ 8678 DO_ABS 8679 break; 8680 8681 case 0x65: /* NEG */ 8682 DO_NEG 8683 break; 8684 8685 case 0x66: /* FLOOR */ 8686 DO_FLOOR 8687 break; 8688 8689 case 0x67: /* CEILING */ 8690 DO_CEILING 8691 break; 8692 8693 case 0x68: /* ROUND */ 8694 case 0x69: /* ROUND */ 8695 case 0x6A: /* ROUND */ 8696 case 0x6B: /* ROUND */ 8697 DO_ROUND 8698 break; 8699 8700 case 0x6C: /* NROUND */ 8701 case 0x6D: /* NROUND */ 8702 case 0x6E: /* NRRUND */ 8703 case 0x6F: /* NROUND */ 8704 DO_NROUND 8705 break; 8706 8707 case 0x70: /* WCVTF */ 8708 DO_WCVTF 8709 break; 8710 8711 case 0x71: /* DELTAP2 */ 8712 case 0x72: /* DELTAP3 */ 8713 Ins_DELTAP( EXEC_ARG_ args ); 8714 break; 8715 8716 case 0x73: /* DELTAC0 */ 8717 case 0x74: /* DELTAC1 */ 8718 case 0x75: /* DELTAC2 */ 8719 Ins_DELTAC( EXEC_ARG_ args ); 8720 break; 8721 8722 case 0x76: /* SROUND */ 8723 DO_SROUND 8724 break; 8725 8726 case 0x77: /* S45Round */ 8727 DO_S45ROUND 8728 break; 8729 8730 case 0x78: /* JROT */ 8731 DO_JROT 8732 break; 8733 8734 case 0x79: /* JROF */ 8735 DO_JROF 8736 break; 8737 8738 case 0x7A: /* ROFF */ 8739 DO_ROFF 8740 break; 8741 8742 case 0x7B: /* ???? */ 8743 Ins_UNKNOWN( EXEC_ARG_ args ); 8744 break; 8745 8746 case 0x7C: /* RUTG */ 8747 DO_RUTG 8748 break; 8749 8750 case 0x7D: /* RDTG */ 8751 DO_RDTG 8752 break; 8753 8754 case 0x7E: /* SANGW */ 8755 case 0x7F: /* AA */ 8756 /* nothing - obsolete */ 8757 break; 8758 8759 case 0x80: /* FLIPPT */ 8760 Ins_FLIPPT( EXEC_ARG_ args ); 8761 break; 8762 8763 case 0x81: /* FLIPRGON */ 8764 Ins_FLIPRGON( EXEC_ARG_ args ); 8765 break; 8766 8767 case 0x82: /* FLIPRGOFF */ 8768 Ins_FLIPRGOFF( EXEC_ARG_ args ); 8769 break; 8770 8771 case 0x83: /* UNKNOWN */ 8772 case 0x84: /* UNKNOWN */ 8773 Ins_UNKNOWN( EXEC_ARG_ args ); 8774 break; 8775 8776 case 0x85: /* SCANCTRL */ 8777 Ins_SCANCTRL( EXEC_ARG_ args ); 8778 break; 8779 8780 case 0x86: /* SDPVTL */ 8781 case 0x87: /* SDPVTL */ 8782 Ins_SDPVTL( EXEC_ARG_ args ); 8783 break; 8784 8785 case 0x88: /* GETINFO */ 8786 Ins_GETINFO( EXEC_ARG_ args ); 8787 break; 8788 8789 case 0x89: /* IDEF */ 8790 Ins_IDEF( EXEC_ARG_ args ); 8791 break; 8792 8793 case 0x8A: /* ROLL */ 8794 Ins_ROLL( EXEC_ARG_ args ); 8795 break; 8796 8797 case 0x8B: /* MAX */ 8798 DO_MAX 8799 break; 8800 8801 case 0x8C: /* MIN */ 8802 DO_MIN 8803 break; 8804 8805 case 0x8D: /* SCANTYPE */ 8806 Ins_SCANTYPE( EXEC_ARG_ args ); 8807 break; 8808 8809 case 0x8E: /* INSTCTRL */ 8810 Ins_INSTCTRL( EXEC_ARG_ args ); 8811 break; 8812 8813 case 0x8F: 8814 Ins_UNKNOWN( EXEC_ARG_ args ); 8815 break; 8816 8817 default: 8818 if ( opcode >= 0xE0 ) 8819 Ins_MIRP( EXEC_ARG_ args ); 8820 else if ( opcode >= 0xC0 ) 8821 Ins_MDRP( EXEC_ARG_ args ); 8822 else if ( opcode >= 0xB8 ) 8823 Ins_PUSHW( EXEC_ARG_ args ); 8824 else if ( opcode >= 0xB0 ) 8825 Ins_PUSHB( EXEC_ARG_ args ); 8826 else 8827 Ins_UNKNOWN( EXEC_ARG_ args ); 8828 } 8829 8830 } 8831 8832#else 8833 8834 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] ); 8835 8836#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */ 8837 8838 if ( CUR.error ) 8839 { 8840 switch ( CUR.error ) 8841 { 8842 /* looking for redefined instructions */ 8843 case FT_ERR( Invalid_Opcode ): 8844 { 8845 TT_DefRecord* def = CUR.IDefs; 8846 TT_DefRecord* limit = def + CUR.numIDefs; 8847 8848 8849 for ( ; def < limit; def++ ) 8850 { 8851 if ( def->active && CUR.opcode == (FT_Byte)def->opc ) 8852 { 8853 TT_CallRec* callrec; 8854 8855 8856 if ( CUR.callTop >= CUR.callSize ) 8857 { 8858 CUR.error = FT_THROW( Invalid_Reference ); 8859 goto LErrorLabel_; 8860 } 8861 8862 callrec = &CUR.callStack[CUR.callTop]; 8863 8864 callrec->Caller_Range = CUR.curRange; 8865 callrec->Caller_IP = CUR.IP + 1; 8866 callrec->Cur_Count = 1; 8867 callrec->Cur_Restart = def->start; 8868 callrec->Cur_End = def->end; 8869 8870 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE ) 8871 goto LErrorLabel_; 8872 8873 goto LSuiteLabel_; 8874 } 8875 } 8876 } 8877 8878 CUR.error = FT_THROW( Invalid_Opcode ); 8879 goto LErrorLabel_; 8880 8881#if 0 8882 break; /* Unreachable code warning suppression. */ 8883 /* Leave to remind in case a later change the editor */ 8884 /* to consider break; */ 8885#endif 8886 8887 default: 8888 goto LErrorLabel_; 8889 8890#if 0 8891 break; 8892#endif 8893 } 8894 } 8895 8896 CUR.top = CUR.new_top; 8897 8898 if ( CUR.step_ins ) 8899 CUR.IP += CUR.length; 8900 8901 /* increment instruction counter and check if we didn't */ 8902 /* run this program for too long (e.g. infinite loops). */ 8903 if ( ++ins_counter > MAX_RUNNABLE_OPCODES ) 8904 return FT_THROW( Execution_Too_Long ); 8905 8906 LSuiteLabel_: 8907 if ( CUR.IP >= CUR.codeSize ) 8908 { 8909 if ( CUR.callTop > 0 ) 8910 { 8911 CUR.error = FT_THROW( Code_Overflow ); 8912 goto LErrorLabel_; 8913 } 8914 else 8915 goto LNo_Error_; 8916 } 8917 } while ( !CUR.instruction_trap ); 8918 8919 LNo_Error_: 8920 8921#ifdef TT_CONFIG_OPTION_STATIC_RASTER 8922 *exc = cur; 8923#endif 8924 8925 return FT_Err_Ok; 8926 8927 LErrorCodeOverflow_: 8928 CUR.error = FT_THROW( Code_Overflow ); 8929 8930 LErrorLabel_: 8931 8932#ifdef TT_CONFIG_OPTION_STATIC_RASTER 8933 *exc = cur; 8934#endif 8935 8936 /* If any errors have occurred, function tables may be broken. */ 8937 /* Force a re-execution of `prep' and `fpgm' tables if no */ 8938 /* bytecode debugger is run. */ 8939 if ( CUR.error && !CUR.instruction_trap ) 8940 { 8941 FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error )); 8942 exc->size->cvt_ready = FALSE; 8943 } 8944 8945 return CUR.error; 8946 } 8947 8948 8949#endif /* TT_USE_BYTECODE_INTERPRETER */ 8950 8951 8952/* END */ 8953