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