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