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