source: trunk/poppler/freetype2/src/truetype/ttinterp.c @ 159

Last change on this file since 159 was 150, checked in by Eugene Romanenko, 15 years ago

update freetype to 2.2.1

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