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