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