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