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