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

Last change on this file since 209 was 209, checked in by Eugene Romanenko, 14 years ago

PDF plugin: freetype library updated to version 2.3.5

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