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