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