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 <ft2build.h>
24#include FT_INTERNAL_DEBUG_H
25#include FT_INTERNAL_CALC_H
26#include FT_TRIGONOMETRY_H
27#include FT_SYSTEM_H
28#include FT_TRUETYPE_DRIVER_H
29
30#include "ttinterp.h"
31#include "tterrors.h"
32#include "ttsubpix.h"
33
34
35#ifdef TT_USE_BYTECODE_INTERPRETER
36
37
38  /*************************************************************************/
39  /*                                                                       */
40  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
41  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
42  /* messages during execution.                                            */
43  /*                                                                       */
44#undef  FT_COMPONENT
45#define FT_COMPONENT  trace_ttinterp
46
47  /*************************************************************************/
48  /*                                                                       */
49  /* 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.GS.freeVector.x != 0 )
5833    {
5834      CUR.zp2.cur[point].x += dx;
5835      if ( touch )
5836        CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5837    }
5838
5839    if ( CUR.GS.freeVector.y != 0 )
5840    {
5841      CUR.zp2.cur[point].y += dy;
5842      if ( touch )
5843        CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5844    }
5845  }
5846
5847
5848  /*************************************************************************/
5849  /*                                                                       */
5850  /* SHP[a]:       SHift Point by the last point                           */
5851  /* Opcode range: 0x32-0x33                                               */
5852  /* Stack:        uint32... -->                                           */
5853  /*                                                                       */
5854  static void
5855  Ins_SHP( INS_ARG )
5856  {
5857    TT_GlyphZoneRec  zp;
5858    FT_UShort        refp;
5859
5860    FT_F26Dot6       dx,
5861                     dy;
5862    FT_UShort        point;
5863
5864    FT_UNUSED_ARG;
5865
5866
5867    if ( CUR.top < CUR.GS.loop )
5868    {
5869      if ( CUR.pedantic_hinting )
5870        CUR.error = FT_THROW( Invalid_Reference );
5871      goto Fail;
5872    }
5873
5874    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5875      return;
5876
5877    while ( CUR.GS.loop > 0 )
5878    {
5879      CUR.args--;
5880      point = (FT_UShort)CUR.stack[CUR.args];
5881
5882      if ( BOUNDS( point, CUR.zp2.n_points ) )
5883      {
5884        if ( CUR.pedantic_hinting )
5885        {
5886          CUR.error = FT_THROW( Invalid_Reference );
5887          return;
5888        }
5889      }
5890      else
5891#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5892      /* doesn't follow Cleartype spec but produces better result */
5893      if ( SUBPIXEL_HINTING  &&
5894           CUR.ignore_x_mode )
5895        MOVE_Zp2_Point( point, 0, dy, TRUE );
5896      else
5897#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5898        MOVE_Zp2_Point( point, dx, dy, TRUE );
5899
5900      CUR.GS.loop--;
5901    }
5902
5903  Fail:
5904    CUR.GS.loop = 1;
5905    CUR.new_top = CUR.args;
5906  }
5907
5908
5909  /*************************************************************************/
5910  /*                                                                       */
5911  /* SHC[a]:       SHift Contour                                           */
5912  /* Opcode range: 0x34-35                                                 */
5913  /* Stack:        uint32 -->                                              */
5914  /*                                                                       */
5915  /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual)     */
5916  /*               contour in the twilight zone, namely contour number     */
5917  /*               zero which includes all points of it.                   */
5918  /*                                                                       */
5919  static void
5920  Ins_SHC( INS_ARG )
5921  {
5922    TT_GlyphZoneRec  zp;
5923    FT_UShort        refp;
5924    FT_F26Dot6       dx, dy;
5925
5926    FT_Short         contour, bounds;
5927    FT_UShort        start, limit, i;
5928
5929
5930    contour = (FT_UShort)args[0];
5931    bounds  = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours;
5932
5933    if ( BOUNDS( contour, bounds ) )
5934    {
5935      if ( CUR.pedantic_hinting )
5936        CUR.error = FT_THROW( Invalid_Reference );
5937      return;
5938    }
5939
5940    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5941      return;
5942
5943    if ( contour == 0 )
5944      start = 0;
5945    else
5946      start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 -
5947                           CUR.zp2.first_point );
5948
5949    /* we use the number of points if in the twilight zone */
5950    if ( CUR.GS.gep2 == 0 )
5951      limit = CUR.zp2.n_points;
5952    else
5953      limit = (FT_UShort)( CUR.zp2.contours[contour] -
5954                           CUR.zp2.first_point + 1 );
5955
5956    for ( i = start; i < limit; i++ )
5957    {
5958      if ( zp.cur != CUR.zp2.cur || refp != i )
5959        MOVE_Zp2_Point( i, dx, dy, TRUE );
5960    }
5961  }
5962
5963
5964  /*************************************************************************/
5965  /*                                                                       */
5966  /* SHZ[a]:       SHift Zone                                              */
5967  /* Opcode range: 0x36-37                                                 */
5968  /* Stack:        uint32 -->                                              */
5969  /*                                                                       */
5970  static void
5971  Ins_SHZ( INS_ARG )
5972  {
5973    TT_GlyphZoneRec  zp;
5974    FT_UShort        refp;
5975    FT_F26Dot6       dx,
5976                     dy;
5977
5978    FT_UShort        limit, i;
5979
5980
5981    if ( BOUNDS( args[0], 2 ) )
5982    {
5983      if ( CUR.pedantic_hinting )
5984        CUR.error = FT_THROW( Invalid_Reference );
5985      return;
5986    }
5987
5988    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5989      return;
5990
5991    /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.     */
5992    /*      Twilight zone has no real contours, so use `n_points'. */
5993    /*      Normal zone's `n_points' includes phantoms, so must    */
5994    /*      use end of last contour.                               */
5995    if ( CUR.GS.gep2 == 0 )
5996      limit = (FT_UShort)CUR.zp2.n_points;
5997    else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
5998      limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 );
5999    else
6000      limit = 0;
6001
6002    /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
6003    for ( i = 0; i < limit; i++ )
6004    {
6005      if ( zp.cur != CUR.zp2.cur || refp != i )
6006        MOVE_Zp2_Point( i, dx, dy, FALSE );
6007    }
6008  }
6009
6010
6011  /*************************************************************************/
6012  /*                                                                       */
6013  /* SHPIX[]:      SHift points by a PIXel amount                          */
6014  /* Opcode range: 0x38                                                    */
6015  /* Stack:        f26.6 uint32... -->                                     */
6016  /*                                                                       */
6017  static void
6018  Ins_SHPIX( INS_ARG )
6019  {
6020    FT_F26Dot6  dx, dy;
6021    FT_UShort   point;
6022#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6023    FT_Int      B1, B2;
6024#endif
6025
6026
6027    if ( CUR.top < CUR.GS.loop + 1 )
6028    {
6029      if ( CUR.pedantic_hinting )
6030        CUR.error = FT_THROW( Invalid_Reference );
6031      goto Fail;
6032    }
6033
6034#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6035    if ( CUR.face->unpatented_hinting )
6036    {
6037      if ( CUR.GS.both_x_axis )
6038      {
6039        dx = (FT_UInt32)args[0];
6040        dy = 0;
6041      }
6042      else
6043      {
6044        dx = 0;
6045        dy = (FT_UInt32)args[0];
6046      }
6047    }
6048    else
6049#endif
6050    {
6051      dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
6052      dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
6053    }
6054
6055    while ( CUR.GS.loop > 0 )
6056    {
6057      CUR.args--;
6058
6059      point = (FT_UShort)CUR.stack[CUR.args];
6060
6061      if ( BOUNDS( point, CUR.zp2.n_points ) )
6062      {
6063        if ( CUR.pedantic_hinting )
6064        {
6065          CUR.error = FT_THROW( Invalid_Reference );
6066          return;
6067        }
6068      }
6069      else
6070#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6071      {
6072        /*  If not using ignore_x_mode rendering, allow ZP2 move.          */
6073        /*  If inline deltas aren't allowed, skip ZP2 move.                */
6074        /*  If using ignore_x_mode rendering, allow ZP2 point move if:     */
6075        /*   - freedom vector is y and sph_compatibility_mode is off       */
6076        /*   - the glyph is composite and the move is in the Y direction   */
6077        /*   - the glyph is specifically set to allow SHPIX moves          */
6078        /*   - the move is on a previously Y-touched point                 */
6079
6080        if ( SUBPIXEL_HINTING  &&
6081             CUR.ignore_x_mode )
6082        {
6083          /* save point for later comparison */
6084          if ( CUR.GS.freeVector.y != 0 )
6085            B1 = CUR.zp2.cur[point].y;
6086          else
6087            B1 = CUR.zp2.cur[point].x;
6088
6089          if ( !CUR.face->sph_compatibility_mode &&
6090               CUR.GS.freeVector.y != 0          )
6091          {
6092            MOVE_Zp2_Point( point, dx, dy, TRUE );
6093
6094            /* save new point */
6095            if ( CUR.GS.freeVector.y != 0 )
6096            {
6097              B2 = CUR.zp2.cur[point].y;
6098
6099              /* reverse any disallowed moves */
6100              if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6101                   ( B1 & 63 ) != 0                                          &&
6102                   ( B2 & 63 ) != 0                                          &&
6103                    B1 != B2                                                 )
6104                MOVE_Zp2_Point( point, -dx, -dy, TRUE );
6105            }
6106          }
6107          else if ( CUR.face->sph_compatibility_mode )
6108          {
6109            if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
6110            {
6111              dx = FT_PIX_ROUND( B1 + dx ) - B1;
6112              dy = FT_PIX_ROUND( B1 + dy ) - B1;
6113            }
6114
6115            /* skip post-iup deltas */
6116            if ( CUR.iup_called                                          &&
6117                 ( ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
6118                   ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
6119              goto Skip;
6120
6121            if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
6122                  ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ||
6123                    ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )   ||
6124                    ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX )     )   )
6125              MOVE_Zp2_Point( point, 0, dy, TRUE );
6126
6127            /* save new point */
6128            if ( CUR.GS.freeVector.y != 0 )
6129            {
6130              B2 = CUR.zp2.cur[point].y;
6131
6132              /* reverse any disallowed moves */
6133              if ( ( B1 & 63 ) == 0 &&
6134                   ( B2 & 63 ) != 0 &&
6135                   B1 != B2         )
6136                MOVE_Zp2_Point( point, 0, -dy, TRUE );
6137            }
6138          }
6139          else if ( CUR.sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
6140            MOVE_Zp2_Point( point, dx, dy, TRUE );
6141        }
6142        else
6143          MOVE_Zp2_Point( point, dx, dy, TRUE );
6144      }
6145
6146    Skip:
6147
6148#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6149
6150        MOVE_Zp2_Point( point, dx, dy, TRUE );
6151
6152#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6153
6154      CUR.GS.loop--;
6155    }
6156
6157  Fail:
6158    CUR.GS.loop = 1;
6159    CUR.new_top = CUR.args;
6160  }
6161
6162
6163  /*************************************************************************/
6164  /*                                                                       */
6165  /* MSIRP[a]:     Move Stack Indirect Relative Position                   */
6166  /* Opcode range: 0x3A-0x3B                                               */
6167  /* Stack:        f26.6 uint32 -->                                        */
6168  /*                                                                       */
6169  static void
6170  Ins_MSIRP( INS_ARG )
6171  {
6172    FT_UShort   point;
6173    FT_F26Dot6  distance;
6174
6175#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6176    FT_F26Dot6  control_value_cutin;
6177
6178
6179    if ( SUBPIXEL_HINTING )
6180    {
6181      control_value_cutin = CUR.GS.control_value_cutin;
6182
6183      if ( CUR.ignore_x_mode                                 &&
6184           CUR.GS.freeVector.x != 0                          &&
6185           !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6186        control_value_cutin = 0;
6187    }
6188
6189#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6190
6191    point = (FT_UShort)args[0];
6192
6193    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
6194         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6195    {
6196      if ( CUR.pedantic_hinting )
6197        CUR.error = FT_THROW( Invalid_Reference );
6198      return;
6199    }
6200
6201    /* UNDOCUMENTED!  The MS rasterizer does that with */
6202    /* twilight points (confirmed by Greg Hitchcock)   */
6203    if ( CUR.GS.gep1 == 0 )
6204    {
6205      CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
6206      CUR_Func_move_orig( &CUR.zp1, point, args[1] );
6207      CUR.zp1.cur[point] = CUR.zp1.org[point];
6208    }
6209
6210    distance = CUR_Func_project( CUR.zp1.cur + point,
6211                                 CUR.zp0.cur + CUR.GS.rp0 );
6212
6213#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6214    /* subpixel hinting - make MSIRP respect CVT cut-in; */
6215    if ( SUBPIXEL_HINTING                                    &&
6216         CUR.ignore_x_mode                                   &&
6217         CUR.GS.freeVector.x != 0                            &&
6218         FT_ABS( distance - args[1] ) >= control_value_cutin )
6219      distance = args[1];
6220#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6221
6222    CUR_Func_move( &CUR.zp1, point, args[1] - distance );
6223
6224    CUR.GS.rp1 = CUR.GS.rp0;
6225    CUR.GS.rp2 = point;
6226
6227    if ( ( CUR.opcode & 1 ) != 0 )
6228      CUR.GS.rp0 = point;
6229  }
6230
6231
6232  /*************************************************************************/
6233  /*                                                                       */
6234  /* MDAP[a]:      Move Direct Absolute Point                              */
6235  /* Opcode range: 0x2E-0x2F                                               */
6236  /* Stack:        uint32 -->                                              */
6237  /*                                                                       */
6238  static void
6239  Ins_MDAP( INS_ARG )
6240  {
6241    FT_UShort   point;
6242    FT_F26Dot6  cur_dist;
6243    FT_F26Dot6  distance;
6244
6245
6246    point = (FT_UShort)args[0];
6247
6248    if ( BOUNDS( point, CUR.zp0.n_points ) )
6249    {
6250      if ( CUR.pedantic_hinting )
6251        CUR.error = FT_THROW( Invalid_Reference );
6252      return;
6253    }
6254
6255    if ( ( CUR.opcode & 1 ) != 0 )
6256    {
6257      cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6258#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6259      if ( SUBPIXEL_HINTING         &&
6260           CUR.ignore_x_mode        &&
6261           CUR.GS.freeVector.x != 0 )
6262        distance = ROUND_None(
6263                     cur_dist,
6264                     CUR.tt_metrics.compensations[0] ) - cur_dist;
6265      else
6266#endif
6267        distance = CUR_Func_round(
6268                     cur_dist,
6269                     CUR.tt_metrics.compensations[0] ) - cur_dist;
6270    }
6271    else
6272      distance = 0;
6273
6274    CUR_Func_move( &CUR.zp0, point, distance );
6275
6276    CUR.GS.rp0 = point;
6277    CUR.GS.rp1 = point;
6278  }
6279
6280
6281  /*************************************************************************/
6282  /*                                                                       */
6283  /* MIAP[a]:      Move Indirect Absolute Point                            */
6284  /* Opcode range: 0x3E-0x3F                                               */
6285  /* Stack:        uint32 uint32 -->                                       */
6286  /*                                                                       */
6287  static void
6288  Ins_MIAP( INS_ARG )
6289  {
6290    FT_ULong    cvtEntry;
6291    FT_UShort   point;
6292    FT_F26Dot6  distance;
6293    FT_F26Dot6  org_dist;
6294    FT_F26Dot6  control_value_cutin;
6295
6296
6297    control_value_cutin = CUR.GS.control_value_cutin;
6298    cvtEntry            = (FT_ULong)args[1];
6299    point               = (FT_UShort)args[0];
6300
6301#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6302    if ( SUBPIXEL_HINTING                                  &&
6303         CUR.ignore_x_mode                                 &&
6304         CUR.GS.freeVector.x != 0                          &&
6305         CUR.GS.freeVector.y == 0                          &&
6306         !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6307      control_value_cutin = 0;
6308#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6309
6310    if ( BOUNDS( point,     CUR.zp0.n_points ) ||
6311         BOUNDSL( cvtEntry, CUR.cvtSize )      )
6312    {
6313      if ( CUR.pedantic_hinting )
6314        CUR.error = FT_THROW( Invalid_Reference );
6315      goto Fail;
6316    }
6317
6318    /* UNDOCUMENTED!                                                      */
6319    /*                                                                    */
6320    /* The behaviour of an MIAP instruction is quite different when used  */
6321    /* in the twilight zone.                                              */
6322    /*                                                                    */
6323    /* First, no control value cut-in test is performed as it would fail  */
6324    /* anyway.  Second, the original point, i.e. (org_x,org_y) of         */
6325    /* zp0.point, is set to the absolute, unrounded distance found in the */
6326    /* CVT.                                                               */
6327    /*                                                                    */
6328    /* This is used in the CVT programs of the Microsoft fonts Arial,     */
6329    /* Times, etc., in order to re-adjust some key font heights.  It      */
6330    /* allows the use of the IP instruction in the twilight zone, which   */
6331    /* otherwise would be invalid according to the specification.         */
6332    /*                                                                    */
6333    /* We implement it with a special sequence for the twilight zone.     */
6334    /* This is a bad hack, but it seems to work.                          */
6335    /*                                                                    */
6336    /* Confirmed by Greg Hitchcock.                                       */
6337
6338    distance = CUR_Func_read_cvt( cvtEntry );
6339
6340    if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
6341    {
6342#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6343      /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
6344      /* Determined via experimentation and may be incorrect...         */
6345      if ( !SUBPIXEL_HINTING                     ||
6346           ( !CUR.ignore_x_mode                ||
6347             !CUR.face->sph_compatibility_mode ) )
6348#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6349        CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
6350                                            CUR.GS.freeVector.x );
6351      CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
6352                                          CUR.GS.freeVector.y ),
6353      CUR.zp0.cur[point]   = CUR.zp0.org[point];
6354    }
6355#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6356    if ( SUBPIXEL_HINTING                              &&
6357         CUR.ignore_x_mode                             &&
6358         ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
6359         distance > 0                                  &&
6360         CUR.GS.freeVector.y != 0                      )
6361      distance = 0;
6362#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6363
6364    org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6365
6366    if ( ( CUR.opcode & 1 ) != 0 )   /* rounding and control cut-in flag */
6367    {
6368      if ( FT_ABS( distance - org_dist ) > control_value_cutin )
6369        distance = org_dist;
6370
6371#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6372      if ( SUBPIXEL_HINTING         &&
6373           CUR.ignore_x_mode        &&
6374           CUR.GS.freeVector.x != 0 )
6375        distance = ROUND_None( distance,
6376                               CUR.tt_metrics.compensations[0] );
6377      else
6378#endif
6379        distance = CUR_Func_round( distance,
6380                                   CUR.tt_metrics.compensations[0] );
6381    }
6382
6383    CUR_Func_move( &CUR.zp0, point, distance - org_dist );
6384
6385  Fail:
6386    CUR.GS.rp0 = point;
6387    CUR.GS.rp1 = point;
6388  }
6389
6390
6391  /*************************************************************************/
6392  /*                                                                       */
6393  /* MDRP[abcde]:  Move Direct Relative Point                              */
6394  /* Opcode range: 0xC0-0xDF                                               */
6395  /* Stack:        uint32 -->                                              */
6396  /*                                                                       */
6397  static void
6398  Ins_MDRP( INS_ARG )
6399  {
6400    FT_UShort   point;
6401    FT_F26Dot6  org_dist, distance, minimum_distance;
6402
6403
6404    minimum_distance = CUR.GS.minimum_distance;
6405
6406#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6407    if ( SUBPIXEL_HINTING                                  &&
6408         CUR.ignore_x_mode                                 &&
6409         CUR.GS.freeVector.x != 0                          &&
6410         !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6411      minimum_distance = 0;
6412#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6413
6414    point = (FT_UShort)args[0];
6415
6416    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
6417         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6418    {
6419      if ( CUR.pedantic_hinting )
6420        CUR.error = FT_THROW( Invalid_Reference );
6421      goto Fail;
6422    }
6423
6424    /* XXX: Is there some undocumented feature while in the */
6425    /*      twilight zone?                                  */
6426
6427    /* XXX: UNDOCUMENTED: twilight zone special case */
6428
6429    if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
6430    {
6431      FT_Vector*  vec1 = &CUR.zp1.org[point];
6432      FT_Vector*  vec2 = &CUR.zp0.org[CUR.GS.rp0];
6433
6434
6435      org_dist = CUR_Func_dualproj( vec1, vec2 );
6436    }
6437    else
6438    {
6439      FT_Vector*  vec1 = &CUR.zp1.orus[point];
6440      FT_Vector*  vec2 = &CUR.zp0.orus[CUR.GS.rp0];
6441
6442
6443      if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6444      {
6445        /* this should be faster */
6446        org_dist = CUR_Func_dualproj( vec1, vec2 );
6447        org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale );
6448      }
6449      else
6450      {
6451        FT_Vector  vec;
6452
6453
6454        vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
6455        vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
6456
6457        org_dist = CUR_fast_dualproj( &vec );
6458      }
6459    }
6460
6461    /* single width cut-in test */
6462
6463    if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
6464         CUR.GS.single_width_cutin )
6465    {
6466      if ( org_dist >= 0 )
6467        org_dist = CUR.GS.single_width_value;
6468      else
6469        org_dist = -CUR.GS.single_width_value;
6470    }
6471
6472    /* round flag */
6473
6474    if ( ( CUR.opcode & 4 ) != 0 )
6475    {
6476#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6477      if ( SUBPIXEL_HINTING         &&
6478           CUR.ignore_x_mode        &&
6479           CUR.GS.freeVector.x != 0 )
6480        distance = ROUND_None(
6481                     org_dist,
6482                     CUR.tt_metrics.compensations[CUR.opcode & 3] );
6483      else
6484#endif
6485      distance = CUR_Func_round(
6486                   org_dist,
6487                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
6488    }
6489    else
6490      distance = ROUND_None(
6491                   org_dist,
6492                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
6493
6494    /* minimum distance flag */
6495
6496    if ( ( CUR.opcode & 8 ) != 0 )
6497    {
6498      if ( org_dist >= 0 )
6499      {
6500        if ( distance < minimum_distance )
6501          distance = minimum_distance;
6502      }
6503      else
6504      {
6505        if ( distance > -minimum_distance )
6506          distance = -minimum_distance;
6507      }
6508    }
6509
6510    /* now move the point */
6511
6512    org_dist = CUR_Func_project( CUR.zp1.cur + point,
6513                                 CUR.zp0.cur + CUR.GS.rp0 );
6514
6515    CUR_Func_move( &CUR.zp1, point, distance - org_dist );
6516
6517  Fail:
6518    CUR.GS.rp1 = CUR.GS.rp0;
6519    CUR.GS.rp2 = point;
6520
6521    if ( ( CUR.opcode & 16 ) != 0 )
6522      CUR.GS.rp0 = point;
6523  }
6524
6525
6526  /*************************************************************************/
6527  /*                                                                       */
6528  /* MIRP[abcde]:  Move Indirect Relative Point                            */
6529  /* Opcode range: 0xE0-0xFF                                               */
6530  /* Stack:        int32? uint32 -->                                       */
6531  /*                                                                       */
6532  static void
6533  Ins_MIRP( INS_ARG )
6534  {
6535    FT_UShort   point;
6536    FT_ULong    cvtEntry;
6537
6538    FT_F26Dot6  cvt_dist,
6539                distance,
6540                cur_dist,
6541                org_dist,
6542                control_value_cutin,
6543                minimum_distance;
6544#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6545    FT_Int      B1;
6546    FT_Int      B2;
6547    FT_Bool     reverse_move = FALSE;
6548#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6549
6550
6551    minimum_distance    = CUR.GS.minimum_distance;
6552    control_value_cutin = CUR.GS.control_value_cutin;
6553    point               = (FT_UShort)args[0];
6554    cvtEntry            = (FT_ULong)( args[1] + 1 );
6555
6556#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6557    if ( SUBPIXEL_HINTING                                  &&
6558         CUR.ignore_x_mode                                 &&
6559         CUR.GS.freeVector.x != 0                          &&
6560         !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6561      control_value_cutin = minimum_distance = 0;
6562#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6563
6564    /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6565
6566    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
6567         BOUNDSL( cvtEntry,  CUR.cvtSize + 1 )  ||
6568         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6569    {
6570      if ( CUR.pedantic_hinting )
6571        CUR.error = FT_THROW( Invalid_Reference );
6572      goto Fail;
6573    }
6574
6575    if ( !cvtEntry )
6576      cvt_dist = 0;
6577    else
6578      cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
6579
6580    /* single width test */
6581
6582    if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
6583         CUR.GS.single_width_cutin )
6584    {
6585      if ( cvt_dist >= 0 )
6586        cvt_dist =  CUR.GS.single_width_value;
6587      else
6588        cvt_dist = -CUR.GS.single_width_value;
6589    }
6590
6591    /* UNDOCUMENTED!  The MS rasterizer does that with */
6592    /* twilight points (confirmed by Greg Hitchcock)   */
6593    if ( CUR.GS.gep1 == 0 )
6594    {
6595      CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
6596                             TT_MulFix14( (FT_UInt32)cvt_dist,
6597                                          CUR.GS.freeVector.x );
6598      CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
6599                             TT_MulFix14( (FT_UInt32)cvt_dist,
6600                                          CUR.GS.freeVector.y );
6601      CUR.zp1.cur[point]   = CUR.zp1.org[point];
6602    }
6603
6604    org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
6605                                  &CUR.zp0.org[CUR.GS.rp0] );
6606    cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
6607                                  &CUR.zp0.cur[CUR.GS.rp0] );
6608
6609    /* auto-flip test */
6610
6611    if ( CUR.GS.auto_flip )
6612    {
6613      if ( ( org_dist ^ cvt_dist ) < 0 )
6614        cvt_dist = -cvt_dist;
6615    }
6616
6617#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6618    if ( SUBPIXEL_HINTING                                         &&
6619         CUR.ignore_x_mode                                        &&
6620         CUR.GS.freeVector.y != 0                                 &&
6621         ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6622    {
6623      if ( cur_dist < -64 )
6624        cvt_dist -= 16;
6625      else if ( cur_dist > 64 && cur_dist < 84 )
6626        cvt_dist += 32;
6627    }
6628#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6629
6630    /* control value cut-in and round */
6631
6632    if ( ( CUR.opcode & 4 ) != 0 )
6633    {
6634      /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
6635      /*      refer to the same zone.                                  */
6636
6637      if ( CUR.GS.gep0 == CUR.GS.gep1 )
6638      {
6639        /* XXX: According to Greg Hitchcock, the following wording is */
6640        /*      the right one:                                        */
6641        /*                                                            */
6642        /*        When the absolute difference between the value in   */
6643        /*        the table [CVT] and the measurement directly from   */
6644        /*        the outline is _greater_ than the cut_in value, the */
6645        /*        outline measurement is used.                        */
6646        /*                                                            */
6647        /*      This is from `instgly.doc'.  The description in       */
6648        /*      `ttinst2.doc', version 1.66, is thus incorrect since  */
6649        /*      it implies `>=' instead of `>'.                       */
6650
6651        if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6652          cvt_dist = org_dist;
6653      }
6654
6655      distance = CUR_Func_round(
6656                   cvt_dist,
6657                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
6658    }
6659    else
6660    {
6661
6662#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6663      /* do cvt cut-in always in MIRP for sph */
6664      if ( SUBPIXEL_HINTING           &&
6665           CUR.ignore_x_mode          &&
6666           CUR.GS.gep0 == CUR.GS.gep1 )
6667      {
6668        if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6669          cvt_dist = org_dist;
6670      }
6671#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6672
6673      distance = ROUND_None(
6674                   cvt_dist,
6675                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
6676    }
6677
6678    /* minimum distance test */
6679
6680    if ( ( CUR.opcode & 8 ) != 0 )
6681    {
6682      if ( org_dist >= 0 )
6683      {
6684        if ( distance < minimum_distance )
6685          distance = minimum_distance;
6686      }
6687      else
6688      {
6689        if ( distance > -minimum_distance )
6690          distance = -minimum_distance;
6691      }
6692    }
6693
6694#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6695    if ( SUBPIXEL_HINTING )
6696    {
6697      B1 = CUR.zp1.cur[point].y;
6698
6699      /* Round moves if necessary */
6700      if ( CUR.ignore_x_mode                                          &&
6701           CUR.GS.freeVector.y != 0                                   &&
6702           ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
6703        distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
6704
6705      if ( CUR.ignore_x_mode                                      &&
6706           CUR.GS.freeVector.y != 0                               &&
6707           ( CUR.opcode & 16 ) == 0                               &&
6708           ( CUR.opcode & 8 ) == 0                                &&
6709           ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
6710        distance += 64;
6711    }
6712#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6713
6714    CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
6715
6716#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6717    if ( SUBPIXEL_HINTING )
6718    {
6719      B2 = CUR.zp1.cur[point].y;
6720
6721      /* Reverse move if necessary */
6722      if ( CUR.ignore_x_mode )
6723      {
6724        if ( CUR.face->sph_compatibility_mode                          &&
6725             CUR.GS.freeVector.y != 0                                  &&
6726             ( B1 & 63 ) == 0                                          &&
6727             ( B2 & 63 ) != 0                                          )
6728          reverse_move = TRUE;
6729
6730        if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6731             CUR.GS.freeVector.y != 0                                  &&
6732             ( B2 & 63 ) != 0                                          &&
6733             ( B1 & 63 ) != 0                                          )
6734          reverse_move = TRUE;
6735      }
6736
6737      if ( reverse_move )
6738        CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
6739    }
6740
6741#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6742
6743  Fail:
6744    CUR.GS.rp1 = CUR.GS.rp0;
6745
6746    if ( ( CUR.opcode & 16 ) != 0 )
6747      CUR.GS.rp0 = point;
6748
6749    CUR.GS.rp2 = point;
6750  }
6751
6752
6753  /*************************************************************************/
6754  /*                                                                       */
6755  /* ALIGNRP[]:    ALIGN Relative Point                                    */
6756  /* Opcode range: 0x3C                                                    */
6757  /* Stack:        uint32 uint32... -->                                    */
6758  /*                                                                       */
6759  static void
6760  Ins_ALIGNRP( INS_ARG )
6761  {
6762    FT_UShort   point;
6763    FT_F26Dot6  distance;
6764
6765    FT_UNUSED_ARG;
6766
6767
6768#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6769    if ( SUBPIXEL_HINTING                                         &&
6770         CUR.ignore_x_mode                                        &&
6771         CUR.iup_called                                           &&
6772         ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6773    {
6774      CUR.error = FT_THROW( Invalid_Reference );
6775      goto Fail;
6776    }
6777#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6778
6779    if ( CUR.top < CUR.GS.loop ||
6780         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6781    {
6782      if ( CUR.pedantic_hinting )
6783        CUR.error = FT_THROW( Invalid_Reference );
6784      goto Fail;
6785    }
6786
6787    while ( CUR.GS.loop > 0 )
6788    {
6789      CUR.args--;
6790
6791      point = (FT_UShort)CUR.stack[CUR.args];
6792
6793      if ( BOUNDS( point, CUR.zp1.n_points ) )
6794      {
6795        if ( CUR.pedantic_hinting )
6796        {
6797          CUR.error = FT_THROW( Invalid_Reference );
6798          return;
6799        }
6800      }
6801      else
6802      {
6803        distance = CUR_Func_project( CUR.zp1.cur + point,
6804                                     CUR.zp0.cur + CUR.GS.rp0 );
6805
6806        CUR_Func_move( &CUR.zp1, point, -distance );
6807      }
6808
6809      CUR.GS.loop--;
6810    }
6811
6812  Fail:
6813    CUR.GS.loop = 1;
6814    CUR.new_top = CUR.args;
6815  }
6816
6817
6818  /*************************************************************************/
6819  /*                                                                       */
6820  /* ISECT[]:      moves point to InterSECTion                             */
6821  /* Opcode range: 0x0F                                                    */
6822  /* Stack:        5 * uint32 -->                                          */
6823  /*                                                                       */
6824  static void
6825  Ins_ISECT( INS_ARG )
6826  {
6827    FT_UShort   point,
6828                a0, a1,
6829                b0, b1;
6830
6831    FT_F26Dot6  discriminant, dotproduct;
6832
6833    FT_F26Dot6  dx,  dy,
6834                dax, day,
6835                dbx, dby;
6836
6837    FT_F26Dot6  val;
6838
6839    FT_Vector   R;
6840
6841
6842    point = (FT_UShort)args[0];
6843
6844    a0 = (FT_UShort)args[1];
6845    a1 = (FT_UShort)args[2];
6846    b0 = (FT_UShort)args[3];
6847    b1 = (FT_UShort)args[4];
6848
6849    if ( BOUNDS( b0, CUR.zp0.n_points )  ||
6850         BOUNDS( b1, CUR.zp0.n_points )  ||
6851         BOUNDS( a0, CUR.zp1.n_points )  ||
6852         BOUNDS( a1, CUR.zp1.n_points )  ||
6853         BOUNDS( point, CUR.zp2.n_points ) )
6854    {
6855      if ( CUR.pedantic_hinting )
6856        CUR.error = FT_THROW( Invalid_Reference );
6857      return;
6858    }
6859
6860    /* Cramer's rule */
6861
6862    dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6863    dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6864
6865    dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6866    day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6867
6868    dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6869    dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6870
6871    CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6872
6873    discriminant = FT_MulDiv( dax, -dby, 0x40 ) +
6874                   FT_MulDiv( day, dbx, 0x40 );
6875    dotproduct   = FT_MulDiv( dax, dbx, 0x40 ) +
6876                   FT_MulDiv( day, dby, 0x40 );
6877
6878    /* The discriminant above is actually a cross product of vectors     */
6879    /* da and db. Together with the dot product, they can be used as     */
6880    /* surrogates for sine and cosine of the angle between the vectors.  */
6881    /* Indeed,                                                           */
6882    /*       dotproduct   = |da||db|cos(angle)                           */
6883    /*       discriminant = |da||db|sin(angle)     .                     */
6884    /* We use these equations to reject grazing intersections by         */
6885    /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
6886    if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) )
6887    {
6888      val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 );
6889
6890      R.x = FT_MulDiv( val, dax, discriminant );
6891      R.y = FT_MulDiv( val, day, discriminant );
6892
6893      CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6894      CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6895    }
6896    else
6897    {
6898      /* else, take the middle of the middles of A and B */
6899
6900      CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6901                               CUR.zp1.cur[a1].x +
6902                               CUR.zp0.cur[b0].x +
6903                               CUR.zp0.cur[b1].x ) / 4;
6904      CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6905                               CUR.zp1.cur[a1].y +
6906                               CUR.zp0.cur[b0].y +
6907                               CUR.zp0.cur[b1].y ) / 4;
6908    }
6909  }
6910
6911
6912  /*************************************************************************/
6913  /*                                                                       */
6914  /* ALIGNPTS[]:   ALIGN PoinTS                                            */
6915  /* Opcode range: 0x27                                                    */
6916  /* Stack:        uint32 uint32 -->                                       */
6917  /*                                                                       */
6918  static void
6919  Ins_ALIGNPTS( INS_ARG )
6920  {
6921    FT_UShort   p1, p2;
6922    FT_F26Dot6  distance;
6923
6924
6925    p1 = (FT_UShort)args[0];
6926    p2 = (FT_UShort)args[1];
6927
6928    if ( BOUNDS( p1, CUR.zp1.n_points ) ||
6929         BOUNDS( p2, CUR.zp0.n_points ) )
6930    {
6931      if ( CUR.pedantic_hinting )
6932        CUR.error = FT_THROW( Invalid_Reference );
6933      return;
6934    }
6935
6936    distance = CUR_Func_project( CUR.zp0.cur + p2,
6937                                 CUR.zp1.cur + p1 ) / 2;
6938
6939    CUR_Func_move( &CUR.zp1, p1, distance );
6940    CUR_Func_move( &CUR.zp0, p2, -distance );
6941  }
6942
6943
6944  /*************************************************************************/
6945  /*                                                                       */
6946  /* IP[]:         Interpolate Point                                       */
6947  /* Opcode range: 0x39                                                    */
6948  /* Stack:        uint32... -->                                           */
6949  /*                                                                       */
6950
6951  /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6952
6953  static void
6954  Ins_IP( INS_ARG )
6955  {
6956    FT_F26Dot6  old_range, cur_range;
6957    FT_Vector*  orus_base;
6958    FT_Vector*  cur_base;
6959    FT_Int      twilight;
6960
6961    FT_UNUSED_ARG;
6962
6963
6964    if ( CUR.top < CUR.GS.loop )
6965    {
6966      if ( CUR.pedantic_hinting )
6967        CUR.error = FT_THROW( Invalid_Reference );
6968      goto Fail;
6969    }
6970
6971    /*
6972     * We need to deal in a special way with the twilight zone.
6973     * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6974     * for every n.
6975     */
6976    twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
6977
6978    if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
6979    {
6980      if ( CUR.pedantic_hinting )
6981        CUR.error = FT_THROW( Invalid_Reference );
6982      goto Fail;
6983    }
6984
6985    if ( twilight )
6986      orus_base = &CUR.zp0.org[CUR.GS.rp1];
6987    else
6988      orus_base = &CUR.zp0.orus[CUR.GS.rp1];
6989
6990    cur_base = &CUR.zp0.cur[CUR.GS.rp1];
6991
6992    /* XXX: There are some glyphs in some braindead but popular */
6993    /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
6994    /*      calling IP[] with bad values of rp[12].             */
6995    /*      Do something sane when this odd thing happens.      */
6996    if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
6997         BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
6998    {
6999      old_range = 0;
7000      cur_range = 0;
7001    }
7002    else
7003    {
7004      if ( twilight )
7005        old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
7006                                       orus_base );
7007      else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
7008        old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
7009                                       orus_base );
7010      else
7011      {
7012        FT_Vector  vec;
7013
7014
7015        vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
7016                           CUR.metrics.x_scale );
7017        vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
7018                           CUR.metrics.y_scale );
7019
7020        old_range = CUR_fast_dualproj( &vec );
7021      }
7022
7023      cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
7024    }
7025
7026    for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
7027    {
7028      FT_UInt     point = (FT_UInt)CUR.stack[--CUR.args];
7029      FT_F26Dot6  org_dist, cur_dist, new_dist;
7030
7031
7032      /* check point bounds */
7033      if ( BOUNDS( point, CUR.zp2.n_points ) )
7034      {
7035        if ( CUR.pedantic_hinting )
7036        {
7037          CUR.error = FT_THROW( Invalid_Reference );
7038          return;
7039        }
7040        continue;
7041      }
7042
7043      if ( twilight )
7044        org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
7045      else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
7046        org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
7047      else
7048      {
7049        FT_Vector  vec;
7050
7051
7052        vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x,
7053                           CUR.metrics.x_scale );
7054        vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y,
7055                           CUR.metrics.y_scale );
7056
7057        org_dist = CUR_fast_dualproj( &vec );
7058      }
7059
7060      cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
7061
7062      if ( org_dist )
7063      {
7064        if ( old_range )
7065          new_dist = FT_MulDiv( org_dist, cur_range, old_range );
7066        else
7067        {
7068          /* This is the same as what MS does for the invalid case:  */
7069          /*                                                         */
7070          /*   delta = (Original_Pt - Original_RP1) -                */
7071          /*           (Current_Pt - Current_RP1)                    */
7072          /*                                                         */
7073          /* In FreeType speak:                                      */
7074          /*                                                         */
7075          /*   new_dist = cur_dist -                                 */
7076          /*              org_dist - cur_dist;                       */
7077
7078          new_dist = -org_dist;
7079        }
7080      }
7081      else
7082        new_dist = 0;
7083
7084      CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
7085    }
7086
7087  Fail:
7088    CUR.GS.loop = 1;
7089    CUR.new_top = CUR.args;
7090  }
7091
7092
7093  /*************************************************************************/
7094  /*                                                                       */
7095  /* UTP[a]:       UnTouch Point                                           */
7096  /* Opcode range: 0x29                                                    */
7097  /* Stack:        uint32 -->                                              */
7098  /*                                                                       */
7099  static void
7100  Ins_UTP( INS_ARG )
7101  {
7102    FT_UShort  point;
7103    FT_Byte    mask;
7104
7105
7106    point = (FT_UShort)args[0];
7107
7108    if ( BOUNDS( point, CUR.zp0.n_points ) )
7109    {
7110      if ( CUR.pedantic_hinting )
7111        CUR.error = FT_THROW( Invalid_Reference );
7112      return;
7113    }
7114
7115    mask = 0xFF;
7116
7117    if ( CUR.GS.freeVector.x != 0 )
7118      mask &= ~FT_CURVE_TAG_TOUCH_X;
7119
7120    if ( CUR.GS.freeVector.y != 0 )
7121      mask &= ~FT_CURVE_TAG_TOUCH_Y;
7122
7123    CUR.zp0.tags[point] &= mask;
7124  }
7125
7126
7127  /* Local variables for Ins_IUP: */
7128  typedef struct  IUP_WorkerRec_
7129  {
7130    FT_Vector*  orgs;   /* original and current coordinate */
7131    FT_Vector*  curs;   /* arrays                          */
7132    FT_Vector*  orus;
7133    FT_UInt     max_points;
7134
7135  } IUP_WorkerRec, *IUP_Worker;
7136
7137
7138  static void
7139  _iup_worker_shift( IUP_Worker  worker,
7140                     FT_UInt     p1,
7141                     FT_UInt     p2,
7142                     FT_UInt     p )
7143  {
7144    FT_UInt     i;
7145    FT_F26Dot6  dx;
7146
7147
7148    dx = worker->curs[p].x - worker->orgs[p].x;
7149    if ( dx != 0 )
7150    {
7151      for ( i = p1; i < p; i++ )
7152        worker->curs[i].x += dx;
7153
7154      for ( i = p + 1; i <= p2; i++ )
7155        worker->curs[i].x += dx;
7156    }
7157  }
7158
7159
7160  static void
7161  _iup_worker_interpolate( IUP_Worker  worker,
7162                           FT_UInt     p1,
7163                           FT_UInt     p2,
7164                           FT_UInt     ref1,
7165                           FT_UInt     ref2 )
7166  {
7167    FT_UInt     i;
7168    FT_F26Dot6  orus1, orus2, org1, org2, delta1, delta2;
7169
7170
7171    if ( p1 > p2 )
7172      return;
7173
7174    if ( BOUNDS( ref1, worker->max_points ) ||
7175         BOUNDS( ref2, worker->max_points ) )
7176      return;
7177
7178    orus1 = worker->orus[ref1].x;
7179    orus2 = worker->orus[ref2].x;
7180
7181    if ( orus1 > orus2 )
7182    {
7183      FT_F26Dot6  tmp_o;
7184      FT_UInt     tmp_r;
7185
7186
7187      tmp_o = orus1;
7188      orus1 = orus2;
7189      orus2 = tmp_o;
7190
7191      tmp_r = ref1;
7192      ref1  = ref2;
7193      ref2  = tmp_r;
7194    }
7195
7196    org1   = worker->orgs[ref1].x;
7197    org2   = worker->orgs[ref2].x;
7198    delta1 = worker->curs[ref1].x - org1;
7199    delta2 = worker->curs[ref2].x - org2;
7200
7201    if ( orus1 == orus2 )
7202    {
7203      /* simple shift of untouched points */
7204      for ( i = p1; i <= p2; i++ )
7205      {
7206        FT_F26Dot6  x = worker->orgs[i].x;
7207
7208
7209        if ( x <= org1 )
7210          x += delta1;
7211        else
7212          x += delta2;
7213
7214        worker->curs[i].x = x;
7215      }
7216    }
7217    else
7218    {
7219      FT_Fixed  scale       = 0;
7220      FT_Bool   scale_valid = 0;
7221
7222
7223      /* interpolation */
7224      for ( i = p1; i <= p2; i++ )
7225      {
7226        FT_F26Dot6  x = worker->orgs[i].x;
7227
7228
7229        if ( x <= org1 )
7230          x += delta1;
7231
7232        else if ( x >= org2 )
7233          x += delta2;
7234
7235        else
7236        {
7237          if ( !scale_valid )
7238          {
7239            scale_valid = 1;
7240            scale       = FT_DivFix( org2 + delta2 - ( org1 + delta1 ),
7241                                     orus2 - orus1 );
7242          }
7243
7244          x = ( org1 + delta1 ) +
7245              FT_MulFix( worker->orus[i].x - orus1, scale );
7246        }
7247        worker->curs[i].x = x;
7248      }
7249    }
7250  }
7251
7252
7253  /*************************************************************************/
7254  /*                                                                       */
7255  /* IUP[a]:       Interpolate Untouched Points                            */
7256  /* Opcode range: 0x30-0x31                                               */
7257  /* Stack:        -->                                                     */
7258  /*                                                                       */
7259  static void
7260  Ins_IUP( INS_ARG )
7261  {
7262    IUP_WorkerRec  V;
7263    FT_Byte        mask;
7264
7265    FT_UInt   first_point;   /* first point of contour        */
7266    FT_UInt   end_point;     /* end point (last+1) of contour */
7267
7268    FT_UInt   first_touched; /* first touched point in contour   */
7269    FT_UInt   cur_touched;   /* current touched point in contour */
7270
7271    FT_UInt   point;         /* current point   */
7272    FT_Short  contour;       /* current contour */
7273
7274    FT_UNUSED_ARG;
7275
7276
7277    /* ignore empty outlines */
7278    if ( CUR.pts.n_contours == 0 )
7279      return;
7280
7281    if ( CUR.opcode & 1 )
7282    {
7283      mask   = FT_CURVE_TAG_TOUCH_X;
7284      V.orgs = CUR.pts.org;
7285      V.curs = CUR.pts.cur;
7286      V.orus = CUR.pts.orus;
7287    }
7288    else
7289    {
7290      mask   = FT_CURVE_TAG_TOUCH_Y;
7291      V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
7292      V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
7293      V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
7294    }
7295    V.max_points = CUR.pts.n_points;
7296
7297    contour = 0;
7298    point   = 0;
7299
7300#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7301    if ( SUBPIXEL_HINTING  &&
7302         CUR.ignore_x_mode )
7303    {
7304      CUR.iup_called = TRUE;
7305      if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
7306        return;
7307    }
7308#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7309
7310    do
7311    {
7312      end_point   = CUR.pts.contours[contour] - CUR.pts.first_point;
7313      first_point = point;
7314
7315      if ( BOUNDS ( end_point, CUR.pts.n_points ) )
7316        end_point = CUR.pts.n_points - 1;
7317
7318      while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
7319        point++;
7320
7321      if ( point <= end_point )
7322      {
7323        first_touched = point;
7324        cur_touched   = point;
7325
7326        point++;
7327
7328        while ( point <= end_point )
7329        {
7330          if ( ( CUR.pts.tags[point] & mask ) != 0 )
7331          {
7332            _iup_worker_interpolate( &V,
7333                                     cur_touched + 1,
7334                                     point - 1,
7335                                     cur_touched,
7336                                     point );
7337            cur_touched = point;
7338          }
7339
7340          point++;
7341        }
7342
7343        if ( cur_touched == first_touched )
7344          _iup_worker_shift( &V, first_point, end_point, cur_touched );
7345        else
7346        {
7347          _iup_worker_interpolate( &V,
7348                                   (FT_UShort)( cur_touched + 1 ),
7349                                   end_point,
7350                                   cur_touched,
7351                                   first_touched );
7352
7353          if ( first_touched > 0 )
7354            _iup_worker_interpolate( &V,
7355                                     first_point,
7356                                     first_touched - 1,
7357                                     cur_touched,
7358                                     first_touched );
7359        }
7360      }
7361      contour++;
7362    } while ( contour < CUR.pts.n_contours );
7363  }
7364
7365
7366  /*************************************************************************/
7367  /*                                                                       */
7368  /* DELTAPn[]:    DELTA exceptions P1, P2, P3                             */
7369  /* Opcode range: 0x5D,0x71,0x72                                          */
7370  /* Stack:        uint32 (2 * uint32)... -->                              */
7371  /*                                                                       */
7372  static void
7373  Ins_DELTAP( INS_ARG )
7374  {
7375    FT_ULong   k, nump;
7376    FT_UShort  A;
7377    FT_ULong   C;
7378    FT_Long    B;
7379#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7380    FT_UShort  B1, B2;
7381
7382
7383    if ( SUBPIXEL_HINTING                                        &&
7384         CUR.ignore_x_mode                                       &&
7385         CUR.iup_called                                          &&
7386         ( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7387      goto Fail;
7388#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7389
7390
7391#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7392    /* Delta hinting is covered by US Patent 5159668. */
7393    if ( CUR.face->unpatented_hinting )
7394    {
7395      FT_Long  n = args[0] * 2;
7396
7397
7398      if ( CUR.args < n )
7399      {
7400        if ( CUR.pedantic_hinting )
7401          CUR.error = FT_THROW( Too_Few_Arguments );
7402        n = CUR.args;
7403      }
7404
7405      CUR.args -= n;
7406      CUR.new_top = CUR.args;
7407      return;
7408    }
7409#endif
7410
7411    nump = (FT_ULong)args[0];   /* some points theoretically may occur more
7412                                   than once, thus UShort isn't enough */
7413
7414    for ( k = 1; k <= nump; k++ )
7415    {
7416      if ( CUR.args < 2 )
7417      {
7418        if ( CUR.pedantic_hinting )
7419          CUR.error = FT_THROW( Too_Few_Arguments );
7420        CUR.args = 0;
7421        goto Fail;
7422      }
7423
7424      CUR.args -= 2;
7425
7426      A = (FT_UShort)CUR.stack[CUR.args + 1];
7427      B = CUR.stack[CUR.args];
7428
7429      /* XXX: Because some popular fonts contain some invalid DeltaP */
7430      /*      instructions, we simply ignore them when the stacked   */
7431      /*      point reference is off limit, rather than returning an */
7432      /*      error.  As a delta instruction doesn't change a glyph  */
7433      /*      in great ways, this shouldn't be a problem.            */
7434
7435      if ( !BOUNDS( A, CUR.zp0.n_points ) )
7436      {
7437        C = ( (FT_ULong)B & 0xF0 ) >> 4;
7438
7439        switch ( CUR.opcode )
7440        {
7441        case 0x5D:
7442          break;
7443
7444        case 0x71:
7445          C += 16;
7446          break;
7447
7448        case 0x72:
7449          C += 32;
7450          break;
7451        }
7452
7453        C += CUR.GS.delta_base;
7454
7455        if ( CURRENT_Ppem() == (FT_Long)C )
7456        {
7457          B = ( (FT_ULong)B & 0xF ) - 8;
7458          if ( B >= 0 )
7459            B++;
7460          B = B * 64 / ( 1L << CUR.GS.delta_shift );
7461
7462#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7463
7464          if ( SUBPIXEL_HINTING )
7465          {
7466            /*
7467             *  Allow delta move if
7468             *
7469             *  - not using ignore_x_mode rendering
7470             *  - glyph is specifically set to allow it
7471             *  - glyph is composite and freedom vector is not subpixel
7472             *    vector
7473             */
7474            if ( !CUR.ignore_x_mode                                   ||
7475                 ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
7476                 ( CUR.is_composite && CUR.GS.freeVector.y != 0 )     )
7477              CUR_Func_move( &CUR.zp0, A, B );
7478
7479            /* Otherwise apply subpixel hinting and */
7480            /* compatibility mode rules             */
7481            else if ( CUR.ignore_x_mode )
7482            {
7483              if ( CUR.GS.freeVector.y != 0 )
7484                B1 = CUR.zp0.cur[A].y;
7485              else
7486                B1 = CUR.zp0.cur[A].x;
7487
7488#if 0
7489              /* Standard Subpixel Hinting: Allow y move.       */
7490              /* This messes up dejavu and may not be needed... */
7491              if ( !CUR.face->sph_compatibility_mode &&
7492                   CUR.GS.freeVector.y != 0          )
7493                CUR_Func_move( &CUR.zp0, A, B );
7494              else
7495#endif /* 0 */
7496
7497              /* Compatibility Mode: Allow x or y move if point touched in */
7498              /* Y direction.                                              */
7499              if ( CUR.face->sph_compatibility_mode                      &&
7500                   !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
7501              {
7502                /* save the y value of the point now; compare after move */
7503                B1 = CUR.zp0.cur[A].y;
7504
7505                if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
7506                  B = FT_PIX_ROUND( B1 + B ) - B1;
7507
7508                /* Allow delta move if using sph_compatibility_mode,   */
7509                /* IUP has not been called, and point is touched on Y. */
7510                if ( !CUR.iup_called                            &&
7511                     ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7512                  CUR_Func_move( &CUR.zp0, A, B );
7513              }
7514
7515              B2 = CUR.zp0.cur[A].y;
7516
7517              /* Reverse this move if it results in a disallowed move */
7518              if ( CUR.GS.freeVector.y != 0                           &&
7519                   ( ( CUR.face->sph_compatibility_mode           &&
7520                       ( B1 & 63 ) == 0                           &&
7521                       ( B2 & 63 ) != 0                           ) ||
7522                     ( ( CUR.sph_tweak_flags                    &
7523                         SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
7524                       ( B1 & 63 ) != 0                           &&
7525                       ( B2 & 63 ) != 0                           ) ) )
7526                CUR_Func_move( &CUR.zp0, A, -B );
7527            }
7528          }
7529          else
7530#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7531
7532            CUR_Func_move( &CUR.zp0, A, B );
7533        }
7534      }
7535      else
7536        if ( CUR.pedantic_hinting )
7537          CUR.error = FT_THROW( Invalid_Reference );
7538    }
7539
7540  Fail:
7541    CUR.new_top = CUR.args;
7542  }
7543
7544
7545  /*************************************************************************/
7546  /*                                                                       */
7547  /* DELTACn[]:    DELTA exceptions C1, C2, C3                             */
7548  /* Opcode range: 0x73,0x74,0x75                                          */
7549  /* Stack:        uint32 (2 * uint32)... -->                              */
7550  /*                                                                       */
7551  static void
7552  Ins_DELTAC( INS_ARG )
7553  {
7554    FT_ULong  nump, k;
7555    FT_ULong  A, C;
7556    FT_Long   B;
7557
7558
7559#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7560    /* Delta hinting is covered by US Patent 5159668. */
7561    if ( CUR.face->unpatented_hinting )
7562    {
7563      FT_Long  n = args[0] * 2;
7564
7565
7566      if ( CUR.args < n )
7567      {
7568        if ( CUR.pedantic_hinting )
7569          CUR.error = FT_THROW( Too_Few_Arguments );
7570        n = CUR.args;
7571      }
7572
7573      CUR.args -= n;
7574      CUR.new_top = CUR.args;
7575      return;
7576    }
7577#endif
7578
7579    nump = (FT_ULong)args[0];
7580
7581    for ( k = 1; k <= nump; k++ )
7582    {
7583      if ( CUR.args < 2 )
7584      {
7585        if ( CUR.pedantic_hinting )
7586          CUR.error = FT_THROW( Too_Few_Arguments );
7587        CUR.args = 0;
7588        goto Fail;
7589      }
7590
7591      CUR.args -= 2;
7592
7593      A = (FT_ULong)CUR.stack[CUR.args + 1];
7594      B = CUR.stack[CUR.args];
7595
7596      if ( BOUNDSL( A, CUR.cvtSize ) )
7597      {
7598        if ( CUR.pedantic_hinting )
7599        {
7600          CUR.error = FT_THROW( Invalid_Reference );
7601          return;
7602        }
7603      }
7604      else
7605      {
7606        C = ( (FT_ULong)B & 0xF0 ) >> 4;
7607
7608        switch ( CUR.opcode )
7609        {
7610        case 0x73:
7611          break;
7612
7613        case 0x74:
7614          C += 16;
7615          break;
7616
7617        case 0x75:
7618          C += 32;
7619          break;
7620        }
7621
7622        C += CUR.GS.delta_base;
7623
7624        if ( CURRENT_Ppem() == (FT_Long)C )
7625        {
7626          B = ( (FT_ULong)B & 0xF ) - 8;
7627          if ( B >= 0 )
7628            B++;
7629          B = B * 64 / ( 1L << CUR.GS.delta_shift );
7630
7631          CUR_Func_move_cvt( A, B );
7632        }
7633      }
7634    }
7635
7636  Fail:
7637    CUR.new_top = CUR.args;
7638  }
7639
7640
7641  /*************************************************************************/
7642  /*                                                                       */
7643  /* MISC. INSTRUCTIONS                                                    */
7644  /*                                                                       */
7645  /*************************************************************************/
7646
7647
7648  /*************************************************************************/
7649  /*                                                                       */
7650  /* GETINFO[]:    GET INFOrmation                                         */
7651  /* Opcode range: 0x88                                                    */
7652  /* Stack:        uint32 --> uint32                                       */
7653  /*                                                                       */
7654  static void
7655  Ins_GETINFO( INS_ARG )
7656  {
7657    FT_Long  K;
7658
7659
7660    K = 0;
7661
7662#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7663    /********************************/
7664    /* RASTERIZER VERSION           */
7665    /* Selector Bit:  0             */
7666    /* Return Bit(s): 0-7           */
7667    /*                              */
7668    if ( SUBPIXEL_HINTING     &&
7669         ( args[0] & 1 ) != 0 &&
7670         CUR.ignore_x_mode    )
7671    {
7672      K = CUR.rasterizer_version;
7673      FT_TRACE7(( "Setting rasterizer version %d\n",
7674                  CUR.rasterizer_version ));
7675    }
7676    else
7677#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7678      if ( ( args[0] & 1 ) != 0 )
7679        K = TT_INTERPRETER_VERSION_35;
7680
7681    /********************************/
7682    /* GLYPH ROTATED                */
7683    /* Selector Bit:  1             */
7684    /* Return Bit(s): 8             */
7685    /*                              */
7686    if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
7687      K |= 0x80;
7688
7689    /********************************/
7690    /* GLYPH STRETCHED              */
7691    /* Selector Bit:  2             */
7692    /* Return Bit(s): 9             */
7693    /*                              */
7694    if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
7695      K |= 1 << 8;
7696
7697    /********************************/
7698    /* HINTING FOR GRAYSCALE        */
7699    /* Selector Bit:  5             */
7700    /* Return Bit(s): 12            */
7701    /*                              */
7702    if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
7703      K |= 1 << 12;
7704
7705#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7706
7707    if ( SUBPIXEL_HINTING                                    &&
7708         CUR.ignore_x_mode                                   &&
7709         CUR.rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7710    {
7711      /********************************/
7712      /* HINTING FOR GRAYSCALE        */
7713      /* Selector Bit:  5             */
7714      /* Return Bit(s): 12            */
7715      /*                              */
7716      if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting )
7717        K |= 1 << 12;
7718
7719      /********************************/
7720      /* HINTING FOR SUBPIXEL         */
7721      /* Selector Bit:  6             */
7722      /* Return Bit(s): 13            */
7723      /*                              */
7724      if ( ( args[0] & 64 ) != 0        &&
7725           CUR.subpixel_hinting         &&
7726           CUR.rasterizer_version >= 37 )
7727      {
7728        K |= 1 << 13;
7729
7730        /* the stuff below is irrelevant if subpixel_hinting is not set */
7731
7732        /********************************/
7733        /* COMPATIBLE WIDTHS ENABLED    */
7734        /* Selector Bit:  7             */
7735        /* Return Bit(s): 14            */
7736        /*                              */
7737        /* Functionality still needs to be added */
7738        if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths )
7739          K |= 1 << 14;
7740
7741        /********************************/
7742        /* SYMMETRICAL SMOOTHING        */
7743        /* Selector Bit:  8             */
7744        /* Return Bit(s): 15            */
7745        /*                              */
7746        /* Functionality still needs to be added */
7747        if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )
7748          K |= 1 << 15;
7749
7750        /********************************/
7751        /* HINTING FOR BGR?             */
7752        /* Selector Bit:  9             */
7753        /* Return Bit(s): 16            */
7754        /*                              */
7755        /* Functionality still needs to be added */
7756        if ( ( args[0] & 512 ) != 0 && CUR.bgr )
7757          K |= 1 << 16;
7758
7759        if ( CUR.rasterizer_version >= 38 )
7760        {
7761          /********************************/
7762          /* SUBPIXEL POSITIONED?         */
7763          /* Selector Bit:  10            */
7764          /* Return Bit(s): 17            */
7765          /*                              */
7766          /* Functionality still needs to be added */
7767          if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned )
7768            K |= 1 << 17;
7769        }
7770      }
7771    }
7772
7773#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7774
7775    args[0] = K;
7776  }
7777
7778
7779  static void
7780  Ins_UNKNOWN( INS_ARG )
7781  {
7782    TT_DefRecord*  def   = CUR.IDefs;
7783    TT_DefRecord*  limit = def + CUR.numIDefs;
7784
7785    FT_UNUSED_ARG;
7786
7787
7788    for ( ; def < limit; def++ )
7789    {
7790      if ( (FT_Byte)def->opc == CUR.opcode && def->active )
7791      {
7792        TT_CallRec*  call;
7793
7794
7795        if ( CUR.callTop >= CUR.callSize )
7796        {
7797          CUR.error = FT_THROW( Stack_Overflow );
7798          return;
7799        }
7800
7801        call = CUR.callStack + CUR.callTop++;
7802
7803        call->Caller_Range = CUR.curRange;
7804        call->Caller_IP    = CUR.IP + 1;
7805        call->Cur_Count    = 1;
7806        call->Cur_Restart  = def->start;
7807        call->Cur_End      = def->end;
7808
7809        INS_Goto_CodeRange( def->range, def->start );
7810
7811        CUR.step_ins = FALSE;
7812        return;
7813      }
7814    }
7815
7816    CUR.error = FT_THROW( Invalid_Opcode );
7817  }
7818
7819
7820#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7821
7822
7823  static
7824  TInstruction_Function  Instruct_Dispatch[256] =
7825  {
7826    /* Opcodes are gathered in groups of 16. */
7827    /* Please keep the spaces as they are.   */
7828
7829    /*  SVTCA  y  */  Ins_SVTCA,
7830    /*  SVTCA  x  */  Ins_SVTCA,
7831    /*  SPvTCA y  */  Ins_SPVTCA,
7832    /*  SPvTCA x  */  Ins_SPVTCA,
7833    /*  SFvTCA y  */  Ins_SFVTCA,
7834    /*  SFvTCA x  */  Ins_SFVTCA,
7835    /*  SPvTL //  */  Ins_SPVTL,
7836    /*  SPvTL +   */  Ins_SPVTL,
7837    /*  SFvTL //  */  Ins_SFVTL,
7838    /*  SFvTL +   */  Ins_SFVTL,
7839    /*  SPvFS     */  Ins_SPVFS,
7840    /*  SFvFS     */  Ins_SFVFS,
7841    /*  GPV       */  Ins_GPV,
7842    /*  GFV       */  Ins_GFV,
7843    /*  SFvTPv    */  Ins_SFVTPV,
7844    /*  ISECT     */  Ins_ISECT,
7845
7846    /*  SRP0      */  Ins_SRP0,
7847    /*  SRP1      */  Ins_SRP1,
7848    /*  SRP2      */  Ins_SRP2,
7849    /*  SZP0      */  Ins_SZP0,
7850    /*  SZP1      */  Ins_SZP1,
7851    /*  SZP2      */  Ins_SZP2,
7852    /*  SZPS      */  Ins_SZPS,
7853    /*  SLOOP     */  Ins_SLOOP,
7854    /*  RTG       */  Ins_RTG,
7855    /*  RTHG      */  Ins_RTHG,
7856    /*  SMD       */  Ins_SMD,
7857    /*  ELSE      */  Ins_ELSE,
7858    /*  JMPR      */  Ins_JMPR,
7859    /*  SCvTCi    */  Ins_SCVTCI,
7860    /*  SSwCi     */  Ins_SSWCI,
7861    /*  SSW       */  Ins_SSW,
7862
7863    /*  DUP       */  Ins_DUP,
7864    /*  POP       */  Ins_POP,
7865    /*  CLEAR     */  Ins_CLEAR,
7866    /*  SWAP      */  Ins_SWAP,
7867    /*  DEPTH     */  Ins_DEPTH,
7868    /*  CINDEX    */  Ins_CINDEX,
7869    /*  MINDEX    */  Ins_MINDEX,
7870    /*  AlignPTS  */  Ins_ALIGNPTS,
7871    /*  INS_0x28  */  Ins_UNKNOWN,
7872    /*  UTP       */  Ins_UTP,
7873    /*  LOOPCALL  */  Ins_LOOPCALL,
7874    /*  CALL      */  Ins_CALL,
7875    /*  FDEF      */  Ins_FDEF,
7876    /*  ENDF      */  Ins_ENDF,
7877    /*  MDAP[0]   */  Ins_MDAP,
7878    /*  MDAP[1]   */  Ins_MDAP,
7879
7880    /*  IUP[0]    */  Ins_IUP,
7881    /*  IUP[1]    */  Ins_IUP,
7882    /*  SHP[0]    */  Ins_SHP,
7883    /*  SHP[1]    */  Ins_SHP,
7884    /*  SHC[0]    */  Ins_SHC,
7885    /*  SHC[1]    */  Ins_SHC,
7886    /*  SHZ[0]    */  Ins_SHZ,
7887    /*  SHZ[1]    */  Ins_SHZ,
7888    /*  SHPIX     */  Ins_SHPIX,
7889    /*  IP        */  Ins_IP,
7890    /*  MSIRP[0]  */  Ins_MSIRP,
7891    /*  MSIRP[1]  */  Ins_MSIRP,
7892    /*  AlignRP   */  Ins_ALIGNRP,
7893    /*  RTDG      */  Ins_RTDG,
7894    /*  MIAP[0]   */  Ins_MIAP,
7895    /*  MIAP[1]   */  Ins_MIAP,
7896
7897    /*  NPushB    */  Ins_NPUSHB,
7898    /*  NPushW    */  Ins_NPUSHW,
7899    /*  WS        */  Ins_WS,
7900    /*  RS        */  Ins_RS,
7901    /*  WCvtP     */  Ins_WCVTP,
7902    /*  RCvt      */  Ins_RCVT,
7903    /*  GC[0]     */  Ins_GC,
7904    /*  GC[1]     */  Ins_GC,
7905    /*  SCFS      */  Ins_SCFS,
7906    /*  MD[0]     */  Ins_MD,
7907    /*  MD[1]     */  Ins_MD,
7908    /*  MPPEM     */  Ins_MPPEM,
7909    /*  MPS       */  Ins_MPS,
7910    /*  FlipON    */  Ins_FLIPON,
7911    /*  FlipOFF   */  Ins_FLIPOFF,
7912    /*  DEBUG     */  Ins_DEBUG,
7913
7914    /*  LT        */  Ins_LT,
7915    /*  LTEQ      */  Ins_LTEQ,
7916    /*  GT        */  Ins_GT,
7917    /*  GTEQ      */  Ins_GTEQ,
7918    /*  EQ        */  Ins_EQ,
7919    /*  NEQ       */  Ins_NEQ,
7920    /*  ODD       */  Ins_ODD,
7921    /*  EVEN      */  Ins_EVEN,
7922    /*  IF        */  Ins_IF,
7923    /*  EIF       */  Ins_EIF,
7924    /*  AND       */  Ins_AND,
7925    /*  OR        */  Ins_OR,
7926    /*  NOT       */  Ins_NOT,
7927    /*  DeltaP1   */  Ins_DELTAP,
7928    /*  SDB       */  Ins_SDB,
7929    /*  SDS       */  Ins_SDS,
7930
7931    /*  ADD       */  Ins_ADD,
7932    /*  SUB       */  Ins_SUB,
7933    /*  DIV       */  Ins_DIV,
7934    /*  MUL       */  Ins_MUL,
7935    /*  ABS       */  Ins_ABS,
7936    /*  NEG       */  Ins_NEG,
7937    /*  FLOOR     */  Ins_FLOOR,
7938    /*  CEILING   */  Ins_CEILING,
7939    /*  ROUND[0]  */  Ins_ROUND,
7940    /*  ROUND[1]  */  Ins_ROUND,
7941    /*  ROUND[2]  */  Ins_ROUND,
7942    /*  ROUND[3]  */  Ins_ROUND,
7943    /*  NROUND[0] */  Ins_NROUND,
7944    /*  NROUND[1] */  Ins_NROUND,
7945    /*  NROUND[2] */  Ins_NROUND,
7946    /*  NROUND[3] */  Ins_NROUND,
7947
7948    /*  WCvtF     */  Ins_WCVTF,
7949    /*  DeltaP2   */  Ins_DELTAP,
7950    /*  DeltaP3   */  Ins_DELTAP,
7951    /*  DeltaCn[0] */ Ins_DELTAC,
7952    /*  DeltaCn[1] */ Ins_DELTAC,
7953    /*  DeltaCn[2] */ Ins_DELTAC,
7954    /*  SROUND    */  Ins_SROUND,
7955    /*  S45Round  */  Ins_S45ROUND,
7956    /*  JROT      */  Ins_JROT,
7957    /*  JROF      */  Ins_JROF,
7958    /*  ROFF      */  Ins_ROFF,
7959    /*  INS_0x7B  */  Ins_UNKNOWN,
7960    /*  RUTG      */  Ins_RUTG,
7961    /*  RDTG      */  Ins_RDTG,
7962    /*  SANGW     */  Ins_SANGW,
7963    /*  AA        */  Ins_AA,
7964
7965    /*  FlipPT    */  Ins_FLIPPT,
7966    /*  FlipRgON  */  Ins_FLIPRGON,
7967    /*  FlipRgOFF */  Ins_FLIPRGOFF,
7968    /*  INS_0x83  */  Ins_UNKNOWN,
7969    /*  INS_0x84  */  Ins_UNKNOWN,
7970    /*  ScanCTRL  */  Ins_SCANCTRL,
7971    /*  SDPVTL[0] */  Ins_SDPVTL,
7972    /*  SDPVTL[1] */  Ins_SDPVTL,
7973    /*  GetINFO   */  Ins_GETINFO,
7974    /*  IDEF      */  Ins_IDEF,
7975    /*  ROLL      */  Ins_ROLL,
7976    /*  MAX       */  Ins_MAX,
7977    /*  MIN       */  Ins_MIN,
7978    /*  ScanTYPE  */  Ins_SCANTYPE,
7979    /*  InstCTRL  */  Ins_INSTCTRL,
7980    /*  INS_0x8F  */  Ins_UNKNOWN,
7981
7982    /*  INS_0x90  */   Ins_UNKNOWN,
7983    /*  INS_0x91  */   Ins_UNKNOWN,
7984    /*  INS_0x92  */   Ins_UNKNOWN,
7985    /*  INS_0x93  */   Ins_UNKNOWN,
7986    /*  INS_0x94  */   Ins_UNKNOWN,
7987    /*  INS_0x95  */   Ins_UNKNOWN,
7988    /*  INS_0x96  */   Ins_UNKNOWN,
7989    /*  INS_0x97  */   Ins_UNKNOWN,
7990    /*  INS_0x98  */   Ins_UNKNOWN,
7991    /*  INS_0x99  */   Ins_UNKNOWN,
7992    /*  INS_0x9A  */   Ins_UNKNOWN,
7993    /*  INS_0x9B  */   Ins_UNKNOWN,
7994    /*  INS_0x9C  */   Ins_UNKNOWN,
7995    /*  INS_0x9D  */   Ins_UNKNOWN,
7996    /*  INS_0x9E  */   Ins_UNKNOWN,
7997    /*  INS_0x9F  */   Ins_UNKNOWN,
7998
7999    /*  INS_0xA0  */   Ins_UNKNOWN,
8000    /*  INS_0xA1  */   Ins_UNKNOWN,
8001    /*  INS_0xA2  */   Ins_UNKNOWN,
8002    /*  INS_0xA3  */   Ins_UNKNOWN,
8003    /*  INS_0xA4  */   Ins_UNKNOWN,
8004    /*  INS_0xA5  */   Ins_UNKNOWN,
8005    /*  INS_0xA6  */   Ins_UNKNOWN,
8006    /*  INS_0xA7  */   Ins_UNKNOWN,
8007    /*  INS_0xA8  */   Ins_UNKNOWN,
8008    /*  INS_0xA9  */   Ins_UNKNOWN,
8009    /*  INS_0xAA  */   Ins_UNKNOWN,
8010    /*  INS_0xAB  */   Ins_UNKNOWN,
8011    /*  INS_0xAC  */   Ins_UNKNOWN,
8012    /*  INS_0xAD  */   Ins_UNKNOWN,
8013    /*  INS_0xAE  */   Ins_UNKNOWN,
8014    /*  INS_0xAF  */   Ins_UNKNOWN,
8015
8016    /*  PushB[0]  */  Ins_PUSHB,
8017    /*  PushB[1]  */  Ins_PUSHB,
8018    /*  PushB[2]  */  Ins_PUSHB,
8019    /*  PushB[3]  */  Ins_PUSHB,
8020    /*  PushB[4]  */  Ins_PUSHB,
8021    /*  PushB[5]  */  Ins_PUSHB,
8022    /*  PushB[6]  */  Ins_PUSHB,
8023    /*  PushB[7]  */  Ins_PUSHB,
8024    /*  PushW[0]  */  Ins_PUSHW,
8025    /*  PushW[1]  */  Ins_PUSHW,
8026    /*  PushW[2]  */  Ins_PUSHW,
8027    /*  PushW[3]  */  Ins_PUSHW,
8028    /*  PushW[4]  */  Ins_PUSHW,
8029    /*  PushW[5]  */  Ins_PUSHW,
8030    /*  PushW[6]  */  Ins_PUSHW,
8031    /*  PushW[7]  */  Ins_PUSHW,
8032
8033    /*  MDRP[00]  */  Ins_MDRP,
8034    /*  MDRP[01]  */  Ins_MDRP,
8035    /*  MDRP[02]  */  Ins_MDRP,
8036    /*  MDRP[03]  */  Ins_MDRP,
8037    /*  MDRP[04]  */  Ins_MDRP,
8038    /*  MDRP[05]  */  Ins_MDRP,
8039    /*  MDRP[06]  */  Ins_MDRP,
8040    /*  MDRP[07]  */  Ins_MDRP,
8041    /*  MDRP[08]  */  Ins_MDRP,
8042    /*  MDRP[09]  */  Ins_MDRP,
8043    /*  MDRP[10]  */  Ins_MDRP,
8044    /*  MDRP[11]  */  Ins_MDRP,
8045    /*  MDRP[12]  */  Ins_MDRP,
8046    /*  MDRP[13]  */  Ins_MDRP,
8047    /*  MDRP[14]  */  Ins_MDRP,
8048    /*  MDRP[15]  */  Ins_MDRP,
8049
8050    /*  MDRP[16]  */  Ins_MDRP,
8051    /*  MDRP[17]  */  Ins_MDRP,
8052    /*  MDRP[18]  */  Ins_MDRP,
8053    /*  MDRP[19]  */  Ins_MDRP,
8054    /*  MDRP[20]  */  Ins_MDRP,
8055    /*  MDRP[21]  */  Ins_MDRP,
8056    /*  MDRP[22]  */  Ins_MDRP,
8057    /*  MDRP[23]  */  Ins_MDRP,
8058    /*  MDRP[24]  */  Ins_MDRP,
8059    /*  MDRP[25]  */  Ins_MDRP,
8060    /*  MDRP[26]  */  Ins_MDRP,
8061    /*  MDRP[27]  */  Ins_MDRP,
8062    /*  MDRP[28]  */  Ins_MDRP,
8063    /*  MDRP[29]  */  Ins_MDRP,
8064    /*  MDRP[30]  */  Ins_MDRP,
8065    /*  MDRP[31]  */  Ins_MDRP,
8066
8067    /*  MIRP[00]  */  Ins_MIRP,
8068    /*  MIRP[01]  */  Ins_MIRP,
8069    /*  MIRP[02]  */  Ins_MIRP,
8070    /*  MIRP[03]  */  Ins_MIRP,
8071    /*  MIRP[04]  */  Ins_MIRP,
8072    /*  MIRP[05]  */  Ins_MIRP,
8073    /*  MIRP[06]  */  Ins_MIRP,
8074    /*  MIRP[07]  */  Ins_MIRP,
8075    /*  MIRP[08]  */  Ins_MIRP,
8076    /*  MIRP[09]  */  Ins_MIRP,
8077    /*  MIRP[10]  */  Ins_MIRP,
8078    /*  MIRP[11]  */  Ins_MIRP,
8079    /*  MIRP[12]  */  Ins_MIRP,
8080    /*  MIRP[13]  */  Ins_MIRP,
8081    /*  MIRP[14]  */  Ins_MIRP,
8082    /*  MIRP[15]  */  Ins_MIRP,
8083
8084    /*  MIRP[16]  */  Ins_MIRP,
8085    /*  MIRP[17]  */  Ins_MIRP,
8086    /*  MIRP[18]  */  Ins_MIRP,
8087    /*  MIRP[19]  */  Ins_MIRP,
8088    /*  MIRP[20]  */  Ins_MIRP,
8089    /*  MIRP[21]  */  Ins_MIRP,
8090    /*  MIRP[22]  */  Ins_MIRP,
8091    /*  MIRP[23]  */  Ins_MIRP,
8092    /*  MIRP[24]  */  Ins_MIRP,
8093    /*  MIRP[25]  */  Ins_MIRP,
8094    /*  MIRP[26]  */  Ins_MIRP,
8095    /*  MIRP[27]  */  Ins_MIRP,
8096    /*  MIRP[28]  */  Ins_MIRP,
8097    /*  MIRP[29]  */  Ins_MIRP,
8098    /*  MIRP[30]  */  Ins_MIRP,
8099    /*  MIRP[31]  */  Ins_MIRP
8100  };
8101
8102
8103#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8104
8105
8106  /*************************************************************************/
8107  /*                                                                       */
8108  /* RUN                                                                   */
8109  /*                                                                       */
8110  /*  This function executes a run of opcodes.  It will exit in the        */
8111  /*  following cases:                                                     */
8112  /*                                                                       */
8113  /*  - Errors (in which case it returns FALSE).                           */
8114  /*                                                                       */
8115  /*  - Reaching the end of the main code range (returns TRUE).            */
8116  /*    Reaching the end of a code range within a function call is an      */
8117  /*    error.                                                             */
8118  /*                                                                       */
8119  /*  - After executing one single opcode, if the flag `Instruction_Trap'  */
8120  /*    is set to TRUE (returns TRUE).                                     */
8121  /*                                                                       */
8122  /*  On exit with TRUE, test IP < CodeSize to know whether it comes from  */
8123  /*  an instruction trap or a normal termination.                         */
8124  /*                                                                       */
8125  /*                                                                       */
8126  /*  Note: The documented DEBUG opcode pops a value from the stack.  This */
8127  /*        behaviour is unsupported; here a DEBUG opcode is always an     */
8128  /*        error.                                                         */
8129  /*                                                                       */
8130  /*                                                                       */
8131  /* THIS IS THE INTERPRETER'S MAIN LOOP.                                  */
8132  /*                                                                       */
8133  /*  Instructions appear in the specification's order.                    */
8134  /*                                                                       */
8135  /*************************************************************************/
8136
8137
8138  /* documentation is in ttinterp.h */
8139
8140  FT_EXPORT_DEF( FT_Error )
8141  TT_RunIns( TT_ExecContext  exc )
8142  {
8143    FT_Long    ins_counter = 0;  /* executed instructions counter */
8144    FT_UShort  i;
8145
8146#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8147    FT_Byte    opcode_pattern[1][2] = {
8148                  /* #8 TypeMan Talk Align */
8149                  {
8150                    0x06, /* SPVTL   */
8151                    0x7D, /* RDTG    */
8152                  },
8153                };
8154    FT_UShort  opcode_patterns   = 1;
8155    FT_UShort  opcode_pointer[1] = { 0 };
8156    FT_UShort  opcode_size[1]    = { 1 };
8157#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8158
8159
8160#ifdef TT_CONFIG_OPTION_STATIC_RASTER
8161    cur = *exc;
8162#endif
8163
8164#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8165    CUR.iup_called = FALSE;
8166#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8167
8168    /* set CVT functions */
8169    CUR.tt_metrics.ratio = 0;
8170    if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
8171    {
8172      /* non-square pixels, use the stretched routines */
8173      CUR.func_read_cvt  = Read_CVT_Stretched;
8174      CUR.func_write_cvt = Write_CVT_Stretched;
8175      CUR.func_move_cvt  = Move_CVT_Stretched;
8176    }
8177    else
8178    {
8179      /* square pixels, use normal routines */
8180      CUR.func_read_cvt  = Read_CVT;
8181      CUR.func_write_cvt = Write_CVT;
8182      CUR.func_move_cvt  = Move_CVT;
8183    }
8184
8185    COMPUTE_Funcs();
8186    COMPUTE_Round( (FT_Byte)exc->GS.round_state );
8187
8188    do
8189    {
8190      CUR.opcode = CUR.code[CUR.IP];
8191
8192      FT_TRACE7(( "  " ));
8193      FT_TRACE7(( opcode_name[CUR.opcode] ));
8194      FT_TRACE7(( "\n" ));
8195
8196      if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
8197      {
8198        if ( CUR.IP + 1 >= CUR.codeSize )
8199          goto LErrorCodeOverflow_;
8200
8201        CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
8202      }
8203
8204      if ( CUR.IP + CUR.length > CUR.codeSize )
8205        goto LErrorCodeOverflow_;
8206
8207      /* First, let's check for empty stack and overflow */
8208      CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
8209
8210      /* `args' is the top of the stack once arguments have been popped. */
8211      /* One can also interpret it as the index of the last argument.    */
8212      if ( CUR.args < 0 )
8213      {
8214        if ( CUR.pedantic_hinting )
8215        {
8216          CUR.error = FT_THROW( Too_Few_Arguments );
8217          goto LErrorLabel_;
8218        }
8219
8220        /* push zeroes onto the stack */
8221        for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ )
8222          CUR.stack[i] = 0;
8223        CUR.args = 0;
8224      }
8225
8226      CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
8227
8228      /* `new_top' is the new top of the stack, after the instruction's */
8229      /* execution.  `top' will be set to `new_top' after the `switch'  */
8230      /* statement.                                                     */
8231      if ( CUR.new_top > CUR.stackSize )
8232      {
8233        CUR.error = FT_THROW( Stack_Overflow );
8234        goto LErrorLabel_;
8235      }
8236
8237      CUR.step_ins = TRUE;
8238      CUR.error    = FT_Err_Ok;
8239
8240#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8241
8242      if ( SUBPIXEL_HINTING )
8243      {
8244        for ( i = 0; i < opcode_patterns; i++ )
8245        {
8246          if ( opcode_pointer[i] < opcode_size[i]                 &&
8247               CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
8248          {
8249            opcode_pointer[i] += 1;
8250
8251            if ( opcode_pointer[i] == opcode_size[i] )
8252            {
8253              FT_TRACE7(( "sph: opcode ptrn: %d, %s %s\n",
8254                          i,
8255                          CUR.face->root.family_name,
8256                          CUR.face->root.style_name ));
8257
8258              switch ( i )
8259              {
8260              case 0:
8261                break;
8262              }
8263              opcode_pointer[i] = 0;
8264            }
8265          }
8266          else
8267            opcode_pointer[i] = 0;
8268        }
8269      }
8270
8271#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8272
8273#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
8274
8275      {
8276        FT_Long*  args   = CUR.stack + CUR.args;
8277        FT_Byte   opcode = CUR.opcode;
8278
8279
8280#undef  ARRAY_BOUND_ERROR
8281#define ARRAY_BOUND_ERROR  goto Set_Invalid_Ref
8282
8283
8284        switch ( opcode )
8285        {
8286        case 0x00:  /* SVTCA y  */
8287        case 0x01:  /* SVTCA x  */
8288        case 0x02:  /* SPvTCA y */
8289        case 0x03:  /* SPvTCA x */
8290        case 0x04:  /* SFvTCA y */
8291        case 0x05:  /* SFvTCA x */
8292          {
8293            FT_Short  AA, BB;
8294
8295
8296            AA = (FT_Short)( ( opcode & 1 ) << 14 );
8297            BB = (FT_Short)( AA ^ 0x4000 );
8298
8299            if ( opcode < 4 )
8300            {
8301              CUR.GS.projVector.x = AA;
8302              CUR.GS.projVector.y = BB;
8303
8304              CUR.GS.dualVector.x = AA;
8305              CUR.GS.dualVector.y = BB;
8306            }
8307            else
8308            {
8309              GUESS_VECTOR( projVector );
8310            }
8311
8312            if ( ( opcode & 2 ) == 0 )
8313            {
8314              CUR.GS.freeVector.x = AA;
8315              CUR.GS.freeVector.y = BB;
8316            }
8317            else
8318            {
8319              GUESS_VECTOR( freeVector );
8320            }
8321
8322            COMPUTE_Funcs();
8323          }
8324          break;
8325
8326        case 0x06:  /* SPvTL // */
8327        case 0x07:  /* SPvTL +  */
8328          DO_SPVTL
8329          break;
8330
8331        case 0x08:  /* SFvTL // */
8332        case 0x09:  /* SFvTL +  */
8333          DO_SFVTL
8334          break;
8335
8336        case 0x0A:  /* SPvFS */
8337          DO_SPVFS
8338          break;
8339
8340        case 0x0B:  /* SFvFS */
8341          DO_SFVFS
8342          break;
8343
8344        case 0x0C:  /* GPV */
8345          DO_GPV
8346          break;
8347
8348        case 0x0D:  /* GFV */
8349          DO_GFV
8350          break;
8351
8352        case 0x0E:  /* SFvTPv */
8353          DO_SFVTPV
8354          break;
8355
8356        case 0x0F:  /* ISECT  */
8357          Ins_ISECT( EXEC_ARG_ args );
8358          break;
8359
8360        case 0x10:  /* SRP0 */
8361          DO_SRP0
8362          break;
8363
8364        case 0x11:  /* SRP1 */
8365          DO_SRP1
8366          break;
8367
8368        case 0x12:  /* SRP2 */
8369          DO_SRP2
8370          break;
8371
8372        case 0x13:  /* SZP0 */
8373          Ins_SZP0( EXEC_ARG_ args );
8374          break;
8375
8376        case 0x14:  /* SZP1 */
8377          Ins_SZP1( EXEC_ARG_ args );
8378          break;
8379
8380        case 0x15:  /* SZP2 */
8381          Ins_SZP2( EXEC_ARG_ args );
8382          break;
8383
8384        case 0x16:  /* SZPS */
8385          Ins_SZPS( EXEC_ARG_ args );
8386          break;
8387
8388        case 0x17:  /* SLOOP */
8389          DO_SLOOP
8390          break;
8391
8392        case 0x18:  /* RTG */
8393          DO_RTG
8394          break;
8395
8396        case 0x19:  /* RTHG */
8397          DO_RTHG
8398          break;
8399
8400        case 0x1A:  /* SMD */
8401          DO_SMD
8402          break;
8403
8404        case 0x1B:  /* ELSE */
8405          Ins_ELSE( EXEC_ARG_ args );
8406          break;
8407
8408        case 0x1C:  /* JMPR */
8409          DO_JMPR
8410          break;
8411
8412        case 0x1D:  /* SCVTCI */
8413          DO_SCVTCI
8414          break;
8415
8416        case 0x1E:  /* SSWCI */
8417          DO_SSWCI
8418          break;
8419
8420        case 0x1F:  /* SSW */
8421          DO_SSW
8422          break;
8423
8424        case 0x20:  /* DUP */
8425          DO_DUP
8426          break;
8427
8428        case 0x21:  /* POP */
8429          /* nothing :-) */
8430          break;
8431
8432        case 0x22:  /* CLEAR */
8433          DO_CLEAR
8434          break;
8435
8436        case 0x23:  /* SWAP */
8437          DO_SWAP
8438          break;
8439
8440        case 0x24:  /* DEPTH */
8441          DO_DEPTH
8442          break;
8443
8444        case 0x25:  /* CINDEX */
8445          DO_CINDEX
8446          break;
8447
8448        case 0x26:  /* MINDEX */
8449          Ins_MINDEX( EXEC_ARG_ args );
8450          break;
8451
8452        case 0x27:  /* ALIGNPTS */
8453          Ins_ALIGNPTS( EXEC_ARG_ args );
8454          break;
8455
8456        case 0x28:  /* ???? */
8457          Ins_UNKNOWN( EXEC_ARG_ args );
8458          break;
8459
8460        case 0x29:  /* UTP */
8461          Ins_UTP( EXEC_ARG_ args );
8462          break;
8463
8464        case 0x2A:  /* LOOPCALL */
8465          Ins_LOOPCALL( EXEC_ARG_ args );
8466          break;
8467
8468        case 0x2B:  /* CALL */
8469          Ins_CALL( EXEC_ARG_ args );
8470          break;
8471
8472        case 0x2C:  /* FDEF */
8473          Ins_FDEF( EXEC_ARG_ args );
8474          break;
8475
8476        case 0x2D:  /* ENDF */
8477          Ins_ENDF( EXEC_ARG_ args );
8478          break;
8479
8480        case 0x2E:  /* MDAP */
8481        case 0x2F:  /* MDAP */
8482          Ins_MDAP( EXEC_ARG_ args );
8483          break;
8484
8485        case 0x30:  /* IUP */
8486        case 0x31:  /* IUP */
8487          Ins_IUP( EXEC_ARG_ args );
8488          break;
8489
8490        case 0x32:  /* SHP */
8491        case 0x33:  /* SHP */
8492          Ins_SHP( EXEC_ARG_ args );
8493          break;
8494
8495        case 0x34:  /* SHC */
8496        case 0x35:  /* SHC */
8497          Ins_SHC( EXEC_ARG_ args );
8498          break;
8499
8500        case 0x36:  /* SHZ */
8501        case 0x37:  /* SHZ */
8502          Ins_SHZ( EXEC_ARG_ args );
8503          break;
8504
8505        case 0x38:  /* SHPIX */
8506          Ins_SHPIX( EXEC_ARG_ args );
8507          break;
8508
8509        case 0x39:  /* IP    */
8510          Ins_IP( EXEC_ARG_ args );
8511          break;
8512
8513        case 0x3A:  /* MSIRP */
8514        case 0x3B:  /* MSIRP */
8515          Ins_MSIRP( EXEC_ARG_ args );
8516          break;
8517
8518        case 0x3C:  /* AlignRP */
8519          Ins_ALIGNRP( EXEC_ARG_ args );
8520          break;
8521
8522        case 0x3D:  /* RTDG */
8523          DO_RTDG
8524          break;
8525
8526        case 0x3E:  /* MIAP */
8527        case 0x3F:  /* MIAP */
8528          Ins_MIAP( EXEC_ARG_ args );
8529          break;
8530
8531        case 0x40:  /* NPUSHB */
8532          Ins_NPUSHB( EXEC_ARG_ args );
8533          break;
8534
8535        case 0x41:  /* NPUSHW */
8536          Ins_NPUSHW( EXEC_ARG_ args );
8537          break;
8538
8539        case 0x42:  /* WS */
8540          DO_WS
8541          break;
8542
8543      Set_Invalid_Ref:
8544            CUR.error = FT_THROW( Invalid_Reference );
8545          break;
8546
8547        case 0x43:  /* RS */
8548          DO_RS
8549          break;
8550
8551        case 0x44:  /* WCVTP */
8552          DO_WCVTP
8553          break;
8554
8555        case 0x45:  /* RCVT */
8556          DO_RCVT
8557          break;
8558
8559        case 0x46:  /* GC */
8560        case 0x47:  /* GC */
8561          Ins_GC( EXEC_ARG_ args );
8562          break;
8563
8564        case 0x48:  /* SCFS */
8565          Ins_SCFS( EXEC_ARG_ args );
8566          break;
8567
8568        case 0x49:  /* MD */
8569        case 0x4A:  /* MD */
8570          Ins_MD( EXEC_ARG_ args );
8571          break;
8572
8573        case 0x4B:  /* MPPEM */
8574          DO_MPPEM
8575          break;
8576
8577        case 0x4C:  /* MPS */
8578          DO_MPS
8579          break;
8580
8581        case 0x4D:  /* FLIPON */
8582          DO_FLIPON
8583          break;
8584
8585        case 0x4E:  /* FLIPOFF */
8586          DO_FLIPOFF
8587          break;
8588
8589        case 0x4F:  /* DEBUG */
8590          DO_DEBUG
8591          break;
8592
8593        case 0x50:  /* LT */
8594          DO_LT
8595          break;
8596
8597        case 0x51:  /* LTEQ */
8598          DO_LTEQ
8599          break;
8600
8601        case 0x52:  /* GT */
8602          DO_GT
8603          break;
8604
8605        case 0x53:  /* GTEQ */
8606          DO_GTEQ
8607          break;
8608
8609        case 0x54:  /* EQ */
8610          DO_EQ
8611          break;
8612
8613        case 0x55:  /* NEQ */
8614          DO_NEQ
8615          break;
8616
8617        case 0x56:  /* ODD */
8618          DO_ODD
8619          break;
8620
8621        case 0x57:  /* EVEN */
8622          DO_EVEN
8623          break;
8624
8625        case 0x58:  /* IF */
8626          Ins_IF( EXEC_ARG_ args );
8627          break;
8628
8629        case 0x59:  /* EIF */
8630          /* do nothing */
8631          break;
8632
8633        case 0x5A:  /* AND */
8634          DO_AND
8635          break;
8636
8637        case 0x5B:  /* OR */
8638          DO_OR
8639          break;
8640
8641        case 0x5C:  /* NOT */
8642          DO_NOT
8643          break;
8644
8645        case 0x5D:  /* DELTAP1 */
8646          Ins_DELTAP( EXEC_ARG_ args );
8647          break;
8648
8649        case 0x5E:  /* SDB */
8650          DO_SDB
8651          break;
8652
8653        case 0x5F:  /* SDS */
8654          DO_SDS
8655          break;
8656
8657        case 0x60:  /* ADD */
8658          DO_ADD
8659          break;
8660
8661        case 0x61:  /* SUB */
8662          DO_SUB
8663          break;
8664
8665        case 0x62:  /* DIV */
8666          DO_DIV
8667          break;
8668
8669        case 0x63:  /* MUL */
8670          DO_MUL
8671          break;
8672
8673        case 0x64:  /* ABS */
8674          DO_ABS
8675          break;
8676
8677        case 0x65:  /* NEG */
8678          DO_NEG
8679          break;
8680
8681        case 0x66:  /* FLOOR */
8682          DO_FLOOR
8683          break;
8684
8685        case 0x67:  /* CEILING */
8686          DO_CEILING
8687          break;
8688
8689        case 0x68:  /* ROUND */
8690        case 0x69:  /* ROUND */
8691        case 0x6A:  /* ROUND */
8692        case 0x6B:  /* ROUND */
8693          DO_ROUND
8694          break;
8695
8696        case 0x6C:  /* NROUND */
8697        case 0x6D:  /* NROUND */
8698        case 0x6E:  /* NRRUND */
8699        case 0x6F:  /* NROUND */
8700          DO_NROUND
8701          break;
8702
8703        case 0x70:  /* WCVTF */
8704          DO_WCVTF
8705          break;
8706
8707        case 0x71:  /* DELTAP2 */
8708        case 0x72:  /* DELTAP3 */
8709          Ins_DELTAP( EXEC_ARG_ args );
8710          break;
8711
8712        case 0x73:  /* DELTAC0 */
8713        case 0x74:  /* DELTAC1 */
8714        case 0x75:  /* DELTAC2 */
8715          Ins_DELTAC( EXEC_ARG_ args );
8716          break;
8717
8718        case 0x76:  /* SROUND */
8719          DO_SROUND
8720          break;
8721
8722        case 0x77:  /* S45Round */
8723          DO_S45ROUND
8724          break;
8725
8726        case 0x78:  /* JROT */
8727          DO_JROT
8728          break;
8729
8730        case 0x79:  /* JROF */
8731          DO_JROF
8732          break;
8733
8734        case 0x7A:  /* ROFF */
8735          DO_ROFF
8736          break;
8737
8738        case 0x7B:  /* ???? */
8739          Ins_UNKNOWN( EXEC_ARG_ args );
8740          break;
8741
8742        case 0x7C:  /* RUTG */
8743          DO_RUTG
8744          break;
8745
8746        case 0x7D:  /* RDTG */
8747          DO_RDTG
8748          break;
8749
8750        case 0x7E:  /* SANGW */
8751        case 0x7F:  /* AA    */
8752          /* nothing - obsolete */
8753          break;
8754
8755        case 0x80:  /* FLIPPT */
8756          Ins_FLIPPT( EXEC_ARG_ args );
8757          break;
8758
8759        case 0x81:  /* FLIPRGON */
8760          Ins_FLIPRGON( EXEC_ARG_ args );
8761          break;
8762
8763        case 0x82:  /* FLIPRGOFF */
8764          Ins_FLIPRGOFF( EXEC_ARG_ args );
8765          break;
8766
8767        case 0x83:  /* UNKNOWN */
8768        case 0x84:  /* UNKNOWN */
8769          Ins_UNKNOWN( EXEC_ARG_ args );
8770          break;
8771
8772        case 0x85:  /* SCANCTRL */
8773          Ins_SCANCTRL( EXEC_ARG_ args );
8774          break;
8775
8776        case 0x86:  /* SDPVTL */
8777        case 0x87:  /* SDPVTL */
8778          Ins_SDPVTL( EXEC_ARG_ args );
8779          break;
8780
8781        case 0x88:  /* GETINFO */
8782          Ins_GETINFO( EXEC_ARG_ args );
8783          break;
8784
8785        case 0x89:  /* IDEF */
8786          Ins_IDEF( EXEC_ARG_ args );
8787          break;
8788
8789        case 0x8A:  /* ROLL */
8790          Ins_ROLL( EXEC_ARG_ args );
8791          break;
8792
8793        case 0x8B:  /* MAX */
8794          DO_MAX
8795          break;
8796
8797        case 0x8C:  /* MIN */
8798          DO_MIN
8799          break;
8800
8801        case 0x8D:  /* SCANTYPE */
8802          Ins_SCANTYPE( EXEC_ARG_ args );
8803          break;
8804
8805        case 0x8E:  /* INSTCTRL */
8806          Ins_INSTCTRL( EXEC_ARG_ args );
8807          break;
8808
8809        case 0x8F:
8810          Ins_UNKNOWN( EXEC_ARG_ args );
8811          break;
8812
8813        default:
8814          if ( opcode >= 0xE0 )
8815            Ins_MIRP( EXEC_ARG_ args );
8816          else if ( opcode >= 0xC0 )
8817            Ins_MDRP( EXEC_ARG_ args );
8818          else if ( opcode >= 0xB8 )
8819            Ins_PUSHW( EXEC_ARG_ args );
8820          else if ( opcode >= 0xB0 )
8821            Ins_PUSHB( EXEC_ARG_ args );
8822          else
8823            Ins_UNKNOWN( EXEC_ARG_ args );
8824        }
8825
8826      }
8827
8828#else
8829
8830      Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
8831
8832#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8833
8834      if ( CUR.error )
8835      {
8836        switch ( CUR.error )
8837        {
8838          /* looking for redefined instructions */
8839        case FT_ERR( Invalid_Opcode ):
8840          {
8841            TT_DefRecord*  def   = CUR.IDefs;
8842            TT_DefRecord*  limit = def + CUR.numIDefs;
8843
8844
8845            for ( ; def < limit; def++ )
8846            {
8847              if ( def->active && CUR.opcode == (FT_Byte)def->opc )
8848              {
8849                TT_CallRec*  callrec;
8850
8851
8852                if ( CUR.callTop >= CUR.callSize )
8853                {
8854                  CUR.error = FT_THROW( Invalid_Reference );
8855                  goto LErrorLabel_;
8856                }
8857
8858                callrec = &CUR.callStack[CUR.callTop];
8859
8860                callrec->Caller_Range = CUR.curRange;
8861                callrec->Caller_IP    = CUR.IP + 1;
8862                callrec->Cur_Count    = 1;
8863                callrec->Cur_Restart  = def->start;
8864                callrec->Cur_End      = def->end;
8865
8866                if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
8867                  goto LErrorLabel_;
8868
8869                goto LSuiteLabel_;
8870              }
8871            }
8872          }
8873
8874          CUR.error = FT_THROW( Invalid_Opcode );
8875          goto LErrorLabel_;
8876
8877#if 0
8878          break;   /* Unreachable code warning suppression.             */
8879                   /* Leave to remind in case a later change the editor */
8880                   /* to consider break;                                */
8881#endif
8882
8883        default:
8884          goto LErrorLabel_;
8885
8886#if 0
8887        break;
8888#endif
8889        }
8890      }
8891
8892      CUR.top = CUR.new_top;
8893
8894      if ( CUR.step_ins )
8895        CUR.IP += CUR.length;
8896
8897      /* increment instruction counter and check if we didn't */
8898      /* run this program for too long (e.g. infinite loops). */
8899      if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
8900        return FT_THROW( Execution_Too_Long );
8901
8902    LSuiteLabel_:
8903      if ( CUR.IP >= CUR.codeSize )
8904      {
8905        if ( CUR.callTop > 0 )
8906        {
8907          CUR.error = FT_THROW( Code_Overflow );
8908          goto LErrorLabel_;
8909        }
8910        else
8911          goto LNo_Error_;
8912      }
8913    } while ( !CUR.instruction_trap );
8914
8915  LNo_Error_:
8916
8917#ifdef TT_CONFIG_OPTION_STATIC_RASTER
8918    *exc = cur;
8919#endif
8920
8921    return FT_Err_Ok;
8922
8923  LErrorCodeOverflow_:
8924    CUR.error = FT_THROW( Code_Overflow );
8925
8926  LErrorLabel_:
8927
8928#ifdef TT_CONFIG_OPTION_STATIC_RASTER
8929    *exc = cur;
8930#endif
8931
8932    /* If any errors have occurred, function tables may be broken. */
8933    /* Force a re-execution of `prep' and `fpgm' tables if no      */
8934    /* bytecode debugger is run.                                   */
8935    if ( CUR.error && !CUR.instruction_trap )
8936    {
8937      FT_TRACE1(( "  The interpreter returned error 0x%x\n", CUR.error ));
8938      exc->size->cvt_ready      = FALSE;
8939    }
8940
8941    return CUR.error;
8942  }
8943
8944
8945#endif /* TT_USE_BYTECODE_INTERPRETER */
8946
8947
8948/* END */
8949