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