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