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