source: svn/trunk/zasc/freetype-2.3.9/ttinterp.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

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