Coverage Report

Created: 2022-10-31 07:00

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