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