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