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