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