Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

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