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