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

Last change on this file since 275 was 275, checked in by rbri, 12 years ago

PDF plugin: freetype library updated to version 2.3.11

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