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