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