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