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