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