source: trunk/poppler/freetype-2.1.10/src/truetype/ttinterp.c @ 2

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

First import

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