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