1 /* Copyright (C) 2003 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: ttinterp.c,v 1.18 2005/08/02 11:12:32 igor Exp $ */ 18 19 /* Changes after FreeType: cut out the TrueType instruction interpreter. */ 20 /* Patented algorithms are replaced with THROW_PATENTED. */ 21 22 /******************************************************************* 23 * 24 * ttinterp.c 2.3 25 * 26 * TrueType bytecode intepreter. 27 * 28 * Copyright 1996-1998 by 29 * David Turner, Robert Wilhelm, and Werner Lemberg 30 * 31 * This file is part of the FreeType project, and may only be used 32 * modified and distributed under the terms of the FreeType project 33 * license, LICENSE.TXT. By continuing to use, modify, or distribute 34 * this file you indicate that you have read the license and 35 * understand and accept it fully. 36 * 37 * 38 * TODO: 39 * 40 * - Fix the non-square pixel case (or how to manage the CVT to 41 * detect horizontal and vertical scaled FUnits ?) 42 * 43 * 44 * Changes between 2.3 and 2.2: 45 * 46 * - added support for rotation, stretching, instruction control 47 * 48 * - added support for non-square pixels. However, this doesn't 49 * work perfectly yet... 50 * 51 * Changes between 2.2 and 2.1: 52 * 53 * - a small bugfix in the Push opcodes 54 * 55 * Changes between 2.1 and 2.0: 56 * 57 * - created the TTExec component to take care of all execution 58 * context management. The interpreter has now one single 59 * function. 60 * 61 * - made some changes to support re-entrancy. The re-entrant 62 * interpreter is smaller! 63 * 64 ******************************************************************/ 65 66 #include "ttmisc.h" 67 68 #include "ttfoutl.h" 69 #include "tttypes.h" 70 #include "ttcalc.h" 71 #include "ttinterp.h" 72 #include "ttfinp.h" 73 74 75 #ifdef DEBUG 76 # define DBG_PAINT CUR.current_face->font->DebugRepaint(CUR.current_face->font); 77 78 # define DBG_PRT_FUN CUR.current_face->font->DebugPrint 79 # define DBG_PRT (void)(!DBG_PRT_FUN ? 0 : DBG_PRT_FUN(CUR.current_face->font 80 # define DBG_PRINT(fmt) DBG_PRT, fmt)) 81 # define DBG_PRINT1(fmt, a) DBG_PRT, fmt, a)) 82 # define DBG_PRINT3(fmt, a, b, c) DBG_PRT, fmt, a, b, c)) 83 # define DBG_PRINT4(fmt, a, b, c, d) DBG_PRT, fmt, a, b, c, d)) 84 #else 85 # define DBG_PRT_FUN NULL 86 # define DBG_PAINT 87 # define DBG_PRINT(fmt) 88 # define DBG_PRINT1(fmt, a) 89 # define DBG_PRINT3(fmt, a, b, c) 90 # define DBG_PRINT4(fmt, a, b, c, d) 91 #endif 92 93 static int nInstrCount=0; 94 95 96 /* There are two kinds of implementations there: */ 97 /* */ 98 /* a. static implementation: */ 99 /* */ 100 /* The current execution context is a static variable, */ 101 /* which fields are accessed directly by the interpreter */ 102 /* during execution. The context is named 'cur'. */ 103 /* */ 104 /* This version is non-reentrant, of course. */ 105 /* */ 106 /* */ 107 /* b. indirect implementation: */ 108 /* */ 109 /* The current execution context is passed to _each_ */ 110 /* function as its first argument, and each field is */ 111 /* thus accessed indirectly. */ 112 /* */ 113 /* This version is, however, fully re-entrant. */ 114 /* */ 115 /* */ 116 /* The idea is that an indirect implementation may be */ 117 /* slower to execute on the low-end processors that are */ 118 /* used in some systems (like 386s or even 486s). */ 119 /* */ 120 /* When the interpreter started, we had no idea of the */ 121 /* time that glyph hinting (i.e. executing instructions) */ 122 /* could take in the whole process of rendering a glyph, */ 123 /* and a 10 to 30% performance penalty on low-end systems */ 124 /* didn't seem much of a good idea. This question led us */ 125 /* to provide two distinct builds of the C version from */ 126 /* a single source, with the use of macros (again). */ 127 /* */ 128 /* Now that the engine is working (and working really */ 129 /* well!), it seems that the greatest time-consuming */ 130 /* factors are: file i/o, glyph loading, rasterizing and */ 131 /* _then_ glyph hinting! */ 132 /* */ 133 /* Tests performed with two versions of the 'fttimer' */ 134 /* program seem to indicate that hinting takes less than 5% */ 135 /* of the rendering process, which is dominated by glyph */ 136 /* loading and scan-line conversion by an high order of */ 137 /* magnitude. */ 138 /* */ 139 /* As a consequence, the indirect implementation is now the */ 140 /* default, as its performance costs can be considered */ 141 /* negligible in our context. Note, however, that we */ 142 /* kept the same source with macros because: */ 143 /* */ 144 /* - the code is kept very close in design to the */ 145 /* Pascal one used for development. */ 146 /* */ 147 /* - it's much more readable that way! */ 148 /* */ 149 /* - it's still open to later experimentation and tuning */ 150 151 152 #ifndef TT_STATIC_INTERPRETER /* indirect implementation */ 153 154 #define CUR (*exc) /* see ttobjs.h */ 155 156 #else /* static implementation */ 157 158 #define CUR cur 159 160 static TExecution_Context cur; /* static exec. context variable */ 161 162 /* apparently, we have a _lot_ of direct indexing when accessing */ 163 /* the static 'cur', which makes the code bigger (due to all the */ 164 /* four bytes addresses). */ 165 166 #endif 167 168 169 #define INS_ARG EXEC_OPS PStorage args /* see ttexec.h */ 170 171 #define SKIP_Code() SkipCode( EXEC_ARG ) 172 173 #define GET_ShortIns() GetShortIns( EXEC_ARG ) 174 175 #define COMPUTE_Funcs() Compute_Funcs( EXEC_ARG ) 176 177 #define NORMalize( x, y, v ) Normalize( EXEC_ARGS x, y, v ) 178 179 #define SET_SuperRound( scale, flags ) \ 180 SetSuperRound( EXEC_ARGS scale, flags ) 181 182 #define INS_Goto_CodeRange( range, ip ) \ 183 Ins_Goto_CodeRange( EXEC_ARGS range, ip ) 184 185 #define CUR_Func_project( x, y ) CUR.func_project( EXEC_ARGS x, y ) 186 #define CUR_Func_move( z, p, d ) CUR.func_move( EXEC_ARGS z, p, d ) 187 #define CUR_Func_dualproj( x, y ) CUR.func_dualproj( EXEC_ARGS x, y ) 188 #define CUR_Func_freeProj( x, y ) CUR.func_freeProj( EXEC_ARGS x, y ) 189 #define CUR_Func_round( d, c ) CUR.func_round( EXEC_ARGS d, c ) 190 191 #define CUR_Func_read_cvt( index ) \ 192 CUR.func_read_cvt( EXEC_ARGS index ) 193 194 #define CUR_Func_write_cvt( index, val ) \ 195 CUR.func_write_cvt( EXEC_ARGS index, val ) 196 197 #define CUR_Func_move_cvt( index, val ) \ 198 CUR.func_move_cvt( EXEC_ARGS index, val ) 199 200 #define CURRENT_Ratio() Current_Ratio( EXEC_ARG ) 201 #define CURRENT_Ppem() Current_Ppem( EXEC_ARG ) 202 203 #define CALC_Length() Calc_Length( EXEC_ARG ) 204 205 #define INS_SxVTL( a, b, c, d ) Ins_SxVTL( EXEC_ARGS a, b, c, d ) 206 207 #define COMPUTE_Point_Displacement( a, b, c, d ) \ 208 Compute_Point_Displacement( EXEC_ARGS a, b, c, d ) 209 210 #define MOVE_Zp2_Point( a, b, c, t ) Move_Zp2_Point( EXEC_ARGS a, b, c, t ) 211 212 #define CUR_Ppem() Cur_PPEM( EXEC_ARG ) 213 214 /* Instruction dispatch function, as used by the interpreter */ 215 typedef void (*TInstruction_Function)( INS_ARG ); 216 217 #define BOUNDS(x,n) ( x < 0 || x >= n ) 218 219 #ifndef ABS 220 #define ABS(x) ( (x) < 0 ? -(x) : (x) ) 221 #endif 222 223 /* The following macro is used to disable algorithms, 224 which could cause Apple's patent infringement. */ 225 #define THROW_PATENTED longjmp(CUR.trap, TT_Err_Invalid_Engine) 226 227 228 229 /*********************************************************************/ 230 /* */ 231 /* Before an opcode is executed, the interpreter verifies that */ 232 /* there are enough arguments on the stack, with the help of */ 233 /* the Pop_Push_Count table. */ 234 /* */ 235 /* For each opcode, the first column gives the number of arguments */ 236 /* that are popped from the stack; the second one gives the number */ 237 /* of those that are pushed in result. */ 238 /* */ 239 /* Note that for opcodes with a varying number of parameters, */ 240 /* either 0 or 1 arg is verified before execution, depending */ 241 /* on the nature of the instruction: */ 242 /* */ 243 /* - if the number of arguments is given by the bytecode */ 244 /* stream or the loop variable, 0 is chosen. */ 245 /* */ 246 /* - if the first argument is a count n that is followed */ 247 /* by arguments a1..an, then 1 is chosen. */ 248 /* */ 249 /*********************************************************************/ 250 251 static unsigned char Pop_Push_Count[512] = 252 { 253 /* opcodes are gathered in groups of 16 */ 254 /* please keep the spaces as they are */ 255 256 /* SVTCA y */ 0, 0, 257 /* SVTCA x */ 0, 0, 258 /* SPvTCA y */ 0, 0, 259 /* SPvTCA x */ 0, 0, 260 /* SFvTCA y */ 0, 0, 261 /* SFvTCA x */ 0, 0, 262 /* SPvTL // */ 2, 0, 263 /* SPvTL + */ 2, 0, 264 /* SFvTL // */ 2, 0, 265 /* SFvTL + */ 2, 0, 266 /* SPvFS */ 2, 0, 267 /* SFvFS */ 2, 0, 268 /* GPV */ 0, 2, 269 /* GFV */ 0, 2, 270 /* SFvTPv */ 0, 0, 271 /* ISECT */ 5, 0, 272 273 /* SRP0 */ 1, 0, 274 /* SRP1 */ 1, 0, 275 /* SRP2 */ 1, 0, 276 /* SZP0 */ 1, 0, 277 /* SZP1 */ 1, 0, 278 /* SZP2 */ 1, 0, 279 /* SZPS */ 1, 0, 280 /* SLOOP */ 1, 0, 281 /* RTG */ 0, 0, 282 /* RTHG */ 0, 0, 283 /* SMD */ 1, 0, 284 /* ELSE */ 0, 0, 285 /* JMPR */ 1, 0, 286 /* SCvTCi */ 1, 0, 287 /* SSwCi */ 1, 0, 288 /* SSW */ 1, 0, 289 290 /* DUP */ 1, 2, 291 /* POP */ 1, 0, 292 /* CLEAR */ 0, 0, 293 /* SWAP */ 2, 2, 294 /* DEPTH */ 0, 1, 295 /* CINDEX */ 1, 1, 296 /* MINDEX */ 1, 0, 297 /* AlignPTS */ 2, 0, 298 /* INS_$28 */ 0, 0, 299 /* UTP */ 1, 0, 300 /* LOOPCALL */ 2, 0, 301 /* CALL */ 1, 0, 302 /* FDEF */ 1, 0, 303 /* ENDF */ 0, 0, 304 /* MDAP[0] */ 1, 0, 305 /* MDAP[1] */ 1, 0, 306 307 /* IUP[0] */ 0, 0, 308 /* IUP[1] */ 0, 0, 309 /* SHP[0] */ 0, 0, 310 /* SHP[1] */ 0, 0, 311 /* SHC[0] */ 1, 0, 312 /* SHC[1] */ 1, 0, 313 /* SHZ[0] */ 1, 0, 314 /* SHZ[1] */ 1, 0, 315 /* SHPIX */ 1, 0, 316 /* IP */ 0, 0, 317 /* MSIRP[0] */ 2, 0, 318 /* MSIRP[1] */ 2, 0, 319 /* AlignRP */ 0, 0, 320 /* RTDG */ 0, 0, 321 /* MIAP[0] */ 2, 0, 322 /* MIAP[1] */ 2, 0, 323 324 /* NPushB */ 0, 0, 325 /* NPushW */ 0, 0, 326 /* WS */ 2, 0, 327 /* RS */ 1, 1, 328 /* WCvtP */ 2, 0, 329 /* RCvt */ 1, 1, 330 /* GC[0] */ 1, 1, 331 /* GC[1] */ 1, 1, 332 /* SCFS */ 2, 0, 333 /* MD[0] */ 2, 1, 334 /* MD[1] */ 2, 1, 335 /* MPPEM */ 0, 1, 336 /* MPS */ 0, 1, 337 /* FlipON */ 0, 0, 338 /* FlipOFF */ 0, 0, 339 /* DEBUG */ 1, 0, 340 341 /* LT */ 2, 1, 342 /* LTEQ */ 2, 1, 343 /* GT */ 2, 1, 344 /* GTEQ */ 2, 1, 345 /* EQ */ 2, 1, 346 /* NEQ */ 2, 1, 347 /* ODD */ 1, 1, 348 /* EVEN */ 1, 1, 349 /* IF */ 1, 0, 350 /* EIF */ 0, 0, 351 /* AND */ 2, 1, 352 /* OR */ 2, 1, 353 /* NOT */ 1, 1, 354 /* DeltaP1 */ 1, 0, 355 /* SDB */ 1, 0, 356 /* SDS */ 1, 0, 357 358 /* ADD */ 2, 1, 359 /* SUB */ 2, 1, 360 /* DIV */ 2, 1, 361 /* MUL */ 2, 1, 362 /* ABS */ 1, 1, 363 /* NEG */ 1, 1, 364 /* FLOOR */ 1, 1, 365 /* CEILING */ 1, 1, 366 /* ROUND[0] */ 1, 1, 367 /* ROUND[1] */ 1, 1, 368 /* ROUND[2] */ 1, 1, 369 /* ROUND[3] */ 1, 1, 370 /* NROUND[0] */ 1, 1, 371 /* NROUND[1] */ 1, 1, 372 /* NROUND[2] */ 1, 1, 373 /* NROUND[3] */ 1, 1, 374 375 /* WCvtF */ 2, 0, 376 /* DeltaP2 */ 1, 0, 377 /* DeltaP3 */ 1, 0, 378 /* DeltaCn[0] */ 1, 0, 379 /* DeltaCn[1] */ 1, 0, 380 /* DeltaCn[2] */ 1, 0, 381 /* SROUND */ 1, 0, 382 /* S45Round */ 1, 0, 383 /* JROT */ 2, 0, 384 /* JROF */ 2, 0, 385 /* ROFF */ 0, 0, 386 /* INS_$7B */ 0, 0, 387 /* RUTG */ 0, 0, 388 /* RDTG */ 0, 0, 389 /* SANGW */ 1, 0, 390 /* AA */ 1, 0, 391 392 /* FlipPT */ 0, 0, 393 /* FlipRgON */ 2, 0, 394 /* FlipRgOFF */ 2, 0, 395 /* INS_$83 */ 0, 0, 396 /* INS_$84 */ 0, 0, 397 /* ScanCTRL */ 1, 0, 398 /* SDVPTL[0] */ 2, 0, 399 /* SDVPTL[1] */ 2, 0, 400 /* GetINFO */ 1, 1, 401 /* IDEF */ 1, 0, 402 /* ROLL */ 3, 3, 403 /* MAX */ 2, 1, 404 /* MIN */ 2, 1, 405 /* ScanTYPE */ 1, 0, 406 /* InstCTRL */ 2, 0, 407 /* INS_$8F */ 0, 0, 408 409 /* INS_$90 */ 0, 0, 410 /* INS_$91 */ 0, 0, 411 /* INS_$92 */ 0, 0, 412 /* INS_$93 */ 0, 0, 413 /* INS_$94 */ 0, 0, 414 /* INS_$95 */ 0, 0, 415 /* INS_$96 */ 0, 0, 416 /* INS_$97 */ 0, 0, 417 /* INS_$98 */ 0, 0, 418 /* INS_$99 */ 0, 0, 419 /* INS_$9A */ 0, 0, 420 /* INS_$9B */ 0, 0, 421 /* INS_$9C */ 0, 0, 422 /* INS_$9D */ 0, 0, 423 /* INS_$9E */ 0, 0, 424 /* INS_$9F */ 0, 0, 425 426 /* INS_$A0 */ 0, 0, 427 /* INS_$A1 */ 0, 0, 428 /* INS_$A2 */ 0, 0, 429 /* INS_$A3 */ 0, 0, 430 /* INS_$A4 */ 0, 0, 431 /* INS_$A5 */ 0, 0, 432 /* INS_$A6 */ 0, 0, 433 /* INS_$A7 */ 0, 0, 434 /* INS_$A8 */ 0, 0, 435 /* INS_$A9 */ 0, 0, 436 /* INS_$AA */ 0, 0, 437 /* INS_$AB */ 0, 0, 438 /* INS_$AC */ 0, 0, 439 /* INS_$AD */ 0, 0, 440 /* INS_$AE */ 0, 0, 441 /* INS_$AF */ 0, 0, 442 443 /* PushB[0] */ 0, 1, 444 /* PushB[1] */ 0, 2, 445 /* PushB[2] */ 0, 3, 446 /* PushB[3] */ 0, 4, 447 /* PushB[4] */ 0, 5, 448 /* PushB[5] */ 0, 6, 449 /* PushB[6] */ 0, 7, 450 /* PushB[7] */ 0, 8, 451 /* PushW[0] */ 0, 1, 452 /* PushW[1] */ 0, 2, 453 /* PushW[2] */ 0, 3, 454 /* PushW[3] */ 0, 4, 455 /* PushW[4] */ 0, 5, 456 /* PushW[5] */ 0, 6, 457 /* PushW[6] */ 0, 7, 458 /* PushW[7] */ 0, 8, 459 460 /* MDRP[00] */ 1, 0, 461 /* MDRP[01] */ 1, 0, 462 /* MDRP[02] */ 1, 0, 463 /* MDRP[03] */ 1, 0, 464 /* MDRP[04] */ 1, 0, 465 /* MDRP[05] */ 1, 0, 466 /* MDRP[06] */ 1, 0, 467 /* MDRP[07] */ 1, 0, 468 /* MDRP[08] */ 1, 0, 469 /* MDRP[09] */ 1, 0, 470 /* MDRP[10] */ 1, 0, 471 /* MDRP[11] */ 1, 0, 472 /* MDRP[12] */ 1, 0, 473 /* MDRP[13] */ 1, 0, 474 /* MDRP[14] */ 1, 0, 475 /* MDRP[15] */ 1, 0, 476 477 /* MDRP[16] */ 1, 0, 478 /* MDRP[17] */ 1, 0, 479 /* MDRP[18] */ 1, 0, 480 /* MDRP[19] */ 1, 0, 481 /* MDRP[20] */ 1, 0, 482 /* MDRP[21] */ 1, 0, 483 /* MDRP[22] */ 1, 0, 484 /* MDRP[23] */ 1, 0, 485 /* MDRP[24] */ 1, 0, 486 /* MDRP[25] */ 1, 0, 487 /* MDRP[26] */ 1, 0, 488 /* MDRP[27] */ 1, 0, 489 /* MDRP[28] */ 1, 0, 490 /* MDRP[29] */ 1, 0, 491 /* MDRP[30] */ 1, 0, 492 /* MDRP[31] */ 1, 0, 493 494 /* MIRP[00] */ 2, 0, 495 /* MIRP[01] */ 2, 0, 496 /* MIRP[02] */ 2, 0, 497 /* MIRP[03] */ 2, 0, 498 /* MIRP[04] */ 2, 0, 499 /* MIRP[05] */ 2, 0, 500 /* MIRP[06] */ 2, 0, 501 /* MIRP[07] */ 2, 0, 502 /* MIRP[08] */ 2, 0, 503 /* MIRP[09] */ 2, 0, 504 /* MIRP[10] */ 2, 0, 505 /* MIRP[11] */ 2, 0, 506 /* MIRP[12] */ 2, 0, 507 /* MIRP[13] */ 2, 0, 508 /* MIRP[14] */ 2, 0, 509 /* MIRP[15] */ 2, 0, 510 511 /* MIRP[16] */ 2, 0, 512 /* MIRP[17] */ 2, 0, 513 /* MIRP[18] */ 2, 0, 514 /* MIRP[19] */ 2, 0, 515 /* MIRP[20] */ 2, 0, 516 /* MIRP[21] */ 2, 0, 517 /* MIRP[22] */ 2, 0, 518 /* MIRP[23] */ 2, 0, 519 /* MIRP[24] */ 2, 0, 520 /* MIRP[25] */ 2, 0, 521 /* MIRP[26] */ 2, 0, 522 /* MIRP[27] */ 2, 0, 523 /* MIRP[28] */ 2, 0, 524 /* MIRP[29] */ 2, 0, 525 /* MIRP[30] */ 2, 0, 526 /* MIRP[31] */ 2, 0 527 }; 528 529 530 /******************************************************************* 531 * 532 * Function : Norm 533 * 534 * Description : Returns the norm (length) of a vector. 535 * 536 * Input : X, Y vector 537 * 538 * Output : Returns length in F26dot6. 539 * 540 *****************************************************************/ 541 Norm(TT_F26Dot6 X,TT_F26Dot6 Y)542 static TT_F26Dot6 Norm( TT_F26Dot6 X, TT_F26Dot6 Y ) 543 { 544 Int64 T1, T2; 545 546 547 MUL_64( X, X, T1 ); 548 MUL_64( Y, Y, T2 ); 549 550 ADD_64( T1, T2, T1 ); 551 552 return (TT_F26Dot6)SQRT_64( T1 ); 553 } 554 555 556 /******************************************************************* 557 * 558 * Function : FUnits_To_Pixels 559 * 560 * Description : Scale a distance in FUnits to pixel coordinates. 561 * 562 * Input : Distance in FUnits 563 * 564 * Output : Distance in 26.6 format. 565 * 566 *****************************************************************/ 567 FUnits_To_Pixels(EXEC_OPS Int distance)568 static TT_F26Dot6 FUnits_To_Pixels( EXEC_OPS Int distance ) 569 { 570 return MulDiv_Round( distance, 571 CUR.metrics.scale1, 572 CUR.metrics.scale2 ); 573 } 574 575 576 /******************************************************************* 577 * 578 * Function : Current_Ratio 579 * 580 * Description : Return the current aspect ratio scaling factor 581 * depending on the projection vector's state and 582 * device resolutions. 583 * 584 * Input : None 585 * 586 * Output : Aspect ratio in 16.16 format, always <= 1.0 . 587 * 588 *****************************************************************/ 589 Current_Ratio(EXEC_OP)590 static Long Current_Ratio( EXEC_OP ) 591 { 592 if ( CUR.metrics.ratio ) 593 return CUR.metrics.ratio; 594 595 if ( CUR.GS.projVector.y == 0 ) 596 CUR.metrics.ratio = CUR.metrics.x_ratio; 597 598 else if ( CUR.GS.projVector.x == 0 ) 599 CUR.metrics.ratio = CUR.metrics.y_ratio; 600 601 else 602 { 603 Long x, y; 604 605 606 x = MulDiv_Round( CUR.GS.projVector.x, CUR.metrics.x_ratio, 0x4000 ); 607 y = MulDiv_Round( CUR.GS.projVector.y, CUR.metrics.y_ratio, 0x4000 ); 608 CUR.metrics.ratio = Norm( x, y ); 609 } 610 611 return CUR.metrics.ratio; 612 } 613 614 Current_Ppem(EXEC_OP)615 static Int Current_Ppem( EXEC_OP ) 616 { 617 return MulDiv_Round( CUR.metrics.ppem, CURRENT_Ratio(), 0x10000 ); 618 } 619 620 Read_CVT(EXEC_OPS Int index)621 static TT_F26Dot6 Read_CVT( EXEC_OPS Int index ) 622 { 623 return CUR.cvt[index]; 624 } 625 626 Read_CVT_Stretched(EXEC_OPS Int index)627 static TT_F26Dot6 Read_CVT_Stretched( EXEC_OPS Int index ) 628 { 629 return MulDiv_Round( CUR.cvt[index], CURRENT_Ratio(), 0x10000 ); 630 } 631 632 Write_CVT(EXEC_OPS Int index,TT_F26Dot6 value)633 static void Write_CVT( EXEC_OPS Int index, TT_F26Dot6 value ) 634 { 635 int ov=CUR.cvt[index]; 636 CUR.cvt[index] = value; 637 DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]); 638 } 639 Write_CVT_Stretched(EXEC_OPS Int index,TT_F26Dot6 value)640 static void Write_CVT_Stretched( EXEC_OPS Int index, TT_F26Dot6 value ) 641 { 642 int ov=CUR.cvt[index]; 643 CUR.cvt[index] = MulDiv_Round( value, 0x10000, CURRENT_Ratio() ); 644 DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]); 645 } 646 647 Move_CVT(EXEC_OPS Int index,TT_F26Dot6 value)648 static void Move_CVT( EXEC_OPS Int index, TT_F26Dot6 value ) 649 { 650 int ov=CUR.cvt[index]; 651 CUR.cvt[index] += value; 652 DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]); 653 } 654 Move_CVT_Stretched(EXEC_OPS Int index,TT_F26Dot6 value)655 static void Move_CVT_Stretched( EXEC_OPS Int index, TT_F26Dot6 value ) 656 { 657 int ov=CUR.cvt[index]; 658 CUR.cvt[index] += MulDiv_Round( value, 0x10000, CURRENT_Ratio() ); 659 DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]); 660 } 661 662 663 /****************************************************************** 664 * 665 * Function : Calc_Length 666 * 667 * Description : Computes the length in bytes of current opcode. 668 * 669 *****************************************************************/ 670 Calc_Length(EXEC_OP)671 static Bool Calc_Length( EXEC_OP ) 672 { 673 CUR.opcode = CUR.code[CUR.IP]; 674 675 switch ( CUR.opcode ) 676 { 677 case 0x40: 678 if ( CUR.IP + 1 >= CUR.codeSize ) 679 return FAILURE; 680 681 CUR.length = CUR.code[CUR.IP + 1] + 2; 682 break; 683 684 case 0x41: 685 if ( CUR.IP + 1 >= CUR.codeSize ) 686 return FAILURE; 687 688 CUR.length = CUR.code[CUR.IP + 1] * 2 + 2; 689 break; 690 691 case 0xB0: 692 case 0xB1: 693 case 0xB2: 694 case 0xB3: 695 case 0xB4: 696 case 0xB5: 697 case 0xB6: 698 case 0xB7: 699 CUR.length = CUR.opcode - 0xB0 + 2; 700 break; 701 702 case 0xB8: 703 case 0xB9: 704 case 0xBA: 705 case 0xBB: 706 case 0xBC: 707 case 0xBD: 708 case 0xBE: 709 case 0xBF: 710 CUR.length = (CUR.opcode - 0xB8) * 2 + 3; 711 break; 712 713 default: 714 CUR.length = 1; 715 break; 716 } 717 718 /* make sure result is in range */ 719 720 if ( CUR.IP + CUR.length > CUR.codeSize ) 721 return FAILURE; 722 723 return SUCCESS; 724 } 725 726 727 /******************************************************************* 728 * 729 * Function : GetShortIns 730 * 731 * Description : Returns a short integer taken from the instruction 732 * stream at address IP. 733 * 734 * Input : None 735 * 736 * Output : Short read at Code^[IP..IP+1] 737 * 738 * Notes : This one could become a Macro in the C version. 739 * 740 *****************************************************************/ 741 GetShortIns(EXEC_OP)742 static Short GetShortIns( EXEC_OP ) 743 { 744 /* Reading a byte stream so there is no endianess (DaveP) */ 745 CUR.IP += 2; 746 return ( CUR.code[CUR.IP-2] << 8) + 747 CUR.code[CUR.IP-1]; 748 } 749 750 751 /******************************************************************* 752 * 753 * Function : Ins_Goto_CodeRange 754 * 755 * Description : Goes to a certain code range in the instruction 756 * stream. 757 * 758 * 759 * Input : aRange 760 * aIP 761 * 762 * Output : SUCCESS or FAILURE. 763 * 764 *****************************************************************/ 765 Ins_Goto_CodeRange(EXEC_OPS Int aRange,Int aIP)766 static Bool Ins_Goto_CodeRange( EXEC_OPS Int aRange, Int aIP ) 767 { 768 TCodeRange* WITH; 769 770 771 if ( aRange < 1 || aRange > 3 ) 772 { 773 CUR.error = TT_Err_Bad_Argument; 774 return FAILURE; 775 } 776 777 WITH = &CUR.codeRangeTable[aRange - 1]; 778 779 if ( WITH->Base == NULL ) /* invalid coderange */ 780 { 781 CUR.error = TT_Err_Invalid_CodeRange; 782 return FAILURE; 783 } 784 785 /* NOTE: Because the last instruction of a program may be a CALL */ 786 /* which will return to the first byte *after* the code */ 787 /* range, we test for AIP <= Size, instead of AIP < Size. */ 788 789 if ( aIP > WITH->Size ) 790 { 791 CUR.error = TT_Err_Code_Overflow; 792 return FAILURE; 793 } 794 795 CUR.code = WITH->Base; 796 CUR.codeSize = WITH->Size; 797 CUR.IP = aIP; 798 CUR.curRange = aRange; 799 800 return SUCCESS; 801 } 802 803 804 /******************************************************************* 805 * 806 * Function : Direct_Move 807 * 808 * Description : Moves a point by a given distance along the 809 * freedom vector. 810 * 811 * Input : Vx, Vy point coordinates to move 812 * touch touch flag to modify 813 * distance 814 * 815 * Output : None 816 * 817 *****************************************************************/ 818 Direct_Move(EXEC_OPS PGlyph_Zone zone,Int point,TT_F26Dot6 distance)819 static void Direct_Move( EXEC_OPS PGlyph_Zone zone, 820 Int point, 821 TT_F26Dot6 distance ) 822 { 823 TT_F26Dot6 v; 824 825 826 v = CUR.GS.freeVector.x; 827 828 if ( v != 0 ) 829 { 830 zone->cur_x[point] += MulDiv_Round( distance, 831 v * 0x10000L, 832 CUR.F_dot_P ); 833 834 zone->touch[point] |= TT_Flag_Touched_X; 835 } 836 837 v = CUR.GS.freeVector.y; 838 839 if ( v != 0 ) 840 { 841 zone->cur_y[point] += MulDiv_Round( distance, 842 v * 0x10000L, 843 CUR.F_dot_P ); 844 845 zone->touch[point] |= TT_Flag_Touched_Y; 846 } 847 } 848 849 850 /******************************************************************/ 851 /* */ 852 /* The following versions are used whenever both vectors are both */ 853 /* along one of the coordinate unit vectors, i.e. in 90% cases. */ 854 /* */ 855 /******************************************************************/ 856 857 /******************************************************************* 858 * Direct_Move_X 859 * 860 *******************************************************************/ 861 Direct_Move_X(EXEC_OPS PGlyph_Zone zone,Int point,TT_F26Dot6 distance)862 static void Direct_Move_X( EXEC_OPS PGlyph_Zone zone, 863 Int point, 864 TT_F26Dot6 distance ) 865 { (void)exc; 866 zone->cur_x[point] += distance; 867 zone->touch[point] |= TT_Flag_Touched_X; 868 } 869 870 871 /******************************************************************* 872 * Direct_Move_Y 873 * 874 *******************************************************************/ 875 Direct_Move_Y(EXEC_OPS PGlyph_Zone zone,Int point,TT_F26Dot6 distance)876 static void Direct_Move_Y( EXEC_OPS PGlyph_Zone zone, 877 Int point, 878 TT_F26Dot6 distance ) 879 { (void)exc; 880 zone->cur_y[point] += distance; 881 zone->touch[point] |= TT_Flag_Touched_Y; 882 } 883 884 885 /******************************************************************* 886 * 887 * Function : Round_None 888 * 889 * Description : Does not round, but adds engine compensation. 890 * 891 * Input : distance : distance to round 892 * compensation : engine compensation 893 * 894 * Output : rounded distance. 895 * 896 * NOTE : The spec says very few about the relationship between 897 * rounding and engine compensation. However, it seems 898 * from the description of super round that we should 899 * should add the compensation before rounding. 900 * 901 ******************************************************************/ 902 Round_None(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)903 static TT_F26Dot6 Round_None( EXEC_OPS TT_F26Dot6 distance, 904 TT_F26Dot6 compensation ) 905 { 906 TT_F26Dot6 val; 907 (void)exc; 908 909 if ( distance >= 0 ) 910 { 911 val = distance + compensation; 912 if ( val < 0 ) 913 val = 0; 914 } 915 else { 916 val = distance - compensation; 917 if ( val > 0 ) 918 val = 0; 919 } 920 921 return val; 922 } 923 924 925 /******************************************************************* 926 * 927 * Function : Round_To_Grid 928 * 929 * Description : Rounds value to grid after adding engine 930 * compensation 931 * 932 * Input : distance : distance to round 933 * compensation : engine compensation 934 * 935 * Output : Rounded distance. 936 * 937 *****************************************************************/ 938 Round_To_Grid(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)939 static TT_F26Dot6 Round_To_Grid( EXEC_OPS TT_F26Dot6 distance, 940 TT_F26Dot6 compensation ) 941 { 942 TT_F26Dot6 val; 943 (void)exc; 944 945 if ( distance >= 0 ) 946 { 947 val = (distance + compensation + 32) & (-64); 948 if ( val < 0 ) 949 val = 0; 950 } 951 else 952 { 953 val = -( (compensation - distance + 32) & (-64) ); 954 if ( val > 0 ) 955 val = 0; 956 } 957 958 959 return val; 960 } 961 962 963 /******************************************************************* 964 * 965 * Function : Round_To_Half_Grid 966 * 967 * Description : Rounds value to half grid after adding engine 968 * compensation. 969 * 970 * Input : distance : distance to round 971 * compensation : engine compensation 972 * 973 * Output : Rounded distance. 974 * 975 *****************************************************************/ 976 Round_To_Half_Grid(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)977 static TT_F26Dot6 Round_To_Half_Grid( EXEC_OPS TT_F26Dot6 distance, 978 TT_F26Dot6 compensation ) 979 { 980 TT_F26Dot6 val; 981 (void)exc; 982 983 if ( distance >= 0 ) 984 { 985 val = ((distance + compensation) & (-64)) + 32; 986 if ( val < 0 ) 987 val = 0; 988 } 989 else 990 { 991 val = -( ((compensation - distance) & (-64)) + 32 ); 992 if ( val > 0 ) 993 val = 0; 994 } 995 996 return val; 997 } 998 999 1000 /******************************************************************* 1001 * 1002 * Function : Round_Down_To_Grid 1003 * 1004 * Description : Rounds value down to grid after adding engine 1005 * compensation. 1006 * 1007 * Input : distance : distance to round 1008 * compensation : engine compensation 1009 * 1010 * Output : Rounded distance. 1011 * 1012 *****************************************************************/ 1013 Round_Down_To_Grid(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)1014 static TT_F26Dot6 Round_Down_To_Grid( EXEC_OPS TT_F26Dot6 distance, 1015 TT_F26Dot6 compensation ) 1016 { 1017 TT_F26Dot6 val; 1018 (void)exc; 1019 1020 if ( distance >= 0 ) 1021 { 1022 val = (distance + compensation) & (-64); 1023 if ( val < 0 ) 1024 val = 0; 1025 } 1026 else 1027 { 1028 val = -( (compensation - distance) & (-64) ); 1029 if ( val > 0 ) 1030 val = 0; 1031 } 1032 1033 return val; 1034 } 1035 1036 1037 /******************************************************************* 1038 * 1039 * Function : Round_Up_To_Grid 1040 * 1041 * Description : Rounds value up to grid after adding engine 1042 * compensation. 1043 * 1044 * Input : distance : distance to round 1045 * compensation : engine compensation 1046 * 1047 * Output : Rounded distance. 1048 * 1049 *****************************************************************/ 1050 Round_Up_To_Grid(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)1051 static TT_F26Dot6 Round_Up_To_Grid( EXEC_OPS TT_F26Dot6 distance, 1052 TT_F26Dot6 compensation ) 1053 { 1054 TT_F26Dot6 val; 1055 (void)exc; 1056 1057 if ( distance >= 0 ) 1058 { 1059 val = (distance + compensation + 63) & (-64); 1060 if ( val < 0 ) 1061 val = 0; 1062 } 1063 else 1064 { 1065 val = -( (compensation - distance + 63) & (-64) ); 1066 if ( val > 0 ) 1067 val = 0; 1068 } 1069 1070 return val; 1071 } 1072 1073 1074 /******************************************************************* 1075 * 1076 * Function : Round_To_Double_Grid 1077 * 1078 * Description : Rounds value to double grid after adding engine 1079 * compensation. 1080 * 1081 * Input : distance : distance to round 1082 * compensation : engine compensation 1083 * 1084 * Output : Rounded distance. 1085 * 1086 *****************************************************************/ 1087 Round_To_Double_Grid(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)1088 static TT_F26Dot6 Round_To_Double_Grid( EXEC_OPS TT_F26Dot6 distance, 1089 TT_F26Dot6 compensation ) 1090 { 1091 TT_F26Dot6 val; 1092 (void)exc; 1093 1094 if ( distance >= 0 ) 1095 { 1096 val = (distance + compensation + 16) & (-32); 1097 if ( val < 0 ) 1098 val = 0; 1099 } 1100 else 1101 { 1102 val = -( (compensation - distance + 16) & (-32) ); 1103 if ( val > 0 ) 1104 val = 0; 1105 } 1106 1107 return val; 1108 } 1109 1110 1111 /******************************************************************* 1112 * 1113 * Function : Round_Super 1114 * 1115 * Description : Super-rounds value to grid after adding engine 1116 * compensation. 1117 * 1118 * Input : distance : distance to round 1119 * compensation : engine compensation 1120 * 1121 * Output : Rounded distance. 1122 * 1123 * NOTE : The spec says very few about the relationship between 1124 * rounding and engine compensation. However, it seems 1125 * from the description of super round that we should 1126 * should add the compensation before rounding. 1127 * 1128 *****************************************************************/ 1129 Round_Super(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)1130 static TT_F26Dot6 Round_Super( EXEC_OPS TT_F26Dot6 distance, 1131 TT_F26Dot6 compensation ) 1132 { 1133 TT_F26Dot6 val; 1134 1135 1136 if ( distance >= 0 ) 1137 { 1138 val = (distance - CUR.phase + CUR.threshold + compensation) & 1139 (-CUR.period); 1140 if ( val < 0 ) 1141 val = 0; 1142 val += CUR.phase; 1143 } 1144 else 1145 { 1146 val = -( (CUR.threshold - CUR.phase - distance + compensation) & 1147 (-CUR.period) ); 1148 if ( val > 0 ) 1149 val = 0; 1150 val -= CUR.phase; 1151 } 1152 1153 return val; 1154 } 1155 1156 1157 /******************************************************************* 1158 * 1159 * Function : Round_Super_45 1160 * 1161 * Description : Super-rounds value to grid after adding engine 1162 * compensation. 1163 * 1164 * Input : distance : distance to round 1165 * compensation : engine compensation 1166 * 1167 * Output : Rounded distance. 1168 * 1169 * NOTE : There is a separate function for Round_Super_45 as we 1170 * may need a greater precision. 1171 * 1172 *****************************************************************/ 1173 Round_Super_45(EXEC_OPS TT_F26Dot6 distance,TT_F26Dot6 compensation)1174 static TT_F26Dot6 Round_Super_45( EXEC_OPS TT_F26Dot6 distance, 1175 TT_F26Dot6 compensation ) 1176 { 1177 TT_F26Dot6 val; 1178 1179 1180 if ( distance >= 0 ) 1181 { 1182 val = ( (distance - CUR.phase + CUR.threshold + compensation) / 1183 CUR.period ) * CUR.period; 1184 if ( val < 0 ) 1185 val = 0; 1186 val += CUR.phase; 1187 } 1188 else 1189 { 1190 val = -( ( (CUR.threshold - CUR.phase - distance + compensation) / 1191 CUR.period ) * CUR.period ); 1192 if ( val > 0 ) 1193 val = 0; 1194 val -= CUR.phase; 1195 } 1196 1197 return val; 1198 } 1199 1200 1201 /******************************************************************* 1202 * Compute_Round 1203 * 1204 *****************************************************************/ 1205 Compute_Round(EXEC_OPS Byte round_mode)1206 static void Compute_Round( EXEC_OPS Byte round_mode ) 1207 { 1208 switch ( round_mode ) 1209 { 1210 case TT_Round_Off: 1211 CUR.func_round = (TRound_Function)Round_None; 1212 break; 1213 1214 case TT_Round_To_Grid: 1215 CUR.func_round = (TRound_Function)Round_To_Grid; 1216 break; 1217 1218 case TT_Round_Up_To_Grid: 1219 CUR.func_round = (TRound_Function)Round_Up_To_Grid; 1220 break; 1221 1222 case TT_Round_Down_To_Grid: 1223 CUR.func_round = (TRound_Function)Round_Down_To_Grid; 1224 break; 1225 1226 case TT_Round_To_Half_Grid: 1227 CUR.func_round = (TRound_Function)Round_To_Half_Grid; 1228 break; 1229 1230 case TT_Round_To_Double_Grid: 1231 CUR.func_round = (TRound_Function)Round_To_Double_Grid; 1232 break; 1233 1234 case TT_Round_Super: 1235 CUR.func_round = (TRound_Function)Round_Super; 1236 break; 1237 1238 case TT_Round_Super_45: 1239 CUR.func_round = (TRound_Function)Round_Super_45; 1240 break; 1241 } 1242 } 1243 1244 1245 /******************************************************************* 1246 * 1247 * Function : SetSuperRound 1248 * 1249 * Description : Sets Super Round parameters. 1250 * 1251 * Input : GridPeriod Grid period 1252 * OpCode SROUND opcode 1253 * 1254 * Output : None. 1255 * 1256 *****************************************************************/ 1257 SetSuperRound(EXEC_OPS TT_F26Dot6 GridPeriod,Long selector)1258 static void SetSuperRound( EXEC_OPS TT_F26Dot6 GridPeriod, 1259 Long selector ) 1260 { 1261 switch ( selector & 0xC0 ) 1262 { 1263 case 0: 1264 CUR.period = GridPeriod / 2; 1265 break; 1266 1267 case 0x40: 1268 CUR.period = GridPeriod; 1269 break; 1270 1271 case 0x80: 1272 CUR.period = GridPeriod * 2; 1273 break; 1274 1275 /* This opcode is reserved, but... */ 1276 1277 case 0xC0: 1278 CUR.period = GridPeriod; 1279 break; 1280 } 1281 1282 switch ( selector & 0x30 ) 1283 { 1284 case 0: 1285 CUR.phase = 0; 1286 break; 1287 1288 case 0x10: 1289 CUR.phase = CUR.period / 4; 1290 break; 1291 1292 case 0x20: 1293 CUR.phase = CUR.period / 2; 1294 break; 1295 1296 case 0x30: 1297 CUR.phase = GridPeriod * 3 / 4; 1298 break; 1299 } 1300 1301 if ( (selector & 0x0F) == 0 ) 1302 CUR.threshold = CUR.period - 1; 1303 else 1304 CUR.threshold = ( (Int)(selector & 0x0F) - 4L ) * CUR.period / 8; 1305 1306 CUR.period /= 256; 1307 CUR.phase /= 256; 1308 CUR.threshold /= 256; 1309 } 1310 /******************************************************************* 1311 * 1312 * Function : Project 1313 * 1314 * Description : Computes the projection of (Vx,Vy) along the 1315 * current projection vector. 1316 * 1317 * Input : Vx, Vy input vector 1318 * 1319 * Output : Returns distance in F26dot6. 1320 * 1321 *****************************************************************/ 1322 Project(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy)1323 static TT_F26Dot6 Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy ) 1324 { 1325 THROW_PATENTED; 1326 return 0; 1327 } 1328 1329 1330 /******************************************************************* 1331 * 1332 * Function : Dual_Project 1333 * 1334 * Description : Computes the projection of (Vx,Vy) along the 1335 * current dual vector. 1336 * 1337 * Input : Vx, Vy input vector 1338 * 1339 * Output : Returns distance in F26dot6. 1340 * 1341 *****************************************************************/ 1342 Dual_Project(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy)1343 static TT_F26Dot6 Dual_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy ) 1344 { 1345 THROW_PATENTED; 1346 return 0; 1347 } 1348 1349 1350 /******************************************************************* 1351 * 1352 * Function : Free_Project 1353 * 1354 * Description : Computes the projection of (Vx,Vy) along the 1355 * current freedom vector. 1356 * 1357 * Input : Vx, Vy input vector 1358 * 1359 * Output : Returns distance in F26dot6. 1360 * 1361 *****************************************************************/ 1362 Free_Project(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy)1363 static TT_F26Dot6 Free_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy ) 1364 { 1365 THROW_PATENTED; 1366 return 0; 1367 } 1368 1369 1370 1371 /******************************************************************* 1372 * 1373 * Function : Project_x 1374 * 1375 * Input : Vx, Vy input vector 1376 * 1377 * Output : Returns Vx. 1378 * 1379 * Note : Used as a dummy function. 1380 * 1381 *****************************************************************/ 1382 Project_x(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy)1383 static TT_F26Dot6 Project_x( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy ) 1384 { (void)exc; (void)Vy; 1385 return Vx; 1386 } 1387 1388 1389 /******************************************************************* 1390 * 1391 * Function : Project_y 1392 * 1393 * Input : Vx, Vy input vector 1394 * 1395 * Output : Returns Vy. 1396 * 1397 * Note : Used as a dummy function. 1398 * 1399 *****************************************************************/ 1400 Project_y(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy)1401 static TT_F26Dot6 Project_y( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy ) 1402 { (void)exc; (void)Vx; 1403 return Vy; 1404 } 1405 1406 1407 /******************************************************************* 1408 * 1409 * Function : Compute_Funcs 1410 * 1411 * Description : Computes the projections and movement function 1412 * pointers according to the current graphics state. 1413 * 1414 * Input : None 1415 * 1416 *****************************************************************/ 1417 Compute_Funcs(EXEC_OP)1418 static void Compute_Funcs( EXEC_OP ) 1419 { 1420 if ( CUR.GS.freeVector.x == 0x4000 ) 1421 { 1422 CUR.func_freeProj = (TProject_Function)Project_x; 1423 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L; 1424 } 1425 else 1426 { 1427 if ( CUR.GS.freeVector.y == 0x4000 ) 1428 { 1429 CUR.func_freeProj = (TProject_Function)Project_y; 1430 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L; 1431 } 1432 else 1433 { 1434 CUR.func_move = (TMove_Function)Direct_Move; 1435 CUR.func_freeProj = (TProject_Function)Free_Project; 1436 CUR.F_dot_P = (Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 + 1437 (Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4; 1438 } 1439 } 1440 1441 CUR.cached_metrics = FALSE; 1442 1443 if ( CUR.GS.projVector.x == 0x4000 ) 1444 CUR.func_project = (TProject_Function)Project_x; 1445 else 1446 { 1447 if ( CUR.GS.projVector.y == 0x4000 ) 1448 CUR.func_project = (TProject_Function)Project_y; 1449 else 1450 CUR.func_project = (TProject_Function)Project; 1451 } 1452 1453 if ( CUR.GS.dualVector.x == 0x4000 ) 1454 CUR.func_dualproj = (TProject_Function)Project_x; 1455 else 1456 { 1457 if ( CUR.GS.dualVector.y == 0x4000 ) 1458 CUR.func_dualproj = (TProject_Function)Project_y; 1459 else 1460 CUR.func_dualproj = (TProject_Function)Dual_Project; 1461 } 1462 1463 CUR.func_move = (TMove_Function)Direct_Move; 1464 1465 if ( CUR.F_dot_P == 0x40000000L ) 1466 { 1467 if ( CUR.GS.freeVector.x == 0x4000 ) 1468 CUR.func_move = (TMove_Function)Direct_Move_X; 1469 else 1470 { 1471 if ( CUR.GS.freeVector.y == 0x4000 ) 1472 CUR.func_move = (TMove_Function)Direct_Move_Y; 1473 } 1474 } 1475 1476 /* at small sizes, F_dot_P can become too small, resulting */ 1477 /* in overflows and 'spikes' in a number of glyphs like 'w'. */ 1478 1479 if ( ABS( CUR.F_dot_P ) < 0x4000000L ) 1480 CUR.F_dot_P = 0x40000000L; 1481 1482 /* Disable cached aspect ratio */ 1483 CUR.metrics.ratio = 0; 1484 } 1485 1486 /******************************************************************* 1487 * 1488 * Function : Normalize 1489 * 1490 * Description : Norms a vector 1491 * 1492 * Input : Vx, Vy input vector 1493 * R unit vector 1494 * 1495 * Output : Returns FAILURE if a vector parameter is zero. 1496 * 1497 *****************************************************************/ 1498 Normalize(EXEC_OPS TT_F26Dot6 Vx,TT_F26Dot6 Vy,TT_UnitVector * R)1499 static Bool Normalize( EXEC_OPS TT_F26Dot6 Vx, 1500 TT_F26Dot6 Vy, 1501 TT_UnitVector* R ) 1502 { 1503 TT_F26Dot6 W; 1504 Bool S1, S2; 1505 1506 1507 if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L ) 1508 { 1509 Vx *= 0x100; 1510 Vy *= 0x100; 1511 1512 W = Norm( Vx, Vy ); 1513 1514 if ( W == 0 ) 1515 { 1516 /* XXX : Undocumented. It seems that it's possible to try */ 1517 /* to normalize the vector (0,0). Return immediately */ 1518 return SUCCESS; 1519 } 1520 1521 R->x = (TT_F2Dot14)MulDiv_Round( Vx, 0x4000L, W ); 1522 R->y = (TT_F2Dot14)MulDiv_Round( Vy, 0x4000L, W ); 1523 1524 return SUCCESS; 1525 } 1526 1527 W = Norm( Vx, Vy ); 1528 1529 if ( W <= 0 ) 1530 { 1531 CUR.error = TT_Err_Divide_By_Zero; 1532 return FAILURE; 1533 } 1534 1535 Vx = MulDiv_Round( Vx, 0x4000L, W ); 1536 Vy = MulDiv_Round( Vy, 0x4000L, W ); 1537 1538 W = Vx * Vx + Vy * Vy; 1539 1540 /* Now, we want that Sqrt( W ) = 0x4000 */ 1541 /* Or 0x10000000 <= W < 0x10004000 */ 1542 1543 if ( Vx < 0 ) 1544 { 1545 Vx = -Vx; 1546 S1 = TRUE; 1547 } 1548 else 1549 S1 = FALSE; 1550 1551 if ( Vy < 0 ) 1552 { 1553 Vy = -Vy; 1554 S2 = TRUE; 1555 } 1556 else 1557 S2 = FALSE; 1558 1559 while ( W < 0x10000000L ) 1560 { 1561 /* We need to increase W, by a minimal amount */ 1562 if ( Vx < Vy ) 1563 Vx++; 1564 else 1565 Vy++; 1566 1567 W = Vx * Vx + Vy * Vy; 1568 } 1569 1570 while ( W >= 0x10004000L ) 1571 { 1572 /* We need to decrease W, by a minimal amount */ 1573 if ( Vx < Vy ) 1574 Vx--; 1575 else 1576 Vy--; 1577 1578 W = Vx * Vx + Vy * Vy; 1579 } 1580 1581 /* Note that in various cases, we can only */ 1582 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */ 1583 1584 if ( S1 ) 1585 Vx = -Vx; 1586 1587 if ( S2 ) 1588 Vy = -Vy; 1589 1590 R->x = (TT_F2Dot14)Vx; /* Type conversion */ 1591 R->y = (TT_F2Dot14)Vy; /* Type conversion */ 1592 1593 return SUCCESS; 1594 } 1595 1596 1597 1598 /****************************************************************/ 1599 /* */ 1600 /* MANAGING THE STACK */ 1601 /* */ 1602 /* Instructions appear in the specs' order. */ 1603 /* */ 1604 /****************************************************************/ 1605 1606 /*******************************************/ 1607 /* DUP[] : Duplicate top stack element */ 1608 /* CodeRange : $20 */ 1609 Ins_DUP(INS_ARG)1610 static void Ins_DUP( INS_ARG ) 1611 { (void)exc; 1612 args[1] = args[0]; 1613 } 1614 1615 1616 /*******************************************/ 1617 /* POP[] : POPs the stack's top elt. */ 1618 /* CodeRange : $21 */ 1619 Ins_POP(INS_ARG)1620 static void Ins_POP( INS_ARG ) 1621 { (void)exc; (void)args; 1622 /* nothing to do */ 1623 } 1624 1625 1626 /*******************************************/ 1627 /* CLEAR[] : Clear the entire stack */ 1628 /* CodeRange : $22 */ 1629 Ins_CLEAR(INS_ARG)1630 static void Ins_CLEAR( INS_ARG ) 1631 { (void)args; 1632 CUR.new_top = 0; 1633 } 1634 1635 1636 /*******************************************/ 1637 /* SWAP[] : Swap the top two elements */ 1638 /* CodeRange : $23 */ 1639 Ins_SWAP(INS_ARG)1640 static void Ins_SWAP( INS_ARG ) 1641 { 1642 Long L; 1643 (void)exc; 1644 1645 L = args[0]; 1646 args[0] = args[1]; 1647 args[1] = L; 1648 } 1649 1650 1651 /*******************************************/ 1652 /* DEPTH[] : return the stack depth */ 1653 /* CodeRange : $24 */ 1654 Ins_DEPTH(INS_ARG)1655 static void Ins_DEPTH( INS_ARG ) 1656 { 1657 args[0] = CUR.top; 1658 } 1659 1660 1661 /*******************************************/ 1662 /* CINDEX[] : copy indexed element */ 1663 /* CodeRange : $25 */ 1664 Ins_CINDEX(INS_ARG)1665 static void Ins_CINDEX( INS_ARG ) 1666 { 1667 Long L; 1668 1669 1670 L = args[0]; 1671 1672 if ( L<0 || L > CUR.args ) 1673 CUR.error = TT_Err_Invalid_Reference; 1674 else 1675 args[0] = CUR.stack[CUR.args - L]; 1676 } 1677 1678 1679 /*******************************************/ 1680 /* MINDEX[] : move indexed element */ 1681 /* CodeRange : $26 */ 1682 Ins_MINDEX(INS_ARG)1683 static void Ins_MINDEX( INS_ARG ) 1684 { 1685 Long L, K; 1686 1687 1688 L = args[0]; 1689 1690 if ( L<0 || L > CUR.args ) 1691 { 1692 CUR.error = TT_Err_Invalid_Reference; 1693 return; 1694 } 1695 1696 K = CUR.stack[CUR.args - L]; 1697 1698 memmove( (&CUR.stack[CUR.args - L ]), 1699 (&CUR.stack[CUR.args - L + 1]), 1700 (L - 1) * sizeof ( Long ) ); 1701 1702 CUR.stack[ CUR.args-1 ] = K; 1703 } 1704 1705 1706 /*******************************************/ 1707 /* ROLL[] : roll top three elements */ 1708 /* CodeRange : $8A */ 1709 Ins_ROLL(INS_ARG)1710 static void Ins_ROLL( INS_ARG ) 1711 { 1712 Long A, B, C; 1713 (void)exc; 1714 1715 A = args[2]; 1716 B = args[1]; 1717 C = args[0]; 1718 1719 args[2] = C; 1720 args[1] = A; 1721 args[0] = B; 1722 } 1723 1724 1725 1726 /****************************************************************/ 1727 /* */ 1728 /* MANAGING THE FLOW OF CONTROL */ 1729 /* */ 1730 /* Instructions appear in the specs' order. */ 1731 /* */ 1732 /****************************************************************/ 1733 SkipCode(EXEC_OP)1734 static Bool SkipCode( EXEC_OP ) 1735 { 1736 CUR.IP += CUR.length; 1737 1738 if ( CUR.IP < CUR.codeSize ) 1739 if ( CALC_Length() == SUCCESS ) 1740 return SUCCESS; 1741 1742 CUR.error = TT_Err_Code_Overflow; 1743 return FAILURE; 1744 } 1745 1746 1747 /*******************************************/ 1748 /* IF[] : IF test */ 1749 /* CodeRange : $58 */ 1750 Ins_IF(INS_ARG)1751 static void Ins_IF( INS_ARG ) 1752 { 1753 Int nIfs; 1754 Bool Out; 1755 1756 1757 if ( args[0] != 0 ) 1758 return; 1759 1760 nIfs = 1; 1761 Out = 0; 1762 1763 do 1764 { 1765 if ( SKIP_Code() == FAILURE ) 1766 return; 1767 1768 switch ( CUR.opcode ) 1769 { 1770 case 0x58: /* IF */ 1771 nIfs++; 1772 break; 1773 1774 case 0x1b: /* ELSE */ 1775 Out = (nIfs == 1); 1776 break; 1777 1778 case 0x59: /* EIF */ 1779 nIfs--; 1780 Out = (nIfs == 0); 1781 break; 1782 } 1783 } while ( Out == 0 ); 1784 } 1785 1786 1787 /*******************************************/ 1788 /* ELSE[] : ELSE */ 1789 /* CodeRange : $1B */ 1790 Ins_ELSE(INS_ARG)1791 static void Ins_ELSE( INS_ARG ) 1792 { 1793 Int nIfs; 1794 (void)args; 1795 1796 nIfs = 1; 1797 1798 do 1799 { 1800 if ( SKIP_Code() == FAILURE ) 1801 return; 1802 1803 switch ( CUR.opcode ) 1804 { 1805 case 0x58: /* IF */ 1806 nIfs++; 1807 break; 1808 1809 case 0x59: /* EIF */ 1810 nIfs--; 1811 break; 1812 } 1813 } while ( nIfs != 0 ); 1814 } 1815 1816 1817 /*******************************************/ 1818 /* EIF[] : End IF */ 1819 /* CodeRange : $59 */ 1820 Ins_EIF(INS_ARG)1821 static void Ins_EIF( INS_ARG ) 1822 { (void)exc; (void)args; 1823 /* nothing to do */ 1824 } 1825 1826 1827 /*******************************************/ 1828 /* JROT[] : Jump Relative On True */ 1829 /* CodeRange : $78 */ 1830 Ins_JROT(INS_ARG)1831 static void Ins_JROT( INS_ARG ) 1832 { 1833 if ( args[1] != 0 ) 1834 { 1835 CUR.IP += (Int)(args[0]); 1836 CUR.step_ins = FALSE; 1837 } 1838 } 1839 1840 1841 /*******************************************/ 1842 /* JMPR[] : JuMP Relative */ 1843 /* CodeRange : $1C */ 1844 Ins_JMPR(INS_ARG)1845 static void Ins_JMPR( INS_ARG ) 1846 { 1847 CUR.IP += (Int)(args[0]); 1848 CUR.step_ins = FALSE; 1849 } 1850 1851 1852 /*******************************************/ 1853 /* JROF[] : Jump Relative On False */ 1854 /* CodeRange : $79 */ 1855 Ins_JROF(INS_ARG)1856 static void Ins_JROF( INS_ARG ) 1857 { 1858 if ( args[1] == 0 ) 1859 { 1860 CUR.IP += (Int)(args[0]); 1861 CUR.step_ins = FALSE; 1862 } 1863 } 1864 1865 1866 1867 /****************************************************************/ 1868 /* */ 1869 /* LOGICAL FUNCTIONS */ 1870 /* */ 1871 /* Instructions appear in the specs' order. */ 1872 /* */ 1873 /****************************************************************/ 1874 1875 /*******************************************/ 1876 /* LT[] : Less Than */ 1877 /* CodeRange : $50 */ 1878 Ins_LT(INS_ARG)1879 static void Ins_LT( INS_ARG ) 1880 { (void)exc; 1881 if ( args[0] < args[1] ) 1882 args[0] = 1; 1883 else 1884 args[0] = 0; 1885 } 1886 1887 1888 /*******************************************/ 1889 /* LTEQ[] : Less Than or EQual */ 1890 /* CodeRange : $51 */ 1891 Ins_LTEQ(INS_ARG)1892 static void Ins_LTEQ( INS_ARG ) 1893 { (void)exc; 1894 if ( args[0] <= args[1] ) 1895 args[0] = 1; 1896 else 1897 args[0] = 0; 1898 } 1899 1900 1901 /*******************************************/ 1902 /* GT[] : Greater Than */ 1903 /* CodeRange : $52 */ 1904 Ins_GT(INS_ARG)1905 static void Ins_GT( INS_ARG ) 1906 { (void)exc; 1907 if ( args[0] > args[1] ) 1908 args[0] = 1; 1909 else 1910 args[0] = 0; 1911 } 1912 1913 1914 /*******************************************/ 1915 /* GTEQ[] : Greater Than or EQual */ 1916 /* CodeRange : $53 */ 1917 Ins_GTEQ(INS_ARG)1918 static void Ins_GTEQ( INS_ARG ) 1919 { (void)exc; 1920 if ( args[0] >= args[1] ) 1921 args[0] = 1; 1922 else 1923 args[0] = 0; 1924 } 1925 1926 1927 /*******************************************/ 1928 /* EQ[] : EQual */ 1929 /* CodeRange : $54 */ 1930 Ins_EQ(INS_ARG)1931 static void Ins_EQ( INS_ARG ) 1932 { (void)exc; 1933 if ( args[0] == args[1] ) 1934 args[0] = 1; 1935 else 1936 args[0] = 0; 1937 } 1938 1939 1940 /*******************************************/ 1941 /* NEQ[] : Not EQual */ 1942 /* CodeRange : $55 */ 1943 Ins_NEQ(INS_ARG)1944 static void Ins_NEQ( INS_ARG ) 1945 { (void)exc; 1946 if ( args[0] != args[1] ) 1947 args[0] = 1; 1948 else 1949 args[0] = 0; 1950 } 1951 1952 1953 /*******************************************/ 1954 /* ODD[] : Odd */ 1955 /* CodeRange : $56 */ 1956 Ins_ODD(INS_ARG)1957 static void Ins_ODD( INS_ARG ) 1958 { 1959 if ( (CUR_Func_round( args[0], 0L ) & 127) == 64 ) 1960 args[0] = 1; 1961 else 1962 args[0] = 0; 1963 } 1964 1965 1966 /*******************************************/ 1967 /* EVEN[] : Even */ 1968 /* CodeRange : $57 */ 1969 Ins_EVEN(INS_ARG)1970 static void Ins_EVEN( INS_ARG ) 1971 { 1972 if ( (CUR_Func_round( args[0], 0L ) & 127) == 0 ) 1973 args[0] = 1; 1974 else 1975 args[0] = 0; 1976 } 1977 1978 1979 /*******************************************/ 1980 /* AND[] : logical AND */ 1981 /* CodeRange : $5A */ 1982 Ins_AND(INS_ARG)1983 static void Ins_AND( INS_ARG ) 1984 { (void)exc; 1985 if ( args[0] != 0 && args[1] != 0 ) 1986 args[0] = 1; 1987 else 1988 args[0] = 0; 1989 } 1990 1991 1992 /*******************************************/ 1993 /* OR[] : logical OR */ 1994 /* CodeRange : $5B */ 1995 Ins_OR(INS_ARG)1996 static void Ins_OR( INS_ARG ) 1997 { (void)exc; 1998 if ( args[0] != 0 || args[1] != 0 ) 1999 args[0] = 1; 2000 else 2001 args[0] = 0; 2002 } 2003 2004 2005 /*******************************************/ 2006 /* NOT[] : logical NOT */ 2007 /* CodeRange : $5C */ 2008 Ins_NOT(INS_ARG)2009 static void Ins_NOT( INS_ARG ) 2010 { (void)exc; 2011 if ( args[0] != 0 ) 2012 args[0] = 0; 2013 else 2014 args[0] = 1; 2015 } 2016 2017 2018 2019 /****************************************************************/ 2020 /* */ 2021 /* ARITHMETIC AND MATH INSTRUCTIONS */ 2022 /* */ 2023 /* Instructions appear in the specs' order. */ 2024 /* */ 2025 /****************************************************************/ 2026 2027 /*******************************************/ 2028 /* ADD[] : ADD */ 2029 /* CodeRange : $60 */ 2030 Ins_ADD(INS_ARG)2031 static void Ins_ADD( INS_ARG ) 2032 { (void)exc; 2033 args[0] += args[1]; 2034 } 2035 2036 2037 /*******************************************/ 2038 /* SUB[] : SUBstract */ 2039 /* CodeRange : $61 */ 2040 Ins_SUB(INS_ARG)2041 static void Ins_SUB( INS_ARG ) 2042 { (void)exc; 2043 args[0] -= args[1]; 2044 } 2045 2046 2047 /*******************************************/ 2048 /* DIV[] : DIVide */ 2049 /* CodeRange : $62 */ 2050 Ins_DIV(INS_ARG)2051 static void Ins_DIV( INS_ARG ) 2052 { 2053 if ( args[1] == 0 ) 2054 { 2055 CUR.error = TT_Err_Divide_By_Zero; 2056 return; 2057 } 2058 2059 args[0] = MulDiv_Round( args[0], 64L, args[1] ); 2060 DBG_PRINT1(" %d", args[0]); 2061 } 2062 2063 2064 /*******************************************/ 2065 /* MUL[] : MULtiply */ 2066 /* CodeRange : $63 */ 2067 Ins_MUL(INS_ARG)2068 static void Ins_MUL( INS_ARG ) 2069 { (void)exc; 2070 args[0] = MulDiv_Round( args[0], args[1], 64L ); 2071 } 2072 2073 2074 /*******************************************/ 2075 /* ABS[] : ABSolute value */ 2076 /* CodeRange : $64 */ 2077 Ins_ABS(INS_ARG)2078 static void Ins_ABS( INS_ARG ) 2079 { (void)exc; 2080 args[0] = ABS( args[0] ); 2081 } 2082 2083 2084 /*******************************************/ 2085 /* NEG[] : NEGate */ 2086 /* CodeRange : $65 */ 2087 Ins_NEG(INS_ARG)2088 static void Ins_NEG( INS_ARG ) 2089 { (void)exc; 2090 args[0] = -args[0]; 2091 } 2092 2093 2094 /*******************************************/ 2095 /* FLOOR[] : FLOOR */ 2096 /* CodeRange : $66 */ 2097 Ins_FLOOR(INS_ARG)2098 static void Ins_FLOOR( INS_ARG ) 2099 { (void)exc; 2100 args[0] &= -64; 2101 } 2102 2103 2104 /*******************************************/ 2105 /* CEILING[] : CEILING */ 2106 /* CodeRange : $67 */ 2107 Ins_CEILING(INS_ARG)2108 static void Ins_CEILING( INS_ARG ) 2109 { (void)exc; 2110 args[0] = (args[0] + 63) & (-64); 2111 } 2112 2113 2114 /*******************************************/ 2115 /* MAX[] : MAXimum */ 2116 /* CodeRange : $68 */ 2117 Ins_MAX(INS_ARG)2118 static void Ins_MAX( INS_ARG ) 2119 { (void)exc; 2120 if ( args[1] > args[0] ) 2121 args[0] = args[1]; 2122 } 2123 2124 2125 /*******************************************/ 2126 /* MIN[] : MINimum */ 2127 /* CodeRange : $69 */ 2128 Ins_MIN(INS_ARG)2129 static void Ins_MIN( INS_ARG ) 2130 { (void)exc; 2131 if ( args[1] < args[0] ) 2132 args[0] = args[1]; 2133 } 2134 2135 2136 2137 /****************************************************************/ 2138 /* */ 2139 /* COMPENSATING FOR THE ENGINE CHARACTERISTICS */ 2140 /* */ 2141 /* Instructions appear in the specs' order. */ 2142 /* */ 2143 /****************************************************************/ 2144 2145 /*******************************************/ 2146 /* ROUND[ab] : ROUND value */ 2147 /* CodeRange : $68-$6B */ 2148 Ins_ROUND(INS_ARG)2149 static void Ins_ROUND( INS_ARG ) 2150 { 2151 args[0] = CUR_Func_round( args[0], 2152 CUR.metrics.compensations[CUR.opcode - 0x68] ); 2153 } 2154 2155 2156 /*******************************************/ 2157 /* NROUND[ab]: No ROUNDing of value */ 2158 /* CodeRange : $6C-$6F */ 2159 Ins_NROUND(INS_ARG)2160 static void Ins_NROUND( INS_ARG ) 2161 { 2162 args[0] = Round_None( EXEC_ARGS 2163 args[0], 2164 CUR.metrics.compensations[CUR.opcode - 0x6C] ); 2165 } 2166 2167 2168 2169 /****************************************************************/ 2170 /* */ 2171 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ 2172 /* */ 2173 /* Instructions appear in the specs' order. */ 2174 /* */ 2175 /****************************************************************/ 2176 2177 /* Skip the whole function definition. */ skip_FDEF(EXEC_OP)2178 static void skip_FDEF( EXEC_OP ) 2179 { 2180 /* We don't allow nested IDEFS & FDEFs. */ 2181 2182 while ( SKIP_Code() == SUCCESS ) 2183 { 2184 switch ( CUR.opcode ) 2185 { 2186 case 0x89: /* IDEF */ 2187 case 0x2c: /* FDEF */ 2188 CUR.error = TT_Err_Nested_DEFS; 2189 return; 2190 2191 case 0x2d: /* ENDF */ 2192 return; 2193 } 2194 } 2195 } 2196 2197 /*******************************************/ 2198 /* FDEF[] : Function DEFinition */ 2199 /* CodeRange : $2C */ 2200 Ins_FDEF(INS_ARG)2201 static void Ins_FDEF( INS_ARG ) 2202 { 2203 PDefRecord pRec; 2204 2205 2206 if ( BOUNDS( args[0], CUR.numFDefs ) ) 2207 { 2208 CUR.error = TT_Err_Invalid_Reference; 2209 return; 2210 } 2211 2212 pRec = &CUR.FDefs[args[0]]; 2213 2214 pRec->Range = CUR.curRange; 2215 pRec->Opc = (Byte)(args[0]); 2216 pRec->Start = CUR.IP + 1; 2217 pRec->Active = TRUE; 2218 2219 skip_FDEF(EXEC_ARG); 2220 } 2221 2222 2223 /*******************************************/ 2224 /* ENDF[] : END Function definition */ 2225 /* CodeRange : $2D */ 2226 Ins_ENDF(INS_ARG)2227 static void Ins_ENDF( INS_ARG ) 2228 { 2229 PCallRecord pRec; 2230 (void)args; 2231 2232 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */ 2233 { 2234 CUR.error = TT_Err_ENDF_In_Exec_Stream; 2235 return; 2236 } 2237 2238 CUR.callTop--; 2239 2240 pRec = &CUR.callStack[CUR.callTop]; 2241 2242 pRec->Cur_Count--; 2243 2244 CUR.step_ins = FALSE; 2245 2246 if ( pRec->Cur_Count > 0 ) 2247 { 2248 CUR.callTop++; 2249 CUR.IP = pRec->Cur_Restart; 2250 } 2251 else 2252 /* Loop through the current function */ 2253 INS_Goto_CodeRange( pRec->Caller_Range, 2254 pRec->Caller_IP ); 2255 2256 /* Exit the current call frame. */ 2257 2258 /* NOTE: When the last intruction of a program */ 2259 /* is a CALL or LOOPCALL, the return address */ 2260 /* is always out of the code range. This is */ 2261 /* a valid address, and it's why we do not test */ 2262 /* the result of Ins_Goto_CodeRange() here! */ 2263 } 2264 2265 2266 /*******************************************/ 2267 /* CALL[] : CALL function */ 2268 /* CodeRange : $2B */ 2269 Ins_CALL(INS_ARG)2270 static void Ins_CALL( INS_ARG ) 2271 { 2272 PCallRecord pCrec; 2273 2274 2275 if ( BOUNDS( args[0], CUR.numFDefs ) || !CUR.FDefs[args[0]].Active ) 2276 { 2277 CUR.error = TT_Err_Invalid_Reference; 2278 return; 2279 } 2280 2281 if ( CUR.callTop >= CUR.callSize ) 2282 { 2283 CUR.error = TT_Err_Stack_Overflow; 2284 return; 2285 } 2286 2287 DBG_PRINT1("%d", args[0]); 2288 2289 pCrec = &CUR.callStack[CUR.callTop]; 2290 2291 pCrec->Caller_Range = CUR.curRange; 2292 pCrec->Caller_IP = CUR.IP + 1; 2293 pCrec->Cur_Count = 1; 2294 pCrec->Cur_Restart = CUR.FDefs[args[0]].Start; 2295 2296 CUR.callTop++; 2297 2298 INS_Goto_CodeRange( CUR.FDefs[args[0]].Range, 2299 CUR.FDefs[args[0]].Start ); 2300 2301 CUR.step_ins = FALSE; 2302 } 2303 2304 2305 /*******************************************/ 2306 /* LOOPCALL[]: LOOP and CALL function */ 2307 /* CodeRange : $2A */ 2308 Ins_LOOPCALL(INS_ARG)2309 static void Ins_LOOPCALL( INS_ARG ) 2310 { 2311 PCallRecord pTCR; 2312 2313 if ( BOUNDS( args[1], CUR.numFDefs ) || !CUR.FDefs[args[1]].Active ) 2314 { 2315 CUR.error = TT_Err_Invalid_Reference; 2316 return; 2317 } 2318 2319 if ( CUR.callTop >= CUR.callSize ) 2320 { 2321 CUR.error = TT_Err_Stack_Overflow; 2322 return; 2323 } 2324 2325 if ( args[0] > 0 ) 2326 { 2327 pTCR = &CUR.callStack[CUR.callTop]; 2328 2329 pTCR->Caller_Range = CUR.curRange; 2330 pTCR->Caller_IP = CUR.IP + 1; 2331 pTCR->Cur_Count = (Int)(args[0]); 2332 pTCR->Cur_Restart = CUR.FDefs[args[1]].Start; 2333 2334 CUR.callTop++; 2335 2336 INS_Goto_CodeRange( CUR.FDefs[args[1]].Range, 2337 CUR.FDefs[args[1]].Start ); 2338 2339 CUR.step_ins = FALSE; 2340 } 2341 } 2342 2343 2344 /*******************************************/ 2345 /* IDEF[] : Instruction DEFinition */ 2346 /* CodeRange : $89 */ 2347 Ins_IDEF(INS_ARG)2348 static void Ins_IDEF( INS_ARG ) 2349 { 2350 if (CUR.countIDefs >= CUR.numIDefs || args[0] > 255) 2351 CUR.error = TT_Err_Storage_Overflow; 2352 else 2353 { 2354 PDefRecord pTDR; 2355 2356 CUR.IDefPtr[(Byte)(args[0])] = CUR.countIDefs; 2357 pTDR = &CUR.IDefs[CUR.countIDefs++]; 2358 pTDR->Opc = (Byte)(args[0]); 2359 pTDR->Start = CUR.IP + 1; 2360 pTDR->Range = CUR.curRange; 2361 pTDR->Active = TRUE; 2362 skip_FDEF(EXEC_ARG); 2363 } 2364 } 2365 2366 2367 2368 /****************************************************************/ 2369 /* */ 2370 /* PUSHING DATA ONTO THE INTERPRETER STACK */ 2371 /* */ 2372 /* Instructions appear in the specs' order. */ 2373 /* */ 2374 /****************************************************************/ 2375 2376 /*******************************************/ 2377 /* NPUSHB[] : PUSH N Bytes */ 2378 /* CodeRange : $40 */ 2379 Ins_NPUSHB(INS_ARG)2380 static void Ins_NPUSHB( INS_ARG ) 2381 { 2382 Int L, K; 2383 2384 L = (Int)CUR.code[CUR.IP + 1]; 2385 2386 if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) ) 2387 { 2388 CUR.error = TT_Err_Stack_Overflow; 2389 return; 2390 } 2391 2392 for ( K = 1; K <= L; K++ ) 2393 { args[K - 1] = CUR.code[CUR.IP + K + 1]; 2394 DBG_PRINT1(" %d", args[K - 1]); 2395 } 2396 2397 CUR.new_top += L; 2398 } 2399 2400 2401 /*******************************************/ 2402 /* NPUSHW[] : PUSH N Words */ 2403 /* CodeRange : $41 */ 2404 Ins_NPUSHW(INS_ARG)2405 static void Ins_NPUSHW( INS_ARG ) 2406 { 2407 Int L, K; 2408 2409 2410 L = (Int)CUR.code[CUR.IP + 1]; 2411 2412 if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) ) 2413 { 2414 CUR.error = TT_Err_Stack_Overflow; 2415 return; 2416 } 2417 2418 CUR.IP += 2; 2419 2420 for ( K = 0; K < L; K++ ) 2421 { args[K] = GET_ShortIns(); 2422 DBG_PRINT1(" %d", args[K]); 2423 } 2424 2425 CUR.step_ins = FALSE; 2426 CUR.new_top += L; 2427 } 2428 2429 2430 /*******************************************/ 2431 /* PUSHB[abc]: PUSH Bytes */ 2432 /* CodeRange : $B0-$B7 */ 2433 Ins_PUSHB(INS_ARG)2434 static void Ins_PUSHB( INS_ARG ) 2435 { 2436 Int L, K; 2437 2438 L = ((Int)CUR.opcode - 0xB0 + 1); 2439 2440 if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) ) 2441 { 2442 CUR.error = TT_Err_Stack_Overflow; 2443 return; 2444 } 2445 2446 for ( K = 1; K <= L; K++ ) 2447 { args[K - 1] = CUR.code[CUR.IP + K]; 2448 DBG_PRINT1(" %d", args[K - 1]); 2449 } 2450 } 2451 2452 2453 /*******************************************/ 2454 /* PUSHW[abc]: PUSH Words */ 2455 /* CodeRange : $B8-$BF */ 2456 Ins_PUSHW(INS_ARG)2457 static void Ins_PUSHW( INS_ARG ) 2458 { 2459 Int L, K; 2460 2461 2462 L = CUR.opcode - 0xB8 + 1; 2463 2464 if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) ) 2465 { 2466 CUR.error = TT_Err_Stack_Overflow; 2467 return; 2468 } 2469 2470 CUR.IP++; 2471 2472 for ( K = 0; K < L; K++ ) 2473 { args[K] = GET_ShortIns(); 2474 DBG_PRINT1(" %d", args[K]); 2475 } 2476 2477 CUR.step_ins = FALSE; 2478 } 2479 2480 2481 2482 /****************************************************************/ 2483 /* */ 2484 /* MANAGING THE STORAGE AREA */ 2485 /* */ 2486 /* Instructions appear in the specs' order. */ 2487 /* */ 2488 /****************************************************************/ 2489 2490 /*******************************************/ 2491 /* RS[] : Read Store */ 2492 /* CodeRange : $43 */ 2493 Ins_RS(INS_ARG)2494 static void Ins_RS( INS_ARG ) 2495 { 2496 if ( BOUNDS( args[0], CUR.storeSize ) ) 2497 { 2498 CUR.error = TT_Err_Invalid_Reference; 2499 return; 2500 } 2501 2502 args[0] = CUR.storage[args[0]]; 2503 } 2504 2505 2506 /*******************************************/ 2507 /* WS[] : Write Store */ 2508 /* CodeRange : $42 */ 2509 Ins_WS(INS_ARG)2510 static void Ins_WS( INS_ARG ) 2511 { 2512 if ( BOUNDS( args[0], CUR.storeSize ) ) 2513 { 2514 CUR.error = TT_Err_Invalid_Reference; 2515 return; 2516 } 2517 2518 CUR.storage[args[0]] = args[1]; 2519 } 2520 2521 2522 /*******************************************/ 2523 /* WCVTP[] : Write CVT in Pixel units */ 2524 /* CodeRange : $44 */ 2525 Ins_WCVTP(INS_ARG)2526 static void Ins_WCVTP( INS_ARG ) 2527 { 2528 if ( BOUNDS( args[0], CUR.cvtSize ) ) 2529 { 2530 CUR.error = TT_Err_Invalid_Reference; 2531 return; 2532 } 2533 2534 CUR_Func_write_cvt( args[0], args[1] ); 2535 } 2536 2537 2538 /*******************************************/ 2539 /* WCVTF[] : Write CVT in FUnits */ 2540 /* CodeRange : $70 */ 2541 Ins_WCVTF(INS_ARG)2542 static void Ins_WCVTF( INS_ARG ) 2543 { 2544 int ov; 2545 2546 if ( BOUNDS( args[0], CUR.cvtSize ) ) 2547 { 2548 CUR.error = TT_Err_Invalid_Reference; 2549 return; 2550 } 2551 2552 ov = CUR.cvt[args[0]]; 2553 CUR.cvt[args[0]] = FUnits_To_Pixels( EXEC_ARGS args[1] ); 2554 DBG_PRINT3(" cvt[%d]%d:=%d", args[0], ov, CUR.cvt[args[0]]); 2555 } 2556 2557 2558 /*******************************************/ 2559 /* RCVT[] : Read CVT */ 2560 /* CodeRange : $45 */ 2561 Ins_RCVT(INS_ARG)2562 static void Ins_RCVT( INS_ARG ) 2563 { 2564 int index; 2565 if ( BOUNDS( args[0], CUR.cvtSize ) ) 2566 { 2567 #if 0 2568 CUR.error = TT_Err_Invalid_Reference; 2569 return; 2570 #else 2571 /* A workaround for the Ghostscript Bug 687604. 2572 Ported from FreeType 2 : !FT_LOAD_PEDANTIC by default. */ 2573 index=args[0]; 2574 args[0] = 0; 2575 DBG_PRINT1(" cvt[%d] stubbed with 0", index); 2576 #endif 2577 } 2578 index=args[0]; 2579 args[0] = CUR_Func_read_cvt( index ); 2580 DBG_PRINT3(" cvt[%d]%d:%d", index, CUR.cvt[index], args[0]); 2581 } 2582 2583 2584 2585 /****************************************************************/ 2586 /* */ 2587 /* MANAGING THE GRAPHICS STATE */ 2588 /* */ 2589 /* Instructions appear in the specs' order. */ 2590 /* */ 2591 /****************************************************************/ 2592 2593 /*******************************************/ 2594 /* SVTCA[a] : Set F and P vectors to axis */ 2595 /* CodeRange : $00-$01 */ 2596 Ins_SVTCA(INS_ARG)2597 static void Ins_SVTCA( INS_ARG ) 2598 { 2599 Short A, B; 2600 (void)args; 2601 2602 if ( CUR.opcode & 1 ) 2603 A = 0x4000; 2604 else 2605 A = 0; 2606 2607 B = A ^ 0x4000; 2608 2609 CUR.GS.freeVector.x = A; 2610 CUR.GS.projVector.x = A; 2611 CUR.GS.dualVector.x = A; 2612 2613 CUR.GS.freeVector.y = B; 2614 CUR.GS.projVector.y = B; 2615 CUR.GS.dualVector.y = B; 2616 2617 COMPUTE_Funcs(); 2618 } 2619 2620 2621 /*******************************************/ 2622 /* SPVTCA[a] : Set PVector to Axis */ 2623 /* CodeRange : $02-$03 */ 2624 Ins_SPVTCA(INS_ARG)2625 static void Ins_SPVTCA( INS_ARG ) 2626 { 2627 Short A, B; 2628 (void)args; 2629 if ( CUR.opcode & 1 ) 2630 A = 0x4000; 2631 else 2632 A = 0; 2633 2634 B = A ^ 0x4000; 2635 2636 CUR.GS.projVector.x = A; 2637 CUR.GS.dualVector.x = A; 2638 2639 CUR.GS.projVector.y = B; 2640 CUR.GS.dualVector.y = B; 2641 2642 COMPUTE_Funcs(); 2643 } 2644 2645 2646 /*******************************************/ 2647 /* SFVTCA[a] : Set FVector to Axis */ 2648 /* CodeRange : $04-$05 */ 2649 Ins_SFVTCA(INS_ARG)2650 static void Ins_SFVTCA( INS_ARG ) 2651 { 2652 Short A, B; 2653 (void)args; 2654 2655 if ( CUR.opcode & 1 ) 2656 A = 0x4000; 2657 else 2658 A = 0; 2659 2660 B = A ^ 0x4000; 2661 2662 CUR.GS.freeVector.x = A; 2663 CUR.GS.freeVector.y = B; 2664 2665 COMPUTE_Funcs(); 2666 } 2667 2668 Ins_SxVTL(EXEC_OPS Int aIdx1,Int aIdx2,Int aOpc,TT_UnitVector * Vec)2669 static Bool Ins_SxVTL( EXEC_OPS Int aIdx1, 2670 Int aIdx2, 2671 Int aOpc, 2672 TT_UnitVector* Vec ) 2673 { 2674 Long A, B, C; 2675 2676 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) || 2677 BOUNDS( aIdx2, CUR.zp1.n_points ) ) 2678 { 2679 CUR.error = TT_Err_Invalid_Reference; 2680 return FAILURE; 2681 } 2682 2683 A = CUR.zp1.cur_x[aIdx2] - CUR.zp2.cur_x[aIdx1]; 2684 B = CUR.zp1.cur_y[aIdx2] - CUR.zp2.cur_y[aIdx1]; 2685 2686 if ( (aOpc & 1) != 0 ) 2687 { 2688 C = B; /* CounterClockwise rotation */ 2689 B = A; 2690 A = -C; 2691 } 2692 2693 if ( NORMalize( A, B, Vec ) == FAILURE ) 2694 { 2695 /* When the vector is too small or zero! */ 2696 2697 CUR.error = TT_Err_Ok; 2698 Vec->x = 0x4000; 2699 Vec->y = 0; 2700 } 2701 2702 return SUCCESS; 2703 } 2704 2705 2706 /*******************************************/ 2707 /* SPVTL[a] : Set PVector to Line */ 2708 /* CodeRange : $06-$07 */ 2709 Ins_SPVTL(INS_ARG)2710 static void Ins_SPVTL( INS_ARG ) 2711 { 2712 if ( INS_SxVTL( args[1], 2713 args[0], 2714 CUR.opcode, 2715 &CUR.GS.projVector) == FAILURE ) 2716 return; 2717 2718 CUR.GS.dualVector = CUR.GS.projVector; 2719 COMPUTE_Funcs(); 2720 } 2721 2722 2723 /*******************************************/ 2724 /* SFVTL[a] : Set FVector to Line */ 2725 /* CodeRange : $08-$09 */ 2726 Ins_SFVTL(INS_ARG)2727 static void Ins_SFVTL( INS_ARG ) 2728 { 2729 if ( INS_SxVTL( (Int)(args[1]), 2730 (Int)(args[0]), 2731 CUR.opcode, 2732 &CUR.GS.freeVector) == FAILURE ) 2733 return; 2734 2735 COMPUTE_Funcs(); 2736 } 2737 2738 2739 /*******************************************/ 2740 /* SFVTPV[] : Set FVector to PVector */ 2741 /* CodeRange : $0E */ 2742 Ins_SFVTPV(INS_ARG)2743 static void Ins_SFVTPV( INS_ARG ) 2744 { (void)args; 2745 CUR.GS.freeVector = CUR.GS.projVector; 2746 COMPUTE_Funcs(); 2747 } 2748 2749 2750 /*******************************************/ 2751 /* SDPVTL[a] : Set Dual PVector to Line */ 2752 /* CodeRange : $86-$87 */ 2753 Ins_SDPVTL(INS_ARG)2754 static void Ins_SDPVTL( INS_ARG ) 2755 { 2756 Long A, B, C; 2757 Long p1, p2; /* was Int in pas type ERROR */ 2758 2759 2760 p1 = args[1]; 2761 p2 = args[0]; 2762 2763 if ( BOUNDS( p2, CUR.zp1.n_points ) || 2764 BOUNDS( p1, CUR.zp2.n_points ) ) 2765 { 2766 CUR.error = TT_Err_Invalid_Reference; 2767 return; 2768 } 2769 2770 A = CUR.zp1.org_x[p2] - CUR.zp2.org_x[p1]; 2771 B = CUR.zp1.org_y[p2] - CUR.zp2.org_y[p1]; 2772 2773 if ( (CUR.opcode & 1) != 0 ) 2774 { 2775 C = B; /* CounterClockwise rotation */ 2776 B = A; 2777 A = -C; 2778 } 2779 2780 if ( NORMalize( A, B, &CUR.GS.dualVector ) == FAILURE ) 2781 return; 2782 2783 A = CUR.zp1.cur_x[p2] - CUR.zp2.cur_x[p1]; 2784 B = CUR.zp1.cur_y[p2] - CUR.zp2.cur_y[p1]; 2785 2786 if ( (CUR.opcode & 1) != 0 ) 2787 { 2788 C = B; /* CounterClockwise rotation */ 2789 B = A; 2790 A = -C; 2791 } 2792 2793 if ( NORMalize( A, B, &CUR.GS.projVector ) == FAILURE ) 2794 return; 2795 2796 COMPUTE_Funcs(); 2797 } 2798 2799 2800 /*******************************************/ 2801 /* SPVFS[] : Set PVector From Stack */ 2802 /* CodeRange : $0A */ 2803 Ins_SPVFS(INS_ARG)2804 static void Ins_SPVFS( INS_ARG ) 2805 { 2806 Short S; 2807 Long X, Y; 2808 2809 2810 /* Only use low 16bits, then sign extend */ 2811 S = (Short)args[1]; 2812 Y = (Long)S; 2813 S = (Short)args[0]; 2814 X = (Long)S; 2815 2816 if ( NORMalize( X, Y, &CUR.GS.projVector ) == FAILURE ) 2817 return; 2818 2819 CUR.GS.dualVector = CUR.GS.projVector; 2820 2821 COMPUTE_Funcs(); 2822 } 2823 2824 2825 /*******************************************/ 2826 /* SFVFS[] : Set FVector From Stack */ 2827 /* CodeRange : $0B */ 2828 Ins_SFVFS(INS_ARG)2829 static void Ins_SFVFS( INS_ARG ) 2830 { 2831 Short S; 2832 Long X, Y; 2833 2834 2835 /* Only use low 16bits, then sign extend */ 2836 S = (Short)args[1]; 2837 Y = (Long)S; 2838 S = (Short)args[0]; 2839 X = S; 2840 2841 if ( NORMalize( X, Y, &CUR.GS.freeVector ) == FAILURE ) 2842 return; 2843 2844 COMPUTE_Funcs(); 2845 } 2846 2847 2848 /*******************************************/ 2849 /* GPV[] : Get Projection Vector */ 2850 /* CodeRange : $0C */ 2851 Ins_GPV(INS_ARG)2852 static void Ins_GPV( INS_ARG ) 2853 { 2854 args[0] = CUR.GS.projVector.x; 2855 args[1] = CUR.GS.projVector.y; 2856 } 2857 2858 2859 /*******************************************/ 2860 /* GFV[] : Get Freedom Vector */ 2861 /* CodeRange : $0D */ 2862 Ins_GFV(INS_ARG)2863 static void Ins_GFV( INS_ARG ) 2864 { 2865 args[0] = CUR.GS.freeVector.x; 2866 args[1] = CUR.GS.freeVector.y; 2867 } 2868 2869 2870 /*******************************************/ 2871 /* SRP0[] : Set Reference Point 0 */ 2872 /* CodeRange : $10 */ 2873 Ins_SRP0(INS_ARG)2874 static void Ins_SRP0( INS_ARG ) 2875 { 2876 CUR.GS.rp0 = (Int)(args[0]); 2877 } 2878 2879 2880 /*******************************************/ 2881 /* SRP1[] : Set Reference Point 1 */ 2882 /* CodeRange : $11 */ 2883 Ins_SRP1(INS_ARG)2884 static void Ins_SRP1( INS_ARG ) 2885 { 2886 CUR.GS.rp1 = (Int)(args[0]); 2887 } 2888 2889 2890 /*******************************************/ 2891 /* SRP2[] : Set Reference Point 2 */ 2892 /* CodeRange : $12 */ 2893 Ins_SRP2(INS_ARG)2894 static void Ins_SRP2( INS_ARG ) 2895 { 2896 CUR.GS.rp2 = (Int)(args[0]); 2897 } 2898 2899 2900 /*******************************************/ 2901 /* SZP0[] : Set Zone Pointer 0 */ 2902 /* CodeRange : $13 */ 2903 Ins_SZP0(INS_ARG)2904 static void Ins_SZP0( INS_ARG ) 2905 { 2906 switch ( args[0] ) 2907 { 2908 case 0: 2909 CUR.zp0 = CUR.twilight; 2910 break; 2911 2912 case 1: 2913 CUR.zp0 = CUR.pts; 2914 break; 2915 2916 default: 2917 CUR.error = TT_Err_Invalid_Reference; 2918 return; 2919 break; 2920 } 2921 2922 CUR.GS.gep0 = (Int)(args[0]); 2923 } 2924 2925 2926 /*******************************************/ 2927 /* SZP1[] : Set Zone Pointer 1 */ 2928 /* CodeRange : $14 */ 2929 Ins_SZP1(INS_ARG)2930 static void Ins_SZP1( INS_ARG ) 2931 { 2932 switch ( args[0] ) 2933 { 2934 case 0: 2935 CUR.zp1 = CUR.twilight; 2936 break; 2937 2938 case 1: 2939 CUR.zp1 = CUR.pts; 2940 break; 2941 2942 default: 2943 CUR.error = TT_Err_Invalid_Reference; 2944 return; 2945 } 2946 2947 CUR.GS.gep1 = (Int)(args[0]); 2948 } 2949 2950 2951 /*******************************************/ 2952 /* SZP2[] : Set Zone Pointer 2 */ 2953 /* CodeRange : $15 */ 2954 Ins_SZP2(INS_ARG)2955 static void Ins_SZP2( INS_ARG ) 2956 { 2957 switch ( args[0] ) 2958 { 2959 case 0: 2960 CUR.zp2 = CUR.twilight; 2961 break; 2962 2963 case 1: 2964 CUR.zp2 = CUR.pts; 2965 break; 2966 2967 default: 2968 CUR.error = TT_Err_Invalid_Reference; 2969 return; 2970 } 2971 2972 CUR.GS.gep2 = (Int)(args[0]); 2973 } 2974 2975 2976 /*******************************************/ 2977 /* SZPS[] : Set Zone Pointers */ 2978 /* CodeRange : $16 */ 2979 Ins_SZPS(INS_ARG)2980 static void Ins_SZPS( INS_ARG ) 2981 { 2982 switch ( args[0] ) 2983 { 2984 case 0: 2985 CUR.zp0 = CUR.twilight; 2986 break; 2987 2988 case 1: 2989 CUR.zp0 = CUR.pts; 2990 break; 2991 2992 default: 2993 CUR.error = TT_Err_Invalid_Reference; 2994 return; 2995 } 2996 2997 CUR.zp1 = CUR.zp0; 2998 CUR.zp2 = CUR.zp0; 2999 3000 CUR.GS.gep0 = (Int)(args[0]); 3001 CUR.GS.gep1 = (Int)(args[0]); 3002 CUR.GS.gep2 = (Int)(args[0]); 3003 } 3004 3005 3006 /*******************************************/ 3007 /* RTHG[] : Round To Half Grid */ 3008 /* CodeRange : $19 */ 3009 Ins_RTHG(INS_ARG)3010 static void Ins_RTHG( INS_ARG ) 3011 { (void)args; 3012 CUR.GS.round_state = TT_Round_To_Half_Grid; 3013 3014 CUR.func_round = (TRound_Function)Round_To_Half_Grid; 3015 } 3016 3017 3018 /*******************************************/ 3019 /* RTG[] : Round To Grid */ 3020 /* CodeRange : $18 */ 3021 Ins_RTG(INS_ARG)3022 static void Ins_RTG( INS_ARG ) 3023 { (void)args; 3024 CUR.GS.round_state = TT_Round_To_Grid; 3025 3026 CUR.func_round = (TRound_Function)Round_To_Grid; 3027 } 3028 3029 3030 /*******************************************/ 3031 /* RTDG[] : Round To Double Grid */ 3032 /* CodeRange : $3D */ 3033 Ins_RTDG(INS_ARG)3034 static void Ins_RTDG( INS_ARG ) 3035 { (void)args; 3036 CUR.GS.round_state = TT_Round_To_Double_Grid; 3037 3038 CUR.func_round = (TRound_Function)Round_To_Double_Grid; 3039 } 3040 3041 3042 /*******************************************/ 3043 /* RUTG[] : Round Up To Grid */ 3044 /* CodeRange : $7C */ 3045 Ins_RUTG(INS_ARG)3046 static void Ins_RUTG( INS_ARG ) 3047 { (void)args; 3048 CUR.GS.round_state = TT_Round_Up_To_Grid; 3049 3050 CUR.func_round = (TRound_Function)Round_Up_To_Grid; 3051 } 3052 3053 3054 /*******************************************/ 3055 /* RDTG[] : Round Down To Grid */ 3056 /* CodeRange : $7D */ 3057 Ins_RDTG(INS_ARG)3058 static void Ins_RDTG( INS_ARG ) 3059 { (void)args; 3060 CUR.GS.round_state = TT_Round_Down_To_Grid; 3061 3062 CUR.func_round = (TRound_Function)Round_Down_To_Grid; 3063 } 3064 3065 3066 /*******************************************/ 3067 /* ROFF[] : Round OFF */ 3068 /* CodeRange : $7A */ 3069 Ins_ROFF(INS_ARG)3070 static void Ins_ROFF( INS_ARG ) 3071 { (void)args; 3072 CUR.GS.round_state = TT_Round_Off; 3073 3074 CUR.func_round = (TRound_Function)Round_None; 3075 } 3076 3077 3078 /*******************************************/ 3079 /* SROUND[] : Super ROUND */ 3080 /* CodeRange : $76 */ 3081 Ins_SROUND(INS_ARG)3082 static void Ins_SROUND( INS_ARG ) 3083 { 3084 SET_SuperRound( 0x4000L, args[0] ); 3085 CUR.GS.round_state = TT_Round_Super; 3086 3087 CUR.func_round = (TRound_Function)Round_Super; 3088 } 3089 3090 3091 /*******************************************/ 3092 /* S45ROUND[]: Super ROUND 45 degrees */ 3093 /* CodeRange : $77 */ 3094 Ins_S45ROUND(INS_ARG)3095 static void Ins_S45ROUND( INS_ARG ) 3096 { 3097 SET_SuperRound( 0x2D41L, args[0] ); 3098 CUR.GS.round_state = TT_Round_Super_45; 3099 3100 CUR.func_round = (TRound_Function)Round_Super_45; 3101 } 3102 3103 3104 /*******************************************/ 3105 /* SLOOP[] : Set LOOP variable */ 3106 /* CodeRange : $17 */ 3107 Ins_SLOOP(INS_ARG)3108 static void Ins_SLOOP( INS_ARG ) 3109 { 3110 CUR.GS.loop = args[0]; 3111 } 3112 3113 3114 /*******************************************/ 3115 /* SMD[] : Set Minimum Distance */ 3116 /* CodeRange : $1A */ 3117 Ins_SMD(INS_ARG)3118 static void Ins_SMD( INS_ARG ) 3119 { 3120 CUR.GS.minimum_distance = args[0]; 3121 } 3122 3123 3124 /*******************************************/ 3125 /* INSTCTRL[]: INSTruction ConTRol */ 3126 /* CodeRange : $8e */ 3127 Ins_INSTCTRL(INS_ARG)3128 static void Ins_INSTCTRL( INS_ARG ) 3129 { 3130 Long K, L; 3131 3132 3133 K = args[1]; 3134 L = args[0]; 3135 3136 if ( K < 0 || K > 3 ) 3137 { 3138 CUR.error = TT_Err_Invalid_Reference; 3139 return; 3140 } 3141 3142 CUR.GS.instruct_control = (Int)((CUR.GS.instruct_control & (~K)) | (L & K)); 3143 } 3144 3145 3146 /*******************************************/ 3147 /* SCANCTRL[]: SCAN ConTRol */ 3148 /* CodeRange : $85 */ 3149 Ins_SCANCTRL(INS_ARG)3150 static void Ins_SCANCTRL( INS_ARG ) 3151 { 3152 Int A; 3153 3154 3155 /* Get Threshold */ 3156 A = (Int)(args[0] & 0xFF); 3157 3158 if ( A == 0xFF ) 3159 { 3160 CUR.GS.scan_control = TRUE; 3161 return; 3162 } 3163 else if ( A == 0 ) 3164 { 3165 CUR.GS.scan_control = FALSE; 3166 return; 3167 } 3168 3169 A *= 64; 3170 3171 if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A ) 3172 CUR.GS.scan_control = TRUE; 3173 3174 if ( (args[0] & 0x200) != 0 && CUR.metrics.rotated ) 3175 CUR.GS.scan_control = TRUE; 3176 3177 if ( (args[0] & 0x400) != 0 && CUR.metrics.stretched ) 3178 CUR.GS.scan_control = TRUE; 3179 3180 if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A ) 3181 CUR.GS.scan_control = FALSE; 3182 3183 if ( (args[0] & 0x1000) != 0 && CUR.metrics.rotated ) 3184 CUR.GS.scan_control = FALSE; 3185 3186 if ( (args[0] & 0x2000) != 0 && CUR.metrics.stretched ) 3187 CUR.GS.scan_control = FALSE; 3188 } 3189 3190 3191 /*******************************************/ 3192 /* SCANTYPE[]: SCAN TYPE */ 3193 /* CodeRange : $8D */ 3194 Ins_SCANTYPE(INS_ARG)3195 static void Ins_SCANTYPE( INS_ARG ) 3196 { 3197 /* For compatibility with future enhancements, */ 3198 /* we must ignore new modes */ 3199 3200 if ( args[0] >= 0 && args[0] <= 5 ) 3201 { 3202 if ( args[0] == 3 ) 3203 args[0] = 2; 3204 3205 CUR.GS.scan_type = (Int)args[0]; 3206 } 3207 } 3208 3209 3210 /**********************************************/ 3211 /* SCVTCI[] : Set Control Value Table Cut In */ 3212 /* CodeRange : $1D */ 3213 Ins_SCVTCI(INS_ARG)3214 static void Ins_SCVTCI( INS_ARG ) 3215 { 3216 CUR.GS.control_value_cutin = (TT_F26Dot6)args[0]; 3217 } 3218 3219 3220 /**********************************************/ 3221 /* SSWCI[] : Set Single Width Cut In */ 3222 /* CodeRange : $1E */ 3223 Ins_SSWCI(INS_ARG)3224 static void Ins_SSWCI( INS_ARG ) 3225 { 3226 CUR.GS.single_width_cutin = (TT_F26Dot6)args[0]; 3227 } 3228 3229 3230 /**********************************************/ 3231 /* SSW[] : Set Single Width */ 3232 /* CodeRange : $1F */ 3233 Ins_SSW(INS_ARG)3234 static void Ins_SSW( INS_ARG ) 3235 { 3236 /* XXX : Undocumented or bug in the Windows engine ? */ 3237 /* */ 3238 /* It seems that the value that is read here is */ 3239 /* expressed in 16.16 format, rather than in */ 3240 /* font units.. */ 3241 /* */ 3242 CUR.GS.single_width_value = (TT_F26Dot6)(args[0] >> 10); 3243 } 3244 3245 3246 /**********************************************/ 3247 /* FLIPON[] : Set Auto_flip to On */ 3248 /* CodeRange : $4D */ 3249 Ins_FLIPON(INS_ARG)3250 static void Ins_FLIPON( INS_ARG ) 3251 { (void)args; 3252 CUR.GS.auto_flip = TRUE; 3253 } 3254 3255 3256 /**********************************************/ 3257 /* FLIPOFF[] : Set Auto_flip to Off */ 3258 /* CodeRange : $4E */ 3259 Ins_FLIPOFF(INS_ARG)3260 static void Ins_FLIPOFF( INS_ARG ) 3261 { (void)args; 3262 CUR.GS.auto_flip = FALSE; 3263 } 3264 3265 3266 /**********************************************/ 3267 /* SANGW[] : Set Angle Weight */ 3268 /* CodeRange : $7E */ 3269 Ins_SANGW(INS_ARG)3270 static void Ins_SANGW( INS_ARG ) 3271 { (void)exc; (void)args; 3272 /* instruction not supported anymore */ 3273 } 3274 3275 3276 /**********************************************/ 3277 /* SDB[] : Set Delta Base */ 3278 /* CodeRange : $5E */ 3279 Ins_SDB(INS_ARG)3280 static void Ins_SDB( INS_ARG ) 3281 { 3282 CUR.GS.delta_base = (Int)args[0]; 3283 } 3284 3285 3286 /**********************************************/ 3287 /* SDS[] : Set Delta Shift */ 3288 /* CodeRange : $5F */ 3289 Ins_SDS(INS_ARG)3290 static void Ins_SDS( INS_ARG ) 3291 { 3292 CUR.GS.delta_shift = (Int)args[0]; 3293 } 3294 3295 3296 /**********************************************/ 3297 /* GC[a] : Get Coordinate projected onto */ 3298 /* CodeRange : $46-$47 */ 3299 3300 /* BULLSHIT: Measures from the original glyph must to be taken */ 3301 /* along the dual projection vector! */ 3302 Ins_GC(INS_ARG)3303 static void Ins_GC( INS_ARG ) 3304 { 3305 Long L; 3306 3307 3308 L = args[0]; 3309 3310 if ( BOUNDS( L, CUR.zp2.n_points ) ) 3311 { 3312 CUR.error = TT_Err_Invalid_Reference; 3313 return; 3314 } 3315 3316 switch ( CUR.opcode & 1 ) 3317 { 3318 case 0: 3319 L = CUR_Func_project( CUR.zp2.cur_x[L], 3320 CUR.zp2.cur_y[L] ); 3321 break; 3322 3323 case 1: 3324 L = CUR_Func_dualproj( CUR.zp2.org_x[L], 3325 CUR.zp2.org_y[L] ); 3326 break; 3327 } 3328 3329 args[0] = L; 3330 } 3331 3332 3333 /**********************************************/ 3334 /* SCFS[] : Set Coordinate From Stack */ 3335 /* CodeRange : $48 */ 3336 /* */ 3337 /* Formula: */ 3338 /* */ 3339 /* OA := OA + ( value - OA.p )/( f.p ) * f */ 3340 /* */ 3341 Ins_SCFS(INS_ARG)3342 static void Ins_SCFS( INS_ARG ) 3343 { 3344 Long K; 3345 Int L; 3346 3347 3348 L = (Int)args[0]; 3349 3350 if ( BOUNDS( args[0], CUR.zp2.n_points ) ) 3351 { 3352 CUR.error = TT_Err_Invalid_Reference; 3353 return; 3354 } 3355 3356 K = CUR_Func_project( CUR.zp2.cur_x[L], 3357 CUR.zp2.cur_y[L] ); 3358 3359 CUR_Func_move( &CUR.zp2, L, args[1] - K ); 3360 3361 /* not part of the specs, but here for safety */ 3362 3363 if ( CUR.GS.gep2 == 0 ) 3364 { 3365 CUR.zp2.org_x[L] = CUR.zp2.cur_x[L]; 3366 CUR.zp2.org_y[L] = CUR.zp2.cur_y[L]; 3367 } 3368 } 3369 3370 3371 /**********************************************/ 3372 /* MD[a] : Measure Distance */ 3373 /* CodeRange : $49-$4A */ 3374 3375 /* BULLSHIT: Measure taken in the original glyph must be along */ 3376 /* the dual projection vector. */ 3377 3378 /* Second BULLSHIT: Flag attributes are inverted! */ 3379 /* 0 => measure distance in original outline */ 3380 /* 1 => measure distance in grid-fitted outline */ 3381 Ins_MD(INS_ARG)3382 static void Ins_MD( INS_ARG ) 3383 { 3384 Long K, L; 3385 TT_F26Dot6 D; 3386 3387 K = args[1]; 3388 L = args[0]; 3389 3390 if( BOUNDS( args[0], CUR.zp2.n_points ) || 3391 BOUNDS( args[1], CUR.zp1.n_points ) ) 3392 { 3393 CUR.error = TT_Err_Invalid_Reference; 3394 return; 3395 } 3396 3397 if ( CUR.opcode & 1 ) 3398 D = CUR_Func_project( CUR.zp2.cur_x[L] - CUR.zp1.cur_x[K], 3399 CUR.zp2.cur_y[L] - CUR.zp1.cur_y[K] ); 3400 else 3401 D = CUR_Func_dualproj( CUR.zp2.org_x[L] - CUR.zp1.org_x[K], 3402 CUR.zp2.org_y[L] - CUR.zp1.org_y[K] ); 3403 3404 args[0] = D; 3405 } 3406 3407 3408 /**********************************************/ 3409 /* MPPEM[] : Measure Pixel Per EM */ 3410 /* CodeRange : $4B */ 3411 Ins_MPPEM(INS_ARG)3412 static void Ins_MPPEM( INS_ARG ) 3413 { 3414 args[0] = CURRENT_Ppem(); 3415 DBG_PRINT1(" %d", args[0]); 3416 } 3417 3418 3419 /**********************************************/ 3420 /* MPS[] : Measure PointSize */ 3421 /* CodeRange : $4C */ 3422 Ins_MPS(INS_ARG)3423 static void Ins_MPS( INS_ARG ) 3424 { 3425 args[0] = CUR.metrics.pointSize; 3426 } 3427 3428 3429 3430 /****************************************************************/ 3431 /* */ 3432 /* MANAGING OUTLINES */ 3433 /* */ 3434 /* Instructions appear in the specs' order. */ 3435 /* */ 3436 /****************************************************************/ 3437 3438 /**********************************************/ 3439 /* FLIPPT[] : FLIP PoinT */ 3440 /* CodeRange : $80 */ 3441 Ins_FLIPPT(INS_ARG)3442 static void Ins_FLIPPT( INS_ARG ) 3443 { 3444 Long point; 3445 (void)args; 3446 3447 if ( CUR.top < CUR.GS.loop ) 3448 { 3449 CUR.error = TT_Err_Too_Few_Arguments; 3450 return; 3451 } 3452 3453 while ( CUR.GS.loop > 0 ) 3454 { 3455 CUR.args--; 3456 3457 point = CUR.stack[CUR.args]; 3458 3459 if ( BOUNDS( point, CUR.pts.n_points ) ) 3460 { 3461 CUR.error = TT_Err_Invalid_Reference; 3462 return; 3463 } 3464 3465 CUR.pts.touch[point] ^= TT_Flag_On_Curve; 3466 3467 CUR.GS.loop--; 3468 } 3469 3470 CUR.GS.loop = 1; 3471 CUR.new_top = CUR.args; 3472 } 3473 3474 3475 /**********************************************/ 3476 /* FLIPRGON[]: FLIP RanGe ON */ 3477 /* CodeRange : $81 */ 3478 Ins_FLIPRGON(INS_ARG)3479 static void Ins_FLIPRGON( INS_ARG ) 3480 { 3481 Long I, K, L; 3482 3483 3484 K = args[1]; 3485 L = args[0]; 3486 3487 if ( BOUNDS( K, CUR.pts.n_points ) || 3488 BOUNDS( L, CUR.pts.n_points ) ) 3489 { 3490 CUR.error = TT_Err_Invalid_Reference; 3491 return; 3492 } 3493 3494 for ( I = L; I <= K; I++ ) 3495 CUR.pts.touch[I] |= TT_Flag_On_Curve; 3496 } 3497 3498 3499 /**********************************************/ 3500 /* FLIPRGOFF : FLIP RanGe OFF */ 3501 /* CodeRange : $82 */ 3502 Ins_FLIPRGOFF(INS_ARG)3503 static void Ins_FLIPRGOFF( INS_ARG ) 3504 { 3505 Long I, K, L; 3506 3507 3508 K = args[1]; 3509 L = args[0]; 3510 3511 if ( BOUNDS( K, CUR.pts.n_points ) || 3512 BOUNDS( L, CUR.pts.n_points ) ) 3513 { 3514 CUR.error = TT_Err_Invalid_Reference; 3515 return; 3516 } 3517 3518 for ( I = L; I <= K; I++ ) 3519 CUR.pts.touch[I] &= ~TT_Flag_On_Curve; 3520 } 3521 3522 Compute_Point_Displacement(EXEC_OPS PCoordinates x,PCoordinates y,PGlyph_Zone zone,Int * refp)3523 static Bool Compute_Point_Displacement( EXEC_OPS 3524 PCoordinates x, 3525 PCoordinates y, 3526 PGlyph_Zone zone, 3527 Int* refp ) 3528 { 3529 TGlyph_Zone zp; 3530 Int p; 3531 TT_F26Dot6 d; 3532 3533 3534 if ( CUR.opcode & 1 ) 3535 { 3536 zp = CUR.zp0; 3537 p = CUR.GS.rp1; 3538 } 3539 else 3540 { 3541 zp = CUR.zp1; 3542 p = CUR.GS.rp2; 3543 } 3544 3545 if ( BOUNDS( p, zp.n_points ) ) 3546 { 3547 CUR.error = TT_Err_Invalid_Displacement; 3548 return FAILURE; 3549 } 3550 3551 *zone = zp; 3552 *refp = p; 3553 3554 d = CUR_Func_project( zp.cur_x[p] - zp.org_x[p], 3555 zp.cur_y[p] - zp.org_y[p] ); 3556 3557 *x = MulDiv_Round(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P ); 3558 *y = MulDiv_Round(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P ); 3559 3560 return SUCCESS; 3561 } 3562 3563 Move_Zp2_Point(EXEC_OPS Long point,TT_F26Dot6 dx,TT_F26Dot6 dy,Bool touch)3564 static void Move_Zp2_Point( EXEC_OPS 3565 Long point, 3566 TT_F26Dot6 dx, 3567 TT_F26Dot6 dy, 3568 Bool touch ) 3569 { 3570 if ( CUR.GS.freeVector.x != 0 ) 3571 { 3572 CUR.zp2.cur_x[point] += dx; 3573 if ( touch ) 3574 CUR.zp2.touch[point] |= TT_Flag_Touched_X; 3575 } 3576 3577 if ( CUR.GS.freeVector.y != 0 ) 3578 { 3579 CUR.zp2.cur_y[point] += dy; 3580 if ( touch ) 3581 CUR.zp2.touch[point] |= TT_Flag_Touched_Y; 3582 } 3583 } 3584 3585 3586 /**********************************************/ 3587 /* SHP[a] : SHift Point by the last point */ 3588 /* CodeRange : $32-33 */ 3589 Ins_SHP(INS_ARG)3590 static void Ins_SHP( INS_ARG ) 3591 { 3592 TGlyph_Zone zp; 3593 Int refp; 3594 3595 TT_F26Dot6 dx, 3596 dy; 3597 Long point; 3598 (void)args; 3599 3600 if ( CUR.top < CUR.GS.loop ) 3601 { 3602 CUR.error = TT_Err_Invalid_Reference; 3603 return; 3604 } 3605 3606 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 3607 return; 3608 3609 while ( CUR.GS.loop > 0 ) 3610 { 3611 CUR.args--; 3612 point = CUR.stack[CUR.args]; 3613 3614 if ( BOUNDS( point, CUR.zp2.n_points ) ) 3615 { 3616 CUR.error = TT_Err_Invalid_Reference; 3617 return; 3618 } 3619 3620 /* undocumented: SHP touches the points */ 3621 MOVE_Zp2_Point( point, dx, dy, TRUE ); 3622 3623 CUR.GS.loop--; 3624 } 3625 3626 CUR.GS.loop = 1; 3627 CUR.new_top = CUR.args; 3628 } 3629 3630 3631 /**********************************************/ 3632 /* SHC[a] : SHift Contour */ 3633 /* CodeRange : $34-35 */ 3634 Ins_SHC(INS_ARG)3635 static void Ins_SHC( INS_ARG ) 3636 { 3637 TGlyph_Zone zp; 3638 Int refp; 3639 TT_F26Dot6 dx, 3640 dy; 3641 3642 Long contour, i; 3643 Int first_point, last_point; 3644 3645 3646 contour = args[0]; 3647 3648 if ( BOUNDS( args[0], CUR.pts.n_contours ) ) 3649 { 3650 CUR.error = TT_Err_Invalid_Reference; 3651 return; 3652 } 3653 3654 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 3655 return; 3656 3657 if ( contour == 0 ) 3658 first_point = 0; 3659 else 3660 first_point = CUR.pts.contours[contour-1] + 1; 3661 3662 last_point = CUR.pts.contours[contour]; 3663 3664 /* undocumented: SHC doesn't touch the points */ 3665 for ( i = first_point; i <= last_point; i++ ) 3666 { 3667 if ( zp.cur_x != CUR.zp2.cur_x || refp != i ) 3668 MOVE_Zp2_Point( i, dx, dy, FALSE ); 3669 } 3670 } 3671 3672 3673 /**********************************************/ 3674 /* SHZ[a] : SHift Zone */ 3675 /* CodeRange : $36-37 */ 3676 Ins_SHZ(INS_ARG)3677 static void Ins_SHZ( INS_ARG ) 3678 { 3679 TGlyph_Zone zp; 3680 Int refp; 3681 TT_F26Dot6 dx, 3682 dy; 3683 3684 Int last_point; 3685 Long i; 3686 3687 3688 if ( BOUNDS( args[0], 2 ) ) 3689 { 3690 CUR.error = TT_Err_Invalid_Reference; 3691 return; 3692 } 3693 3694 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) 3695 return; 3696 3697 last_point = zp.n_points - 1; 3698 3699 /* undocumented: SHZ doesn't touch the points */ 3700 for ( i = 0; i <= last_point; i++ ) 3701 { 3702 if ( zp.cur_x != CUR.zp2.cur_x || refp != i ) 3703 MOVE_Zp2_Point( i, dx, dy, FALSE ); 3704 } 3705 } 3706 3707 3708 /**********************************************/ 3709 /* SHPIX[] : SHift points by a PIXel amount */ 3710 /* CodeRange : $38 */ 3711 Ins_SHPIX(INS_ARG)3712 static void Ins_SHPIX( INS_ARG ) 3713 { 3714 TT_F26Dot6 dx, dy; 3715 Long point; 3716 3717 3718 if ( CUR.top < CUR.GS.loop ) 3719 { 3720 CUR.error = TT_Err_Invalid_Reference; 3721 return; 3722 } 3723 3724 dx = MulDiv_Round( args[0], 3725 (Long)CUR.GS.freeVector.x, 3726 0x4000 ); 3727 dy = MulDiv_Round( args[0], 3728 (Long)CUR.GS.freeVector.y, 3729 0x4000 ); 3730 3731 while ( CUR.GS.loop > 0 ) 3732 { 3733 CUR.args--; 3734 3735 point = CUR.stack[CUR.args]; 3736 3737 if ( BOUNDS( point, CUR.zp2.n_points ) ) 3738 { 3739 CUR.error = TT_Err_Invalid_Reference; 3740 return; 3741 } 3742 3743 MOVE_Zp2_Point( point, dx, dy, TRUE ); 3744 3745 CUR.GS.loop--; 3746 } 3747 3748 CUR.GS.loop = 1; 3749 CUR.new_top = CUR.args; 3750 } 3751 3752 3753 /**********************************************/ 3754 /* MSIRP[a] : Move Stack Indirect Relative */ 3755 /* CodeRange : $3A-$3B */ 3756 Ins_MSIRP(INS_ARG)3757 static void Ins_MSIRP( INS_ARG ) 3758 { 3759 Int point; 3760 TT_F26Dot6 distance; 3761 3762 3763 point = (Int)args[0]; 3764 3765 if ( BOUNDS( args[0], CUR.zp1.n_points ) ) 3766 { 3767 CUR.error = TT_Err_Invalid_Reference; 3768 return; 3769 } 3770 3771 /* XXX: Undocumented behaviour */ 3772 3773 if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */ 3774 { 3775 CUR.zp1.org_x[point] = CUR.zp0.org_x[CUR.GS.rp0]; 3776 CUR.zp1.org_y[point] = CUR.zp0.org_y[CUR.GS.rp0]; 3777 CUR.zp1.cur_x[point] = CUR.zp1.org_x[point]; 3778 CUR.zp1.cur_y[point] = CUR.zp1.org_y[point]; 3779 } 3780 3781 distance = CUR_Func_project( CUR.zp1.cur_x[point] - 3782 CUR.zp0.cur_x[CUR.GS.rp0], 3783 CUR.zp1.cur_y[point] - 3784 CUR.zp0.cur_y[CUR.GS.rp0] ); 3785 3786 CUR_Func_move( &CUR.zp1, point, args[1] - distance ); 3787 3788 CUR.GS.rp1 = CUR.GS.rp0; 3789 CUR.GS.rp2 = point; 3790 3791 if ( (CUR.opcode & 1) != 0 ) 3792 CUR.GS.rp0 = point; 3793 } 3794 3795 3796 /**********************************************/ 3797 /* MDAP[a] : Move Direct Absolute Point */ 3798 /* CodeRange : $2E-$2F */ 3799 Ins_MDAP(INS_ARG)3800 static void Ins_MDAP( INS_ARG ) 3801 { 3802 Int point; 3803 TT_F26Dot6 cur_dist, 3804 distance; 3805 3806 3807 point = (Int)args[0]; 3808 3809 if ( BOUNDS( args[0], CUR.zp0.n_points ) ) 3810 { 3811 CUR.error = TT_Err_Invalid_Reference; 3812 return; 3813 } 3814 3815 /* XXX: Is there some undocumented feature while in the */ 3816 /* twilight zone? ? */ 3817 3818 if ( (CUR.opcode & 1) != 0 ) 3819 { 3820 cur_dist = CUR_Func_project( CUR.zp0.cur_x[point], 3821 CUR.zp0.cur_y[point] ); 3822 distance = CUR_Func_round( cur_dist, 3823 CUR.metrics.compensations[0] ) - cur_dist; 3824 } 3825 else 3826 distance = 0; 3827 3828 CUR_Func_move( &CUR.zp0, point, distance ); 3829 3830 CUR.GS.rp0 = point; 3831 CUR.GS.rp1 = point; 3832 } 3833 3834 3835 /**********************************************/ 3836 /* MIAP[a] : Move Indirect Absolute Point */ 3837 /* CodeRange : $3E-$3F */ 3838 Ins_MIAP(INS_ARG)3839 static void Ins_MIAP( INS_ARG ) 3840 { 3841 Int cvtEntry, point; 3842 TT_F26Dot6 distance, 3843 org_dist; 3844 3845 3846 cvtEntry = (Int)args[1]; 3847 point = (Int)args[0]; 3848 3849 if ( BOUNDS( args[0], CUR.zp0.n_points ) || 3850 BOUNDS( args[1], CUR.cvtSize ) ) 3851 { 3852 CUR.error = TT_Err_Invalid_Reference; 3853 return; 3854 } 3855 3856 /* Undocumented: */ 3857 /* */ 3858 /* The behaviour of an MIAP instruction is quite */ 3859 /* different when used in the twilight zone. */ 3860 /* */ 3861 /* First, no control value cutin test is performed */ 3862 /* as it would fail anyway. Second, the original */ 3863 /* point, i.e. (org_x,org_y) of zp0.point, is set */ 3864 /* to the absolute, unrounded distance found in */ 3865 /* the CVT. */ 3866 /* */ 3867 /* This is used in the CVT programs of the Microsoft */ 3868 /* fonts Arial, Times, etc., in order to re-adjust */ 3869 /* some key font heights. It allows the use of the */ 3870 /* IP instruction in the twilight zone, which */ 3871 /* otherwise would be "illegal" according to the */ 3872 /* specs :) */ 3873 /* */ 3874 /* We implement it with a special sequence for the */ 3875 /* twilight zone. This is a bad hack, but it seems */ 3876 /* to work. */ 3877 3878 distance = CUR_Func_read_cvt( cvtEntry ); 3879 3880 DBG_PRINT3(" cvtEntry=%d point=%d distance=%d", cvtEntry, point, distance); 3881 3882 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ 3883 { 3884 CUR.zp0.org_x[point] = MulDiv_Round( CUR.GS.freeVector.x, 3885 distance, 0x4000L ); 3886 CUR.zp0.cur_x[point] = CUR.zp0.org_x[point]; 3887 3888 CUR.zp0.org_y[point] = MulDiv_Round( CUR.GS.freeVector.y, 3889 distance, 0x4000L ); 3890 CUR.zp0.cur_y[point] = CUR.zp0.org_y[point]; 3891 } 3892 3893 org_dist = CUR_Func_project( CUR.zp0.cur_x[point], 3894 CUR.zp0.cur_y[point] ); 3895 3896 if ( (CUR.opcode & 1) != 0 ) /* rounding and control cutin flag */ 3897 { 3898 if ( ABS(distance - org_dist) > CUR.GS.control_value_cutin ) 3899 distance = org_dist; 3900 3901 distance = CUR_Func_round( distance, CUR.metrics.compensations[0] ); 3902 } 3903 3904 CUR_Func_move( &CUR.zp0, point, distance - org_dist ); 3905 3906 CUR.GS.rp0 = point; 3907 CUR.GS.rp1 = point; 3908 } 3909 3910 3911 /**********************************************/ 3912 /* MDRP[abcde] : Move Direct Relative Point */ 3913 /* CodeRange : $C0-$DF */ 3914 Ins_MDRP(INS_ARG)3915 static void Ins_MDRP( INS_ARG ) 3916 { 3917 Int point; 3918 TT_F26Dot6 distance, 3919 org_dist; 3920 3921 3922 point = (Int)args[0]; 3923 3924 if ( BOUNDS( args[0], CUR.zp1.n_points ) ) 3925 { 3926 CUR.error = TT_Err_Invalid_Reference; 3927 return; 3928 } 3929 3930 /* XXX: Is there some undocumented feature while in the */ 3931 /* twilight zone? */ 3932 3933 org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] - 3934 CUR.zp0.org_x[CUR.GS.rp0], 3935 CUR.zp1.org_y[point] - 3936 CUR.zp0.org_y[CUR.GS.rp0] ); 3937 3938 /* single width cutin test */ 3939 3940 if ( ABS(org_dist) < CUR.GS.single_width_cutin ) 3941 { 3942 if ( org_dist >= 0 ) 3943 org_dist = CUR.GS.single_width_value; 3944 else 3945 org_dist = -CUR.GS.single_width_value; 3946 } 3947 3948 /* round flag */ 3949 3950 if ( (CUR.opcode & 4) != 0 ) 3951 distance = CUR_Func_round( org_dist, 3952 CUR.metrics.compensations[CUR.opcode & 3] ); 3953 else 3954 distance = Round_None( EXEC_ARGS 3955 org_dist, 3956 CUR.metrics.compensations[CUR.opcode & 3] ); 3957 3958 /* minimum distance flag */ 3959 3960 if ( (CUR.opcode & 8) != 0 ) 3961 { 3962 if ( org_dist >= 0 ) 3963 { 3964 if ( distance < CUR.GS.minimum_distance ) 3965 distance = CUR.GS.minimum_distance; 3966 } 3967 else 3968 { 3969 if ( distance > -CUR.GS.minimum_distance ) 3970 distance = -CUR.GS.minimum_distance; 3971 } 3972 } 3973 3974 /* now move the point */ 3975 3976 org_dist = CUR_Func_project( CUR.zp1.cur_x[point] - 3977 CUR.zp0.cur_x[CUR.GS.rp0], 3978 CUR.zp1.cur_y[point] - 3979 CUR.zp0.cur_y[CUR.GS.rp0] ); 3980 3981 CUR_Func_move( &CUR.zp1, point, distance - org_dist ); 3982 3983 CUR.GS.rp1 = CUR.GS.rp0; 3984 CUR.GS.rp2 = point; 3985 3986 if ( (CUR.opcode & 16) != 0 ) 3987 CUR.GS.rp0 = point; 3988 } 3989 3990 3991 /**********************************************/ 3992 /* MIRP[abcde] : Move Indirect Relative Point */ 3993 /* CodeRange : $E0-$FF */ 3994 Ins_MIRP(INS_ARG)3995 static void Ins_MIRP( INS_ARG ) 3996 { 3997 Int point, 3998 cvtEntry; 3999 4000 TT_F26Dot6 cvt_dist, 4001 distance, 4002 cur_dist, 4003 org_dist; 4004 4005 4006 point = (Int)args[0]; 4007 cvtEntry = (Int)args[1]; 4008 4009 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ 4010 4011 if ( BOUNDS( args[0], CUR.zp1.n_points ) || 4012 BOUNDS( args[1]+1, CUR.cvtSize+1 ) ) 4013 { 4014 CUR.error = TT_Err_Invalid_Reference; 4015 return; 4016 } 4017 4018 if ( args[1] < 0 ) 4019 cvt_dist = 0; 4020 else 4021 cvt_dist = CUR_Func_read_cvt( cvtEntry ); 4022 4023 /* single width test */ 4024 4025 if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin ) 4026 { 4027 if ( cvt_dist >= 0 ) 4028 cvt_dist = CUR.GS.single_width_value; 4029 else 4030 cvt_dist = -CUR.GS.single_width_value; 4031 } 4032 4033 /* XXX : Undocumented - twilight zone */ 4034 4035 if ( CUR.GS.gep1 == 0 ) 4036 { 4037 CUR.zp1.org_x[point] = CUR.zp0.org_x[CUR.GS.rp0] + 4038 MulDiv_Round( cvt_dist, 4039 CUR.GS.freeVector.x, 4040 0x4000 ); 4041 4042 CUR.zp1.org_y[point] = CUR.zp0.org_y[CUR.GS.rp0] + 4043 MulDiv_Round( cvt_dist, 4044 CUR.GS.freeVector.y, 4045 0x4000 ); 4046 4047 CUR.zp1.cur_x[point] = CUR.zp1.org_x[point]; 4048 CUR.zp1.cur_y[point] = CUR.zp1.org_y[point]; 4049 } 4050 4051 org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] - 4052 CUR.zp0.org_x[CUR.GS.rp0], 4053 CUR.zp1.org_y[point] - 4054 CUR.zp0.org_y[CUR.GS.rp0] ); 4055 4056 cur_dist = CUR_Func_project( CUR.zp1.cur_x[point] - 4057 CUR.zp0.cur_x[CUR.GS.rp0], 4058 CUR.zp1.cur_y[point] - 4059 CUR.zp0.cur_y[CUR.GS.rp0] ); 4060 4061 /* auto-flip test */ 4062 4063 if ( CUR.GS.auto_flip ) 4064 { 4065 if ( (org_dist ^ cvt_dist) < 0 ) 4066 cvt_dist = -cvt_dist; 4067 } 4068 4069 /* control value cutin and round */ 4070 4071 if ( (CUR.opcode & 4) != 0 ) 4072 { 4073 /* XXX: Undocumented : only perform cut-in test when both points */ 4074 /* refer to the same zone. */ 4075 4076 if ( CUR.GS.gep0 == CUR.GS.gep1 ) 4077 if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) 4078 cvt_dist = org_dist; 4079 4080 distance = CUR_Func_round( cvt_dist, 4081 CUR.metrics.compensations[CUR.opcode & 3] ); 4082 } 4083 else 4084 distance = Round_None( EXEC_ARGS 4085 cvt_dist, 4086 CUR.metrics.compensations[CUR.opcode & 3] ); 4087 4088 /* minimum distance test */ 4089 4090 if ( (CUR.opcode & 8) != 0 ) 4091 { 4092 if ( org_dist >= 0 ) 4093 { 4094 if ( distance < CUR.GS.minimum_distance ) 4095 distance = CUR.GS.minimum_distance; 4096 } 4097 else 4098 { 4099 if ( distance > -CUR.GS.minimum_distance ) 4100 distance = -CUR.GS.minimum_distance; 4101 } 4102 } 4103 4104 CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); 4105 4106 CUR.GS.rp1 = CUR.GS.rp0; 4107 4108 if ( (CUR.opcode & 16) != 0 ) 4109 CUR.GS.rp0 = point; 4110 4111 /* UNDOCUMENTED! */ 4112 4113 CUR.GS.rp2 = point; 4114 } 4115 4116 4117 /**********************************************/ 4118 /* ALIGNRP[] : ALIGN Relative Point */ 4119 /* CodeRange : $3C */ 4120 Ins_ALIGNRP(INS_ARG)4121 static void Ins_ALIGNRP( INS_ARG ) 4122 { 4123 Int point; 4124 TT_F26Dot6 distance; 4125 (void)args; 4126 4127 if ( CUR.top < CUR.GS.loop ) 4128 { 4129 CUR.error = TT_Err_Invalid_Reference; 4130 return; 4131 } 4132 4133 while ( CUR.GS.loop > 0 ) 4134 { 4135 CUR.args--; 4136 4137 point = (Int)CUR.stack[CUR.args]; 4138 4139 if ( BOUNDS( point, CUR.zp1.n_points ) ) 4140 { 4141 CUR.error = TT_Err_Invalid_Reference; 4142 return; 4143 } 4144 4145 distance = CUR_Func_project( CUR.zp1.cur_x[point] - 4146 CUR.zp0.cur_x[CUR.GS.rp0], 4147 CUR.zp1.cur_y[point] - 4148 CUR.zp0.cur_y[CUR.GS.rp0] ); 4149 4150 CUR_Func_move( &CUR.zp1, point, -distance ); 4151 CUR.GS.loop--; 4152 } 4153 4154 CUR.GS.loop = 1; 4155 CUR.new_top = CUR.args; 4156 } 4157 4158 4159 /**********************************************/ 4160 /* AA[] : Adjust Angle */ 4161 /* CodeRange : $7F */ 4162 Ins_AA(INS_ARG)4163 static void Ins_AA( INS_ARG ) 4164 { (void)exc; (void)args; 4165 /* Intentional - no longer supported */ 4166 } 4167 4168 4169 /**********************************************/ 4170 /* ISECT[] : moves point to InterSECTion */ 4171 /* CodeRange : $0F */ 4172 Ins_ISECT(INS_ARG)4173 static void Ins_ISECT( INS_ARG ) 4174 { 4175 Long point, /* are these Ints or Longs? */ 4176 a0, a1, 4177 b0, b1; 4178 4179 TT_F26Dot6 discriminant; 4180 4181 TT_F26Dot6 dx, dy, 4182 dax, day, 4183 dbx, dby; 4184 4185 TT_F26Dot6 val; 4186 4187 TT_Vector R; 4188 4189 4190 point = args[0]; 4191 4192 a0 = args[1]; 4193 a1 = args[2]; 4194 b0 = args[3]; 4195 b1 = args[4]; 4196 4197 if ( BOUNDS( b0, CUR.zp0.n_points ) || 4198 BOUNDS( b1, CUR.zp0.n_points ) || 4199 BOUNDS( a0, CUR.zp1.n_points ) || 4200 BOUNDS( a1, CUR.zp1.n_points ) ) 4201 { 4202 CUR.error = TT_Err_Invalid_Reference; 4203 return; 4204 } 4205 4206 dbx = CUR.zp0.cur_x[b1] - CUR.zp0.cur_x[b0]; 4207 dby = CUR.zp0.cur_y[b1] - CUR.zp0.cur_y[b0]; 4208 4209 dax = CUR.zp1.cur_x[a1] - CUR.zp1.cur_x[a0]; 4210 day = CUR.zp1.cur_y[a1] - CUR.zp1.cur_y[a0]; 4211 4212 dx = CUR.zp0.cur_x[b0] - CUR.zp1.cur_x[a0]; 4213 dy = CUR.zp0.cur_y[b0] - CUR.zp1.cur_y[a0]; 4214 4215 CUR.zp2.touch[point] |= TT_Flag_Touched_Both; 4216 4217 discriminant = MulDiv_Round( dax, -dby, 0x40L ) + 4218 MulDiv_Round( day, dbx, 0x40L ); 4219 4220 if ( ABS( discriminant ) >= 0x40 ) 4221 { 4222 val = MulDiv_Round( dx, -dby, 0x40L ) + MulDiv_Round( dy, dbx, 0x40L ); 4223 4224 R.x = MulDiv_Round( val, dax, discriminant ); 4225 R.y = MulDiv_Round( val, day, discriminant ); 4226 4227 CUR.zp2.cur_x[point] = CUR.zp1.cur_x[a0] + R.x; 4228 CUR.zp2.cur_y[point] = CUR.zp1.cur_y[a0] + R.y; 4229 } 4230 else 4231 { 4232 /* else, take the middle of the middles of A and B */ 4233 4234 CUR.zp2.cur_x[point] = ( CUR.zp1.cur_x[a0] + 4235 CUR.zp1.cur_x[a1] + 4236 CUR.zp0.cur_x[b0] + 4237 CUR.zp1.cur_x[b1] ) / 4; 4238 CUR.zp2.cur_y[point] = ( CUR.zp1.cur_y[a0] + 4239 CUR.zp1.cur_y[a1] + 4240 CUR.zp0.cur_y[b0] + 4241 CUR.zp1.cur_y[b1] ) / 4; 4242 } 4243 } 4244 4245 4246 /**********************************************/ 4247 /* ALIGNPTS[] : ALIGN PoinTS */ 4248 /* CodeRange : $27 */ 4249 Ins_ALIGNPTS(INS_ARG)4250 static void Ins_ALIGNPTS( INS_ARG ) 4251 { 4252 Int p1, p2; 4253 TT_F26Dot6 distance; 4254 4255 4256 p1 = (Int)args[0]; 4257 p2 = (Int)args[1]; 4258 4259 if ( BOUNDS( args[0], CUR.zp1.n_points ) || 4260 BOUNDS( args[1], CUR.zp0.n_points ) ) 4261 { 4262 CUR.error = TT_Err_Invalid_Reference; 4263 return; 4264 } 4265 4266 distance = CUR_Func_project( CUR.zp0.cur_x[p2] - 4267 CUR.zp1.cur_x[p1], 4268 CUR.zp0.cur_y[p2] - 4269 CUR.zp1.cur_x[p1] ) / 2; 4270 4271 CUR_Func_move( &CUR.zp1, p1, distance ); 4272 4273 CUR_Func_move( &CUR.zp0, p2, -distance ); 4274 } 4275 4276 4277 /**********************************************/ 4278 /* IP[] : Interpolate Point */ 4279 /* CodeRange : $39 */ 4280 Ins_IP(INS_ARG)4281 static void Ins_IP( INS_ARG ) 4282 { 4283 TT_F26Dot6 org_a, org_b, org_x, 4284 cur_a, cur_b, cur_x, 4285 distance; 4286 Int point; 4287 (void)args; 4288 4289 if ( CUR.top < CUR.GS.loop ) 4290 { 4291 CUR.error = TT_Err_Invalid_Reference; 4292 return; 4293 } 4294 4295 org_a = CUR_Func_dualproj( CUR.zp0.org_x[CUR.GS.rp1], 4296 CUR.zp0.org_y[CUR.GS.rp1] ); 4297 4298 org_b = CUR_Func_dualproj( CUR.zp1.org_x[CUR.GS.rp2], 4299 CUR.zp1.org_y[CUR.GS.rp2] ); 4300 4301 cur_a = CUR_Func_project( CUR.zp0.cur_x[CUR.GS.rp1], 4302 CUR.zp0.cur_y[CUR.GS.rp1] ); 4303 4304 cur_b = CUR_Func_project( CUR.zp1.cur_x[CUR.GS.rp2], 4305 CUR.zp1.cur_y[CUR.GS.rp2] ); 4306 4307 while ( CUR.GS.loop > 0 ) 4308 { 4309 CUR.args--; 4310 4311 point = (Int)CUR.stack[CUR.args]; 4312 if ( BOUNDS( point, CUR.zp2.n_points ) ) 4313 { 4314 CUR.error = TT_Err_Invalid_Reference; 4315 return; 4316 } 4317 4318 org_x = CUR_Func_dualproj( CUR.zp2.org_x[point], 4319 CUR.zp2.org_y[point] ); 4320 4321 cur_x = CUR_Func_project( CUR.zp2.cur_x[point], 4322 CUR.zp2.cur_y[point] ); 4323 4324 if ( ( org_a <= org_b && org_x <= org_a ) || 4325 ( org_a > org_b && org_x >= org_a ) ) 4326 4327 distance = ( cur_a - org_a ) + ( org_x - cur_x ); 4328 4329 else if ( ( org_a <= org_b && org_x >= org_b ) || 4330 ( org_a > org_b && org_x < org_b ) ) 4331 4332 distance = ( cur_b - org_b ) + ( org_x - cur_x ); 4333 4334 else 4335 /* note: it seems that rounding this value isn't a good */ 4336 /* idea (cf. width of capital 'S' in Times) */ 4337 4338 distance = MulDiv_Round( cur_b - cur_a, 4339 org_x - org_a, 4340 org_b - org_a ) + ( cur_a - cur_x ); 4341 4342 CUR_Func_move( &CUR.zp2, point, distance ); 4343 4344 CUR.GS.loop--; 4345 } 4346 4347 CUR.GS.loop = 1; 4348 CUR.new_top = CUR.args; 4349 } 4350 4351 4352 /**********************************************/ 4353 /* UTP[a] : UnTouch Point */ 4354 /* CodeRange : $29 */ 4355 Ins_UTP(INS_ARG)4356 static void Ins_UTP( INS_ARG ) 4357 { 4358 Byte mask; 4359 4360 if ( BOUNDS( args[0], CUR.zp0.n_points ) ) 4361 { 4362 CUR.error = TT_Err_Invalid_Reference; 4363 return; 4364 } 4365 4366 mask = 0xFF; 4367 4368 if ( CUR.GS.freeVector.x != 0 ) 4369 mask &= ~TT_Flag_Touched_X; 4370 4371 if ( CUR.GS.freeVector.y != 0 ) 4372 mask &= ~TT_Flag_Touched_Y; 4373 4374 CUR.zp0.touch[args[0]] &= mask; 4375 } 4376 4377 4378 /* Local variables for Ins_IUP: */ 4379 struct LOC_Ins_IUP 4380 { 4381 PCoordinates orgs; /* original and current coordinate */ 4382 PCoordinates curs; /* arrays */ 4383 }; 4384 4385 Shift(Int p1,Int p2,Int p,struct LOC_Ins_IUP * LINK)4386 static void Shift( Int p1, 4387 Int p2, 4388 Int p, 4389 struct LOC_Ins_IUP* LINK ) 4390 { 4391 Int i; 4392 TT_F26Dot6 x; 4393 4394 4395 x = LINK->curs[p] - LINK->orgs[p]; 4396 4397 for ( i = p1; i < p; i++ ) 4398 LINK->curs[i] += x; 4399 4400 for ( i = p + 1; i <= p2; i++ ) 4401 LINK->curs[i] += x; 4402 } 4403 4404 Interp(Int p1,Int p2,Int ref1,Int ref2,struct LOC_Ins_IUP * LINK)4405 static void Interp( Int p1, Int p2, 4406 Int ref1, Int ref2, 4407 struct LOC_Ins_IUP* LINK ) 4408 { 4409 Long i; 4410 TT_F26Dot6 x, x1, x2, d1, d2; 4411 4412 4413 if ( p1 > p2 ) 4414 return; 4415 4416 x1 = LINK->orgs[ref1]; 4417 d1 = LINK->curs[ref1] - LINK->orgs[ref1]; 4418 x2 = LINK->orgs[ref2]; 4419 d2 = LINK->curs[ref2] - LINK->orgs[ref2]; 4420 4421 if ( x1 == x2 ) 4422 { 4423 for ( i = p1; i <= p2; i++ ) 4424 { 4425 x = LINK->orgs[i]; 4426 4427 if ( x <= x1 ) 4428 x += d1; 4429 else 4430 x += d2; 4431 4432 LINK->curs[i] = x; 4433 } 4434 return; 4435 } 4436 4437 if ( x1 < x2 ) 4438 { 4439 for ( i = p1; i <= p2; i++ ) 4440 { 4441 x = LINK->orgs[i]; 4442 4443 if ( x <= x1 ) 4444 x += d1; 4445 else 4446 { 4447 if ( x >= x2 ) 4448 x += d2; 4449 else 4450 x = LINK->curs[ref1] + 4451 MulDiv_Round( x - x1, 4452 LINK->curs[ref2] - LINK->curs[ref1], 4453 x2 - x1 ); 4454 } 4455 LINK->curs[i] = x; 4456 } 4457 return; 4458 } 4459 4460 /* x2 < x1 */ 4461 4462 for ( i = p1; i <= p2; i++ ) 4463 { 4464 x = LINK->orgs[i]; 4465 if ( x <= x2 ) 4466 x += d2; 4467 else 4468 { 4469 if ( x >= x1 ) 4470 x += d1; 4471 else 4472 x = LINK->curs[ref1] + 4473 MulDiv_Round( x - x1, 4474 LINK->curs[ref2] - LINK->curs[ref1], 4475 x2 - x1 ); 4476 } 4477 LINK->curs[i] = x; 4478 } 4479 } 4480 4481 4482 /**********************************************/ 4483 /* IUP[a] : Interpolate Untouched Points */ 4484 /* CodeRange : $30-$31 */ 4485 Ins_IUP(INS_ARG)4486 static void Ins_IUP( INS_ARG ) 4487 { 4488 struct LOC_Ins_IUP V; 4489 unsigned char mask; 4490 4491 Long first_point; /* first point of contour */ 4492 Long end_point; /* end point (last+1) of contour */ 4493 4494 Long first_touched; /* first touched point in contour */ 4495 Long cur_touched; /* current touched point in contour */ 4496 4497 Long point; /* current point */ 4498 Long contour; /* current contour */ 4499 (void)args; 4500 4501 if ( CUR.opcode & 1 ) 4502 { 4503 mask = TT_Flag_Touched_X; 4504 V.orgs = CUR.pts.org_x; 4505 V.curs = CUR.pts.cur_x; 4506 } 4507 else 4508 { 4509 mask = TT_Flag_Touched_Y; 4510 V.orgs = CUR.pts.org_y; 4511 V.curs = CUR.pts.cur_y; 4512 } 4513 4514 contour = 0; 4515 point = 0; 4516 4517 do 4518 { 4519 end_point = CUR.pts.contours[contour]; 4520 first_point = point; 4521 4522 while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 ) 4523 point++; 4524 4525 if ( point <= end_point ) 4526 { 4527 first_touched = point; 4528 cur_touched = point; 4529 4530 point++; 4531 4532 while ( point <= end_point ) 4533 { 4534 if ( (CUR.pts.touch[point] & mask) != 0 ) 4535 { 4536 Interp( (Int)(cur_touched + 1), 4537 (Int)(point - 1), 4538 (Int)cur_touched, 4539 (Int)point, 4540 &V ); 4541 cur_touched = point; 4542 } 4543 4544 point++; 4545 } 4546 4547 if ( cur_touched == first_touched ) 4548 Shift( (Int)first_point, (Int)end_point, (Int)cur_touched, &V ); 4549 else 4550 { 4551 Interp((Int)(cur_touched + 1), 4552 (Int)(end_point), 4553 (Int)(cur_touched), 4554 (Int)(first_touched), 4555 &V ); 4556 4557 Interp((Int)(first_point), 4558 (Int)(first_touched - 1), 4559 (Int)(cur_touched), 4560 (Int)(first_touched), 4561 &V ); 4562 } 4563 } 4564 contour++; 4565 } while ( contour < CUR.pts.n_contours ); 4566 } 4567 4568 4569 /**********************************************/ 4570 /* DELTAPn[] : DELTA Exceptions P1, P2, P3 */ 4571 /* CodeRange : $5D,$71,$72 */ 4572 Ins_DELTAP(INS_ARG)4573 static void Ins_DELTAP( INS_ARG ) 4574 { 4575 Int k; 4576 Long A, B, C, nump; 4577 4578 4579 nump = args[0]; 4580 4581 for ( k = 1; k <= nump; k++ ) 4582 { 4583 if ( CUR.args < 2 ) 4584 { 4585 CUR.error = TT_Err_Too_Few_Arguments; 4586 return; 4587 } 4588 4589 CUR.args -= 2; 4590 4591 A = CUR.stack[CUR.args + 1]; 4592 B = CUR.stack[CUR.args]; 4593 #if 0 4594 if ( BOUNDS( A, CUR.zp0.n_points ) ) 4595 #else 4596 /* igorm changed : allow phantom points (Altona.Page_3.2002-09-27.pdf). */ 4597 if ( BOUNDS( A, CUR.zp0.n_points + 2 ) ) 4598 #endif 4599 { 4600 CUR.error = TT_Err_Invalid_Reference; 4601 return; 4602 } 4603 4604 C = (B & 0xF0) >> 4; 4605 4606 switch ( CUR.opcode ) 4607 { 4608 case 0x5d: 4609 break; 4610 4611 case 0x71: 4612 C += 16; 4613 break; 4614 4615 case 0x72: 4616 C += 32; 4617 break; 4618 } 4619 4620 C += CUR.GS.delta_base; 4621 4622 if ( CURRENT_Ppem() == C ) 4623 { 4624 B = (B & 0xF) - 8; 4625 if ( B >= 0 ) 4626 B++; 4627 B = B * 64 / (1L << CUR.GS.delta_shift); 4628 4629 CUR_Func_move( &CUR.zp0, (Int)A, (Int)B ); 4630 } 4631 } 4632 4633 CUR.new_top = CUR.args; 4634 } 4635 4636 4637 /**********************************************/ 4638 /* DELTACn[] : DELTA Exceptions C1, C2, C3 */ 4639 /* CodeRange : $73,$74,$75 */ 4640 Ins_DELTAC(INS_ARG)4641 static void Ins_DELTAC( INS_ARG ) 4642 { 4643 Long nump, k; 4644 Long A, B, C; 4645 4646 4647 nump = args[0]; 4648 4649 for ( k = 1; k <= nump; k++ ) 4650 { 4651 if ( CUR.args < 2 ) 4652 { 4653 CUR.error = TT_Err_Too_Few_Arguments; 4654 return; 4655 } 4656 4657 CUR.args -= 2; 4658 4659 A = CUR.stack[CUR.args + 1]; 4660 B = CUR.stack[CUR.args]; 4661 4662 if ( A >= CUR.cvtSize ) 4663 { 4664 CUR.error = TT_Err_Invalid_Reference; 4665 return; 4666 } 4667 4668 C = ((unsigned long)(B & 0xF0)) >> 4; 4669 4670 switch ( CUR.opcode ) 4671 { 4672 case 0x73: 4673 break; 4674 4675 case 0x74: 4676 C += 16; 4677 break; 4678 4679 case 0x75: 4680 C += 32; 4681 break; 4682 } 4683 4684 C += CUR.GS.delta_base; 4685 4686 if ( CURRENT_Ppem() == C ) 4687 { 4688 B = (B & 0xF) - 8; 4689 if ( B >= 0 ) 4690 B++; 4691 B = B * 64 / (1L << CUR.GS.delta_shift); 4692 4693 CUR_Func_move_cvt( A, B ); 4694 } 4695 } 4696 4697 CUR.new_top = CUR.args; 4698 } 4699 4700 4701 4702 /****************************************************************/ 4703 /* */ 4704 /* MISC. INSTRUCTIONS */ 4705 /* */ 4706 /****************************************************************/ 4707 4708 /***********************************************************/ 4709 /* DEBUG[] : DEBUG. Unsupported */ 4710 /* CodeRange : $4F */ 4711 4712 /* NOTE : The original instruction pops a value from the stack */ 4713 Ins_DEBUG(INS_ARG)4714 static void Ins_DEBUG( INS_ARG ) 4715 { (void)args; 4716 CUR.error = TT_Err_Debug_OpCode; 4717 } 4718 4719 4720 /**********************************************/ 4721 /* GETINFO[] : GET INFOrmation */ 4722 /* CodeRange : $88 */ 4723 Ins_GETINFO(INS_ARG)4724 static void Ins_GETINFO( INS_ARG ) 4725 { 4726 Long K; 4727 4728 4729 K = 0; 4730 4731 /* We return then Windows 3.1 version number */ 4732 /* for the font scaler */ 4733 if ( (args[0] & 1) != 0 ) 4734 K = 3; 4735 4736 /* Has the glyph been rotated ? */ 4737 if ( CUR.metrics.rotated ) 4738 K |= 0x80; 4739 4740 /* Has the glyph been stretched ? */ 4741 if ( CUR.metrics.stretched ) 4742 K |= 0x100; 4743 4744 args[0] = K; 4745 } 4746 4747 Ins_UNKNOWN(INS_ARG)4748 static void Ins_UNKNOWN( INS_ARG ) 4749 { /* Rewritten by igorm. */ 4750 Byte i; 4751 TDefRecord* def; 4752 PCallRecord call; 4753 4754 # if 0 /* The condition below appears always false 4755 due to limited range of data type 4756 - skip it to quiet a compiler warning. */ 4757 if (CUR.opcode > sizeof(CUR.IDefPtr) / sizeof(CUR.IDefPtr[0])) { 4758 CUR.error = TT_Err_Invalid_Opcode; 4759 return; 4760 } 4761 # endif 4762 i = CUR.IDefPtr[(Byte)CUR.opcode]; 4763 4764 if (i >= CUR.numIDefs) 4765 { 4766 CUR.error = TT_Err_Invalid_Opcode; 4767 return; 4768 } 4769 def = &CUR.IDefs[i]; 4770 4771 4772 if ( CUR.callTop >= CUR.callSize ) 4773 { 4774 CUR.error = TT_Err_Stack_Overflow; 4775 return; 4776 } 4777 4778 call = CUR.callStack + CUR.callTop++; 4779 4780 call->Caller_Range = CUR.curRange; 4781 call->Caller_IP = CUR.IP+1; 4782 call->Cur_Count = 1; 4783 call->Cur_Restart = def->Start; 4784 4785 INS_Goto_CodeRange( def->Range, def->Start ); 4786 4787 CUR.step_ins = FALSE; 4788 return; 4789 } 4790 4791 4792 static struct { const char *sName; TInstruction_Function p; } Instruct_Dispatch[256] = 4793 { 4794 /* Opcodes are gathered in groups of 16. */ 4795 /* Please keep the spaces as they are. */ 4796 4797 {" SVTCA y ", Ins_SVTCA } 4798 ,{" SVTCA x ", Ins_SVTCA } 4799 ,{" SPvTCA y ", Ins_SPVTCA } 4800 ,{" SPvTCA x ", Ins_SPVTCA } 4801 ,{" SFvTCA y ", Ins_SFVTCA } 4802 ,{" SFvTCA x ", Ins_SFVTCA } 4803 ,{" SPvTL // ", Ins_SPVTL } 4804 ,{" SPvTL + ", Ins_SPVTL } 4805 ,{" SFvTL // ", Ins_SFVTL } 4806 ,{" SFvTL + ", Ins_SFVTL } 4807 ,{" SPvFS ", Ins_SPVFS } 4808 ,{" SFvFS ", Ins_SFVFS } 4809 ,{" GPV ", Ins_GPV } 4810 ,{" GFV ", Ins_GFV } 4811 ,{" SFvTPv ", Ins_SFVTPV } 4812 ,{" ISECT ", Ins_ISECT } 4813 4814 ,{" SRP0 ", Ins_SRP0 } 4815 ,{" SRP1 ", Ins_SRP1 } 4816 ,{" SRP2 ", Ins_SRP2 } 4817 ,{" SZP0 ", Ins_SZP0 } 4818 ,{" SZP1 ", Ins_SZP1 } 4819 ,{" SZP2 ", Ins_SZP2 } 4820 ,{" SZPS ", Ins_SZPS } 4821 ,{" SLOOP ", Ins_SLOOP } 4822 ,{" RTG ", Ins_RTG } 4823 ,{" RTHG ", Ins_RTHG } 4824 ,{" SMD ", Ins_SMD } 4825 ,{" ELSE ", Ins_ELSE } 4826 ,{" JMPR ", Ins_JMPR } 4827 ,{" SCvTCi ", Ins_SCVTCI } 4828 ,{" SSwCi ", Ins_SSWCI } 4829 ,{" SSW ", Ins_SSW } 4830 4831 ,{" DUP ", Ins_DUP } 4832 ,{" POP ", Ins_POP } 4833 ,{" CLEAR ", Ins_CLEAR } 4834 ,{" SWAP ", Ins_SWAP } 4835 ,{" DEPTH ", Ins_DEPTH } 4836 ,{" CINDEX ", Ins_CINDEX } 4837 ,{" MINDEX ", Ins_MINDEX } 4838 ,{" AlignPTS ", Ins_ALIGNPTS} 4839 ,{" INS_$28 ", Ins_UNKNOWN } 4840 ,{" UTP ", Ins_UTP } 4841 ,{" LOOPCALL ", Ins_LOOPCALL} 4842 ,{" CALL ", Ins_CALL } 4843 ,{" FDEF ", Ins_FDEF } 4844 ,{" ENDF ", Ins_ENDF } 4845 ,{" MDAP[0] ", Ins_MDAP } 4846 ,{" MDAP[1] ", Ins_MDAP } 4847 4848 ,{" IUP[0] ", Ins_IUP } 4849 ,{" IUP[1] ", Ins_IUP } 4850 ,{" SHP[0] ", Ins_SHP } 4851 ,{" SHP[1] ", Ins_SHP } 4852 ,{" SHC[0] ", Ins_SHC } 4853 ,{" SHC[1] ", Ins_SHC } 4854 ,{" SHZ[0] ", Ins_SHZ } 4855 ,{" SHZ[1] ", Ins_SHZ } 4856 ,{" SHPIX ", Ins_SHPIX } 4857 ,{" IP ", Ins_IP } 4858 ,{" MSIRP[0] ", Ins_MSIRP } 4859 ,{" MSIRP[1] ", Ins_MSIRP } 4860 ,{" AlignRP ", Ins_ALIGNRP } 4861 ,{" RTDG ", Ins_RTDG } 4862 ,{" MIAP[0] ", Ins_MIAP } 4863 ,{" MIAP[1] ", Ins_MIAP } 4864 4865 ,{" NPushB ", Ins_NPUSHB } 4866 ,{" NPushW ", Ins_NPUSHW } 4867 ,{" WS ", Ins_WS } 4868 ,{" RS ", Ins_RS } 4869 ,{" WCvtP ", Ins_WCVTP } 4870 ,{" RCvt ", Ins_RCVT } 4871 ,{" GC[0] ", Ins_GC } 4872 ,{" GC[1] ", Ins_GC } 4873 ,{" SCFS ", Ins_SCFS } 4874 ,{" MD[0] ", Ins_MD } 4875 ,{" MD[1] ", Ins_MD } 4876 ,{" MPPEM ", Ins_MPPEM } 4877 ,{" MPS ", Ins_MPS } 4878 ,{" FlipON ", Ins_FLIPON } 4879 ,{" FlipOFF ", Ins_FLIPOFF } 4880 ,{" DEBUG ", Ins_DEBUG } 4881 4882 ,{" LT ", Ins_LT } 4883 ,{" LTEQ ", Ins_LTEQ } 4884 ,{" GT ", Ins_GT } 4885 ,{" GTEQ ", Ins_GTEQ } 4886 ,{" EQ ", Ins_EQ } 4887 ,{" NEQ ", Ins_NEQ } 4888 ,{" ODD ", Ins_ODD } 4889 ,{" EVEN ", Ins_EVEN } 4890 ,{" IF ", Ins_IF } 4891 ,{" EIF ", Ins_EIF } 4892 ,{" AND ", Ins_AND } 4893 ,{" OR ", Ins_OR } 4894 ,{" NOT ", Ins_NOT } 4895 ,{" DeltaP1 ", Ins_DELTAP } 4896 ,{" SDB ", Ins_SDB } 4897 ,{" SDS ", Ins_SDS } 4898 4899 ,{" ADD ", Ins_ADD } 4900 ,{" SUB ", Ins_SUB } 4901 ,{" DIV ", Ins_DIV } 4902 ,{" MUL ", Ins_MUL } 4903 ,{" ABS ", Ins_ABS } 4904 ,{" NEG ", Ins_NEG } 4905 ,{" FLOOR ", Ins_FLOOR } 4906 ,{" CEILING ", Ins_CEILING } 4907 ,{" ROUND[0] ", Ins_ROUND } 4908 ,{" ROUND[1] ", Ins_ROUND } 4909 ,{" ROUND[2] ", Ins_ROUND } 4910 ,{" ROUND[3] ", Ins_ROUND } 4911 ,{" NROUND[0] ", Ins_NROUND } 4912 ,{" NROUND[1] ", Ins_NROUND } 4913 ,{" NROUND[2] ", Ins_NROUND } 4914 ,{" NROUND[3] ", Ins_NROUND } 4915 4916 ,{" WCvtF ", Ins_WCVTF } 4917 ,{" DeltaP2 ", Ins_DELTAP } 4918 ,{" DeltaP3 ", Ins_DELTAP } 4919 ,{" DeltaCn[0] ", Ins_DELTAC } 4920 ,{" DeltaCn[1] ", Ins_DELTAC } 4921 ,{" DeltaCn[2] ", Ins_DELTAC } 4922 ,{" SROUND ", Ins_SROUND } 4923 ,{" S45Round ", Ins_S45ROUND } 4924 ,{" JROT ", Ins_JROT } 4925 ,{" JROF ", Ins_JROF } 4926 ,{" ROFF ", Ins_ROFF } 4927 ,{" INS_$7B ", Ins_UNKNOWN } 4928 ,{" RUTG ", Ins_RUTG } 4929 ,{" RDTG ", Ins_RDTG } 4930 ,{" SANGW ", Ins_SANGW } 4931 ,{" AA ", Ins_AA } 4932 4933 ,{" FlipPT ", Ins_FLIPPT } 4934 ,{" FlipRgON ", Ins_FLIPRGON } 4935 ,{" FlipRgOFF ", Ins_FLIPRGOFF } 4936 ,{" INS_$83 ", Ins_UNKNOWN } 4937 ,{" INS_$84 ", Ins_UNKNOWN } 4938 ,{" ScanCTRL ", Ins_SCANCTRL } 4939 ,{" SDPVTL[0] ", Ins_SDPVTL } 4940 ,{" SDPVTL[1] ", Ins_SDPVTL } 4941 ,{" GetINFO ", Ins_GETINFO } 4942 ,{" IDEF ", Ins_IDEF } 4943 ,{" ROLL ", Ins_ROLL } 4944 ,{" MAX ", Ins_MAX } 4945 ,{" MIN ", Ins_MIN } 4946 ,{" ScanTYPE ", Ins_SCANTYPE } 4947 ,{" InstCTRL ", Ins_INSTCTRL } 4948 ,{" INS_$8F ", Ins_UNKNOWN } 4949 4950 ,{" INS_$90 ", Ins_UNKNOWN } 4951 ,{" INS_$91 ", Ins_UNKNOWN } 4952 ,{" INS_$92 ", Ins_UNKNOWN } 4953 ,{" INS_$93 ", Ins_UNKNOWN } 4954 ,{" INS_$94 ", Ins_UNKNOWN } 4955 ,{" INS_$95 ", Ins_UNKNOWN } 4956 ,{" INS_$96 ", Ins_UNKNOWN } 4957 ,{" INS_$97 ", Ins_UNKNOWN } 4958 ,{" INS_$98 ", Ins_UNKNOWN } 4959 ,{" INS_$99 ", Ins_UNKNOWN } 4960 ,{" INS_$9A ", Ins_UNKNOWN } 4961 ,{" INS_$9B ", Ins_UNKNOWN } 4962 ,{" INS_$9C ", Ins_UNKNOWN } 4963 ,{" INS_$9D ", Ins_UNKNOWN } 4964 ,{" INS_$9E ", Ins_UNKNOWN } 4965 ,{" INS_$9F ", Ins_UNKNOWN } 4966 4967 ,{" INS_$A0 ", Ins_UNKNOWN } 4968 ,{" INS_$A1 ", Ins_UNKNOWN } 4969 ,{" INS_$A2 ", Ins_UNKNOWN } 4970 ,{" INS_$A3 ", Ins_UNKNOWN } 4971 ,{" INS_$A4 ", Ins_UNKNOWN } 4972 ,{" INS_$A5 ", Ins_UNKNOWN } 4973 ,{" INS_$A6 ", Ins_UNKNOWN } 4974 ,{" INS_$A7 ", Ins_UNKNOWN } 4975 ,{" INS_$A8 ", Ins_UNKNOWN } 4976 ,{" INS_$A9 ", Ins_UNKNOWN } 4977 ,{" INS_$AA ", Ins_UNKNOWN } 4978 ,{" INS_$AB ", Ins_UNKNOWN } 4979 ,{" INS_$AC ", Ins_UNKNOWN } 4980 ,{" INS_$AD ", Ins_UNKNOWN } 4981 ,{" INS_$AE ", Ins_UNKNOWN } 4982 ,{" INS_$AF ", Ins_UNKNOWN } 4983 4984 ,{" PushB[0] ", Ins_PUSHB } 4985 ,{" PushB[1] ", Ins_PUSHB } 4986 ,{" PushB[2] ", Ins_PUSHB } 4987 ,{" PushB[3] ", Ins_PUSHB } 4988 ,{" PushB[4] ", Ins_PUSHB } 4989 ,{" PushB[5] ", Ins_PUSHB } 4990 ,{" PushB[6] ", Ins_PUSHB } 4991 ,{" PushB[7] ", Ins_PUSHB } 4992 ,{" PushW[0] ", Ins_PUSHW } 4993 ,{" PushW[1] ", Ins_PUSHW } 4994 ,{" PushW[2] ", Ins_PUSHW } 4995 ,{" PushW[3] ", Ins_PUSHW } 4996 ,{" PushW[4] ", Ins_PUSHW } 4997 ,{" PushW[5] ", Ins_PUSHW } 4998 ,{" PushW[6] ", Ins_PUSHW } 4999 ,{" PushW[7] ", Ins_PUSHW } 5000 5001 ,{" MDRP[00] ", Ins_MDRP } 5002 ,{" MDRP[01] ", Ins_MDRP } 5003 ,{" MDRP[02] ", Ins_MDRP } 5004 ,{" MDRP[03] ", Ins_MDRP } 5005 ,{" MDRP[04] ", Ins_MDRP } 5006 ,{" MDRP[05] ", Ins_MDRP } 5007 ,{" MDRP[06] ", Ins_MDRP } 5008 ,{" MDRP[07] ", Ins_MDRP } 5009 ,{" MDRP[08] ", Ins_MDRP } 5010 ,{" MDRP[09] ", Ins_MDRP } 5011 ,{" MDRP[10] ", Ins_MDRP } 5012 ,{" MDRP[11] ", Ins_MDRP } 5013 ,{" MDRP[12] ", Ins_MDRP } 5014 ,{" MDRP[13] ", Ins_MDRP } 5015 ,{" MDRP[14] ", Ins_MDRP } 5016 ,{" MDRP[15] ", Ins_MDRP } 5017 5018 ,{" MDRP[16] ", Ins_MDRP } 5019 ,{" MDRP[17] ", Ins_MDRP } 5020 ,{" MDRP[18] ", Ins_MDRP } 5021 ,{" MDRP[19] ", Ins_MDRP } 5022 ,{" MDRP[20] ", Ins_MDRP } 5023 ,{" MDRP[21] ", Ins_MDRP } 5024 ,{" MDRP[22] ", Ins_MDRP } 5025 ,{" MDRP[23] ", Ins_MDRP } 5026 ,{" MDRP[24] ", Ins_MDRP } 5027 ,{" MDRP[25] ", Ins_MDRP } 5028 ,{" MDRP[26] ", Ins_MDRP } 5029 ,{" MDRP[27] ", Ins_MDRP } 5030 ,{" MDRP[28] ", Ins_MDRP } 5031 ,{" MDRP[29] ", Ins_MDRP } 5032 ,{" MDRP[30] ", Ins_MDRP } 5033 ,{" MDRP[31] ", Ins_MDRP } 5034 5035 ,{" MIRP[00] ", Ins_MIRP } 5036 ,{" MIRP[01] ", Ins_MIRP } 5037 ,{" MIRP[02] ", Ins_MIRP } 5038 ,{" MIRP[03] ", Ins_MIRP } 5039 ,{" MIRP[04] ", Ins_MIRP } 5040 ,{" MIRP[05] ", Ins_MIRP } 5041 ,{" MIRP[06] ", Ins_MIRP } 5042 ,{" MIRP[07] ", Ins_MIRP } 5043 ,{" MIRP[08] ", Ins_MIRP } 5044 ,{" MIRP[09] ", Ins_MIRP } 5045 ,{" MIRP[10] ", Ins_MIRP } 5046 ,{" MIRP[11] ", Ins_MIRP } 5047 ,{" MIRP[12] ", Ins_MIRP } 5048 ,{" MIRP[13] ", Ins_MIRP } 5049 ,{" MIRP[14] ", Ins_MIRP } 5050 ,{" MIRP[15] ", Ins_MIRP } 5051 5052 ,{" MIRP[16] ", Ins_MIRP } 5053 ,{" MIRP[17] ", Ins_MIRP } 5054 ,{" MIRP[18] ", Ins_MIRP } 5055 ,{" MIRP[19] ", Ins_MIRP } 5056 ,{" MIRP[20] ", Ins_MIRP } 5057 ,{" MIRP[21] ", Ins_MIRP } 5058 ,{" MIRP[22] ", Ins_MIRP } 5059 ,{" MIRP[23] ", Ins_MIRP } 5060 ,{" MIRP[24] ", Ins_MIRP } 5061 ,{" MIRP[25] ", Ins_MIRP } 5062 ,{" MIRP[26] ", Ins_MIRP } 5063 ,{" MIRP[27] ", Ins_MIRP } 5064 ,{" MIRP[28] ", Ins_MIRP } 5065 ,{" MIRP[29] ", Ins_MIRP } 5066 ,{" MIRP[30] ", Ins_MIRP } 5067 ,{" MIRP[31] ", Ins_MIRP } 5068 }; 5069 5070 5071 5072 /****************************************************************/ 5073 /* */ 5074 /* RUN */ 5075 /* */ 5076 /* This function executes a run of opcodes. It will exit */ 5077 /* in the following cases: */ 5078 /* */ 5079 /* - Errors (in which case it returns FALSE) */ 5080 /* */ 5081 /* - Reaching the end of the main code range (returns TRUE). */ 5082 /* Reaching the end of a code range within a function */ 5083 /* call is an error. */ 5084 /* */ 5085 /* - After executing one single opcode, if the flag */ 5086 /* 'Instruction_Trap' is set to TRUE (returns TRUE). */ 5087 /* */ 5088 /* On exit whith TRUE, test IP < CodeSize to know wether it */ 5089 /* comes from a instruction trap or a normal termination. */ 5090 /* */ 5091 /* */ 5092 /* Note: The documented DEBUG opcode pops a value from */ 5093 /* the stack. This behaviour is unsupported, here */ 5094 /* a DEBUG opcode is always an error. */ 5095 /* */ 5096 /* */ 5097 /* THIS IS THE INTERPRETER'S MAIN LOOP */ 5098 /* */ 5099 /* Instructions appear in the specs' order. */ 5100 /* */ 5101 /****************************************************************/ 5102 RunIns(PExecution_Context exc)5103 TT_Error RunIns( PExecution_Context exc ) 5104 { 5105 TT_Error Result; 5106 Int A; 5107 PDefRecord WITH; 5108 PCallRecord WITH1; 5109 bool bFirst; 5110 bool dbg_prt = (DBG_PRT_FUN != NULL); 5111 # ifdef DEBUG 5112 ttfMemory *mem = exc->current_face->font->tti->ttf_memory; 5113 F26Dot6 *save_ox, *save_oy, *save_cx, *save_cy; 5114 5115 DBG_PRINT("\n%% *** Entering RunIns ***"); 5116 # endif 5117 5118 /* set CVT functions */ 5119 CUR.metrics.ratio = 0; 5120 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) 5121 { 5122 /* non-square pixels, use the stretched routines */ 5123 CUR.func_read_cvt = Read_CVT_Stretched; 5124 CUR.func_write_cvt = Write_CVT_Stretched; 5125 CUR.func_move_cvt = Move_CVT_Stretched; 5126 } 5127 else 5128 { 5129 /* square pixels, use normal routines */ 5130 CUR.func_read_cvt = Read_CVT; 5131 CUR.func_write_cvt = Write_CVT; 5132 CUR.func_move_cvt = Move_CVT; 5133 } 5134 5135 COMPUTE_Funcs(); 5136 Compute_Round( EXEC_ARGS (Byte)exc->GS.round_state ); 5137 5138 # ifdef DEBUG 5139 if (dbg_prt && CUR.pts.n_points) { 5140 save_ox = mem->alloc_bytes(mem, CUR.pts.n_points * sizeof(*save_ox), "RunIns"); 5141 save_oy = mem->alloc_bytes(mem, CUR.pts.n_points * sizeof(*save_oy), "RunIns"); 5142 save_cx = mem->alloc_bytes(mem, CUR.pts.n_points * sizeof(*save_cx), "RunIns"); 5143 save_cy = mem->alloc_bytes(mem, CUR.pts.n_points * sizeof(*save_cy), "RunIns"); 5144 if (!save_ox || !save_oy || !save_cx || !save_cy) 5145 return TT_Err_Out_Of_Memory; 5146 } else 5147 save_ox = save_oy = save_cx = save_cy = NULL; 5148 # endif 5149 5150 Result = setjmp(exc->trap); 5151 if (Result) { 5152 CUR.error = Result; 5153 goto _LExit; 5154 } 5155 bFirst = true; 5156 5157 do 5158 { 5159 CALC_Length(); 5160 5161 /* First, let's check for empty stack and overflow */ 5162 5163 CUR.args = CUR.top - Pop_Push_Count[CUR.opcode * 2]; 5164 5165 /* `args' is the top of the stack once arguments have been popped. */ 5166 /* One can also interpret it as the index of the last argument. */ 5167 5168 if ( CUR.args < 0 ) 5169 { 5170 CUR.error = TT_Err_Too_Few_Arguments; 5171 goto _LErrorLabel; 5172 } 5173 5174 CUR.new_top = CUR.args + Pop_Push_Count[CUR.opcode * 2 + 1]; 5175 5176 /* `new_top' is the new top of the stack, after the instruction's */ 5177 /* execution. `top' will be set to `new_top' after the 'switch' */ 5178 /* statement. */ 5179 5180 if ( CUR.new_top > CUR.stackSize ) 5181 { 5182 CUR.error = TT_Err_Stack_Overflow; 5183 goto _LErrorLabel; 5184 } 5185 5186 CUR.step_ins = TRUE; 5187 CUR.error = TT_Err_Ok; 5188 5189 # ifdef DEBUG 5190 DBG_PRINT3("\n%%n=%5d IP=%5d OP=%s ", nInstrCount, CUR.IP, Instruct_Dispatch[CUR.opcode].sName); 5191 /* 5192 { for(int i=0;i<CUR.top;i++) 5193 DBG_PRINT1("% %d",CUR.stack[i]); 5194 } 5195 */ 5196 if (save_ox != NULL) { 5197 memcpy(save_ox, CUR.pts.org_x, sizeof(CUR.pts.org_x[0]) * CUR.pts.n_points); 5198 memcpy(save_oy, CUR.pts.org_y, sizeof(CUR.pts.org_y[0]) * CUR.pts.n_points); 5199 memcpy(save_cx, CUR.pts.cur_x, sizeof(CUR.pts.cur_x[0]) * CUR.pts.n_points); 5200 memcpy(save_cy, CUR.pts.cur_y, sizeof(CUR.pts.cur_y[0]) * CUR.pts.n_points); 5201 } 5202 # endif 5203 5204 Instruct_Dispatch[CUR.opcode].p( EXEC_ARGS &CUR.stack[CUR.args] ); 5205 5206 # ifdef DEBUG 5207 if (save_ox != NULL) { 5208 F26Dot6 *pp[4], *qq[4]; 5209 const char *ss[] = {"org.x", "org.y", "cur.x", "cur.y"}; 5210 int l = 0, i, j; 5211 5212 pp[0] = save_ox, 5213 pp[1] = save_oy, 5214 pp[2] = save_cx, 5215 pp[3] = save_cy; 5216 qq[0] = CUR.pts.org_x; 5217 qq[1] = CUR.pts.org_y; 5218 qq[2] = CUR.pts.cur_x; 5219 qq[3] = CUR.pts.cur_y; 5220 5221 for(i = 0; i < 4; i++) 5222 for(j = 0;j < CUR.pts.n_points; j++) 5223 { F26Dot6 *ppi = pp[i], *qqi = qq[i]; 5224 if(ppi[j] != qqi[j] || bFirst) 5225 { 5226 DBG_PRINT4("%% %s[%d]%d:=%d", ss[i], j, pp[i][j], qq[i][j]); 5227 if(++l > 3) 5228 { l=0; 5229 DBG_PRINT("\n"); 5230 } 5231 } 5232 } 5233 nInstrCount++; 5234 bFirst=FALSE; 5235 } 5236 # endif 5237 5238 DBG_PAINT 5239 5240 if ( CUR.error != TT_Err_Ok ) 5241 { 5242 switch ( CUR.error ) 5243 { 5244 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */ 5245 A = 0; 5246 5247 while ( A < CUR.numIDefs ) 5248 { 5249 WITH = &CUR.IDefs[A]; 5250 5251 if ( WITH->Active && CUR.opcode == WITH->Opc ) 5252 { 5253 if ( CUR.callTop >= CUR.callSize ) 5254 { 5255 CUR.error = TT_Err_Invalid_Reference; 5256 goto _LErrorLabel; 5257 } 5258 5259 WITH1 = &CUR.callStack[CUR.callTop]; 5260 5261 WITH1->Caller_Range = CUR.curRange; 5262 WITH1->Caller_IP = CUR.IP + 1; 5263 WITH1->Cur_Count = 1; 5264 WITH1->Cur_Restart = WITH->Start; 5265 5266 if ( INS_Goto_CodeRange( WITH->Range, WITH->Start ) == FAILURE ) 5267 goto _LErrorLabel; 5268 5269 goto _LSuiteLabel; 5270 } 5271 else 5272 { 5273 A++; 5274 continue; 5275 } 5276 } 5277 5278 CUR.error = TT_Err_Invalid_Opcode; 5279 goto _LErrorLabel; 5280 break; 5281 5282 default: 5283 CUR.error = CUR.error; 5284 goto _LErrorLabel; 5285 break; 5286 } 5287 } 5288 5289 CUR.top = CUR.new_top; 5290 5291 if ( CUR.step_ins ) 5292 CUR.IP += CUR.length; 5293 5294 _LSuiteLabel: 5295 5296 if ( CUR.IP >= CUR.codeSize ) 5297 { 5298 if ( CUR.callTop > 0 ) 5299 { 5300 CUR.error = TT_Err_Code_Overflow; 5301 goto _LErrorLabel; 5302 } 5303 else 5304 goto _LNo_Error; 5305 } 5306 } while ( !CUR.instruction_trap ); 5307 5308 _LNo_Error: 5309 Result = TT_Err_Ok; 5310 goto _LExit; 5311 5312 _LErrorLabel: 5313 Result = CUR.error; 5314 DBG_PRINT1("%% ERROR=%d", Result); 5315 _LExit: 5316 # ifdef DEBUG 5317 if (save_ox != NULL) { 5318 mem->free(mem, save_ox, "RunIns"); 5319 mem->free(mem, save_oy, "RunIns"); 5320 mem->free(mem, save_cx, "RunIns"); 5321 mem->free(mem, save_cy, "RunIns"); 5322 } 5323 # endif 5324 5325 return Result; 5326 } 5327