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