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