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