ReactOS  0.4.14-dev-998-g623dd26
ttinterp.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2018 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17 
18 
19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
20 /* issues; many thanks! */
21 
22 
23 #include <ft2build.h>
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_CALC_H
26 #include FT_TRIGONOMETRY_H
27 #include FT_SYSTEM_H
28 #include FT_DRIVER_H
29 #include FT_MULTIPLE_MASTERS_H
30 
31 #include "ttinterp.h"
32 #include "tterrors.h"
33 #include "ttsubpix.h"
34 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
35 #include "ttgxvar.h"
36 #endif
37 
38 
39 #ifdef TT_USE_BYTECODE_INTERPRETER
40 
41 
42  /*************************************************************************/
43  /* */
44  /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
45  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
46  /* messages during execution. */
47  /* */
48 #undef FT_COMPONENT
49 #define FT_COMPONENT trace_ttinterp
50 
51 
52 #define NO_SUBPIXEL_HINTING \
53  ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
54  TT_INTERPRETER_VERSION_35 )
55 
56 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
57 #define SUBPIXEL_HINTING_INFINALITY \
58  ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
59  TT_INTERPRETER_VERSION_38 )
60 #endif
61 
62 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
63 #define SUBPIXEL_HINTING_MINIMAL \
64  ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
65  TT_INTERPRETER_VERSION_40 )
66 #endif
67 
68 #define PROJECT( v1, v2 ) \
69  exc->func_project( exc, \
70  SUB_LONG( (v1)->x, (v2)->x ), \
71  SUB_LONG( (v1)->y, (v2)->y ) )
72 
73 #define DUALPROJ( v1, v2 ) \
74  exc->func_dualproj( exc, \
75  SUB_LONG( (v1)->x, (v2)->x ), \
76  SUB_LONG( (v1)->y, (v2)->y ) )
77 
78 #define FAST_PROJECT( v ) \
79  exc->func_project( exc, (v)->x, (v)->y )
80 
81 #define FAST_DUALPROJ( v ) \
82  exc->func_dualproj( exc, (v)->x, (v)->y )
83 
84 
85  /*************************************************************************/
86  /* */
87  /* Two simple bounds-checking macros. */
88  /* */
89 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
90 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
91 
92 
93 #undef SUCCESS
94 #define SUCCESS 0
95 
96 #undef FAILURE
97 #define FAILURE 1
98 
99 
100  /*************************************************************************/
101  /* */
102  /* CODERANGE FUNCTIONS */
103  /* */
104  /*************************************************************************/
105 
106 
107  /*************************************************************************/
108  /* */
109  /* <Function> */
110  /* TT_Goto_CodeRange */
111  /* */
112  /* <Description> */
113  /* Switches to a new code range (updates the code related elements in */
114  /* `exec', and `IP'). */
115  /* */
116  /* <Input> */
117  /* range :: The new execution code range. */
118  /* */
119  /* IP :: The new IP in the new code range. */
120  /* */
121  /* <InOut> */
122  /* exec :: The target execution context. */
123  /* */
124  FT_LOCAL_DEF( void )
125  TT_Goto_CodeRange( TT_ExecContext exec,
126  FT_Int range,
127  FT_Long IP )
128  {
129  TT_CodeRange* coderange;
130 
131 
132  FT_ASSERT( range >= 1 && range <= 3 );
133 
134  coderange = &exec->codeRangeTable[range - 1];
135 
136  FT_ASSERT( coderange->base );
137 
138  /* NOTE: Because the last instruction of a program may be a CALL */
139  /* which will return to the first byte *after* the code */
140  /* range, we test for IP <= Size instead of IP < Size. */
141  /* */
142  FT_ASSERT( IP <= coderange->size );
143 
144  exec->code = coderange->base;
145  exec->codeSize = coderange->size;
146  exec->IP = IP;
147  exec->curRange = range;
148  }
149 
150 
151  /*************************************************************************/
152  /* */
153  /* <Function> */
154  /* TT_Set_CodeRange */
155  /* */
156  /* <Description> */
157  /* Sets a code range. */
158  /* */
159  /* <Input> */
160  /* range :: The code range index. */
161  /* */
162  /* base :: The new code base. */
163  /* */
164  /* length :: The range size in bytes. */
165  /* */
166  /* <InOut> */
167  /* exec :: The target execution context. */
168  /* */
169  FT_LOCAL_DEF( void )
170  TT_Set_CodeRange( TT_ExecContext exec,
171  FT_Int range,
172  void* base,
173  FT_Long length )
174  {
175  FT_ASSERT( range >= 1 && range <= 3 );
176 
177  exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
178  exec->codeRangeTable[range - 1].size = length;
179  }
180 
181 
182  /*************************************************************************/
183  /* */
184  /* <Function> */
185  /* TT_Clear_CodeRange */
186  /* */
187  /* <Description> */
188  /* Clears a code range. */
189  /* */
190  /* <Input> */
191  /* range :: The code range index. */
192  /* */
193  /* <InOut> */
194  /* exec :: The target execution context. */
195  /* */
196  FT_LOCAL_DEF( void )
197  TT_Clear_CodeRange( TT_ExecContext exec,
198  FT_Int range )
199  {
200  FT_ASSERT( range >= 1 && range <= 3 );
201 
202  exec->codeRangeTable[range - 1].base = NULL;
203  exec->codeRangeTable[range - 1].size = 0;
204  }
205 
206 
207  /*************************************************************************/
208  /* */
209  /* EXECUTION CONTEXT ROUTINES */
210  /* */
211  /*************************************************************************/
212 
213 
214  /*************************************************************************/
215  /* */
216  /* <Function> */
217  /* TT_Done_Context */
218  /* */
219  /* <Description> */
220  /* Destroys a given context. */
221  /* */
222  /* <Input> */
223  /* exec :: A handle to the target execution context. */
224  /* */
225  /* memory :: A handle to the parent memory object. */
226  /* */
227  /* <Note> */
228  /* Only the glyph loader and debugger should call this function. */
229  /* */
230  FT_LOCAL_DEF( void )
231  TT_Done_Context( TT_ExecContext exec )
232  {
233  FT_Memory memory = exec->memory;
234 
235 
236  /* points zone */
237  exec->maxPoints = 0;
238  exec->maxContours = 0;
239 
240  /* free stack */
241  FT_FREE( exec->stack );
242  exec->stackSize = 0;
243 
244  /* free call stack */
245  FT_FREE( exec->callStack );
246  exec->callSize = 0;
247  exec->callTop = 0;
248 
249  /* free glyph code range */
250  FT_FREE( exec->glyphIns );
251  exec->glyphSize = 0;
252 
253  exec->size = NULL;
254  exec->face = NULL;
255 
256  FT_FREE( exec );
257  }
258 
259 
260  /*************************************************************************/
261  /* */
262  /* <Function> */
263  /* Init_Context */
264  /* */
265  /* <Description> */
266  /* Initializes a context object. */
267  /* */
268  /* <Input> */
269  /* memory :: A handle to the parent memory object. */
270  /* */
271  /* <InOut> */
272  /* exec :: A handle to the target execution context. */
273  /* */
274  /* <Return> */
275  /* FreeType error code. 0 means success. */
276  /* */
277  static FT_Error
278  Init_Context( TT_ExecContext exec,
279  FT_Memory memory )
280  {
281  FT_Error error;
282 
283 
284  FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
285 
286  exec->memory = memory;
287  exec->callSize = 32;
288 
289  if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
290  goto Fail_Memory;
291 
292  /* all values in the context are set to 0 already, but this is */
293  /* here as a remainder */
294  exec->maxPoints = 0;
295  exec->maxContours = 0;
296 
297  exec->stackSize = 0;
298  exec->glyphSize = 0;
299 
300  exec->stack = NULL;
301  exec->glyphIns = NULL;
302 
303  exec->face = NULL;
304  exec->size = NULL;
305 
306  return FT_Err_Ok;
307 
308  Fail_Memory:
309  FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
310  TT_Done_Context( exec );
311 
312  return error;
313  }
314 
315 
316  /*************************************************************************/
317  /* */
318  /* <Function> */
319  /* Update_Max */
320  /* */
321  /* <Description> */
322  /* Checks the size of a buffer and reallocates it if necessary. */
323  /* */
324  /* <Input> */
325  /* memory :: A handle to the parent memory object. */
326  /* */
327  /* multiplier :: The size in bytes of each element in the buffer. */
328  /* */
329  /* new_max :: The new capacity (size) of the buffer. */
330  /* */
331  /* <InOut> */
332  /* size :: The address of the buffer's current size expressed */
333  /* in elements. */
334  /* */
335  /* buff :: The address of the buffer base pointer. */
336  /* */
337  /* <Return> */
338  /* FreeType error code. 0 means success. */
339  /* */
341  Update_Max( FT_Memory memory,
342  FT_ULong* size,
343  FT_ULong multiplier,
344  void* _pbuff,
345  FT_ULong new_max )
346  {
347  FT_Error error;
348  void** pbuff = (void**)_pbuff;
349 
350 
351  if ( *size < new_max )
352  {
353  if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
354  return error;
355  *size = new_max;
356  }
357 
358  return FT_Err_Ok;
359  }
360 
361 
362  /*************************************************************************/
363  /* */
364  /* <Function> */
365  /* TT_Load_Context */
366  /* */
367  /* <Description> */
368  /* Prepare an execution context for glyph hinting. */
369  /* */
370  /* <Input> */
371  /* face :: A handle to the source face object. */
372  /* */
373  /* size :: A handle to the source size object. */
374  /* */
375  /* <InOut> */
376  /* exec :: A handle to the target execution context. */
377  /* */
378  /* <Return> */
379  /* FreeType error code. 0 means success. */
380  /* */
381  /* <Note> */
382  /* Only the glyph loader and debugger should call this function. */
383  /* */
385  TT_Load_Context( TT_ExecContext exec,
386  TT_Face face,
387  TT_Size size )
388  {
389  FT_Int i;
390  FT_ULong tmp;
391  TT_MaxProfile* maxp;
392  FT_Error error;
393 
394 
395  exec->face = face;
396  maxp = &face->max_profile;
397  exec->size = size;
398 
399  if ( size )
400  {
401  exec->numFDefs = size->num_function_defs;
402  exec->maxFDefs = size->max_function_defs;
403  exec->numIDefs = size->num_instruction_defs;
404  exec->maxIDefs = size->max_instruction_defs;
405  exec->FDefs = size->function_defs;
406  exec->IDefs = size->instruction_defs;
407  exec->pointSize = size->point_size;
408  exec->tt_metrics = size->ttmetrics;
409  exec->metrics = *size->metrics;
410 
411  exec->maxFunc = size->max_func;
412  exec->maxIns = size->max_ins;
413 
414  for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
415  exec->codeRangeTable[i] = size->codeRangeTable[i];
416 
417  /* set graphics state */
418  exec->GS = size->GS;
419 
420  exec->cvtSize = size->cvt_size;
421  exec->cvt = size->cvt;
422 
423  exec->storeSize = size->storage_size;
424  exec->storage = size->storage;
425 
426  exec->twilight = size->twilight;
427 
428  /* In case of multi-threading it can happen that the old size object */
429  /* no longer exists, thus we must clear all glyph zone references. */
430  FT_ZERO( &exec->zp0 );
431  exec->zp1 = exec->zp0;
432  exec->zp2 = exec->zp0;
433  }
434 
435  /* XXX: We reserve a little more elements on the stack to deal safely */
436  /* with broken fonts like arialbs, courbs, timesbs, etc. */
437  tmp = (FT_ULong)exec->stackSize;
438  error = Update_Max( exec->memory,
439  &tmp,
440  sizeof ( FT_F26Dot6 ),
441  (void*)&exec->stack,
442  maxp->maxStackElements + 32 );
443  exec->stackSize = (FT_Long)tmp;
444  if ( error )
445  return error;
446 
447  tmp = exec->glyphSize;
448  error = Update_Max( exec->memory,
449  &tmp,
450  sizeof ( FT_Byte ),
451  (void*)&exec->glyphIns,
452  maxp->maxSizeOfInstructions );
453  exec->glyphSize = (FT_UShort)tmp;
454  if ( error )
455  return error;
456 
457  exec->pts.n_points = 0;
458  exec->pts.n_contours = 0;
459 
460  exec->zp1 = exec->pts;
461  exec->zp2 = exec->pts;
462  exec->zp0 = exec->pts;
463 
464  exec->instruction_trap = FALSE;
465 
466  return FT_Err_Ok;
467  }
468 
469 
470  /*************************************************************************/
471  /* */
472  /* <Function> */
473  /* TT_Save_Context */
474  /* */
475  /* <Description> */
476  /* Saves the code ranges in a `size' object. */
477  /* */
478  /* <Input> */
479  /* exec :: A handle to the source execution context. */
480  /* */
481  /* <InOut> */
482  /* size :: A handle to the target size object. */
483  /* */
484  /* <Note> */
485  /* Only the glyph loader and debugger should call this function. */
486  /* */
487  FT_LOCAL_DEF( void )
488  TT_Save_Context( TT_ExecContext exec,
489  TT_Size size )
490  {
491  FT_Int i;
492 
493 
494  /* XXX: Will probably disappear soon with all the code range */
495  /* management, which is now rather obsolete. */
496  /* */
497  size->num_function_defs = exec->numFDefs;
498  size->num_instruction_defs = exec->numIDefs;
499 
500  size->max_func = exec->maxFunc;
501  size->max_ins = exec->maxIns;
502 
503  for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
504  size->codeRangeTable[i] = exec->codeRangeTable[i];
505  }
506 
507 
508  /*************************************************************************/
509  /* */
510  /* <Function> */
511  /* TT_Run_Context */
512  /* */
513  /* <Description> */
514  /* Executes one or more instructions in the execution context. */
515  /* */
516  /* <Input> */
517  /* debug :: A Boolean flag. If set, the function sets some internal */
518  /* variables and returns immediately, otherwise TT_RunIns() */
519  /* is called. */
520  /* */
521  /* This is commented out currently. */
522  /* */
523  /* <Input> */
524  /* exec :: A handle to the target execution context. */
525  /* */
526  /* <Return> */
527  /* TrueType error code. 0 means success. */
528  /* */
530  TT_Run_Context( TT_ExecContext exec )
531  {
532  TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
533 
534  exec->zp0 = exec->pts;
535  exec->zp1 = exec->pts;
536  exec->zp2 = exec->pts;
537 
538  exec->GS.gep0 = 1;
539  exec->GS.gep1 = 1;
540  exec->GS.gep2 = 1;
541 
542  exec->GS.projVector.x = 0x4000;
543  exec->GS.projVector.y = 0x0000;
544 
545  exec->GS.freeVector = exec->GS.projVector;
546  exec->GS.dualVector = exec->GS.projVector;
547 
548  exec->GS.round_state = 1;
549  exec->GS.loop = 1;
550 
551  /* some glyphs leave something on the stack. so we clean it */
552  /* before a new execution. */
553  exec->top = 0;
554  exec->callTop = 0;
555 
556  return exec->face->interpreter( exec );
557  }
558 
559 
560  /* The default value for `scan_control' is documented as FALSE in the */
561  /* TrueType specification. This is confusing since it implies a */
562  /* Boolean value. However, this is not the case, thus both the */
563  /* default values of our `scan_type' and `scan_control' fields (which */
564  /* the documentation's `scan_control' variable is split into) are */
565  /* zero. */
566 
568  {
569  0, 0, 0,
570  { 0x4000, 0 },
571  { 0x4000, 0 },
572  { 0x4000, 0 },
573 
574  1, 64, 1,
575  TRUE, 68, 0, 0, 9, 3,
576  0, FALSE, 0, 1, 1, 1
577  };
578 
579 
580  /* documentation is in ttinterp.h */
581 
584  {
586  FT_Error error;
587 
588  TT_ExecContext exec = NULL;
589 
590 
591  if ( !driver )
592  goto Fail;
593 
594  memory = driver->root.root.memory;
595 
596  /* allocate object */
597  if ( FT_NEW( exec ) )
598  goto Fail;
599 
600  /* initialize it; in case of error this deallocates `exec' too */
601  error = Init_Context( exec, memory );
602  if ( error )
603  goto Fail;
604 
605  return exec;
606 
607  Fail:
608  return NULL;
609  }
610 
611 
612  /*************************************************************************/
613  /* */
614  /* Before an opcode is executed, the interpreter verifies that there are */
615  /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
616  /* table. */
617  /* */
618  /* For each opcode, the first column gives the number of arguments that */
619  /* are popped from the stack; the second one gives the number of those */
620  /* that are pushed in result. */
621  /* */
622  /* Opcodes which have a varying number of parameters in the data stream */
623  /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
624  /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
625  /* to zero. */
626  /* */
627  /*************************************************************************/
628 
629 
630 #undef PACK
631 #define PACK( x, y ) ( ( x << 4 ) | y )
632 
633 
634  static
635  const FT_Byte Pop_Push_Count[256] =
636  {
637  /* opcodes are gathered in groups of 16 */
638  /* please keep the spaces as they are */
639 
640  /* SVTCA y */ PACK( 0, 0 ),
641  /* SVTCA x */ PACK( 0, 0 ),
642  /* SPvTCA y */ PACK( 0, 0 ),
643  /* SPvTCA x */ PACK( 0, 0 ),
644  /* SFvTCA y */ PACK( 0, 0 ),
645  /* SFvTCA x */ PACK( 0, 0 ),
646  /* SPvTL // */ PACK( 2, 0 ),
647  /* SPvTL + */ PACK( 2, 0 ),
648  /* SFvTL // */ PACK( 2, 0 ),
649  /* SFvTL + */ PACK( 2, 0 ),
650  /* SPvFS */ PACK( 2, 0 ),
651  /* SFvFS */ PACK( 2, 0 ),
652  /* GPv */ PACK( 0, 2 ),
653  /* GFv */ PACK( 0, 2 ),
654  /* SFvTPv */ PACK( 0, 0 ),
655  /* ISECT */ PACK( 5, 0 ),
656 
657  /* SRP0 */ PACK( 1, 0 ),
658  /* SRP1 */ PACK( 1, 0 ),
659  /* SRP2 */ PACK( 1, 0 ),
660  /* SZP0 */ PACK( 1, 0 ),
661  /* SZP1 */ PACK( 1, 0 ),
662  /* SZP2 */ PACK( 1, 0 ),
663  /* SZPS */ PACK( 1, 0 ),
664  /* SLOOP */ PACK( 1, 0 ),
665  /* RTG */ PACK( 0, 0 ),
666  /* RTHG */ PACK( 0, 0 ),
667  /* SMD */ PACK( 1, 0 ),
668  /* ELSE */ PACK( 0, 0 ),
669  /* JMPR */ PACK( 1, 0 ),
670  /* SCvTCi */ PACK( 1, 0 ),
671  /* SSwCi */ PACK( 1, 0 ),
672  /* SSW */ PACK( 1, 0 ),
673 
674  /* DUP */ PACK( 1, 2 ),
675  /* POP */ PACK( 1, 0 ),
676  /* CLEAR */ PACK( 0, 0 ),
677  /* SWAP */ PACK( 2, 2 ),
678  /* DEPTH */ PACK( 0, 1 ),
679  /* CINDEX */ PACK( 1, 1 ),
680  /* MINDEX */ PACK( 1, 0 ),
681  /* AlignPTS */ PACK( 2, 0 ),
682  /* INS_$28 */ PACK( 0, 0 ),
683  /* UTP */ PACK( 1, 0 ),
684  /* LOOPCALL */ PACK( 2, 0 ),
685  /* CALL */ PACK( 1, 0 ),
686  /* FDEF */ PACK( 1, 0 ),
687  /* ENDF */ PACK( 0, 0 ),
688  /* MDAP[0] */ PACK( 1, 0 ),
689  /* MDAP[1] */ PACK( 1, 0 ),
690 
691  /* IUP[0] */ PACK( 0, 0 ),
692  /* IUP[1] */ PACK( 0, 0 ),
693  /* SHP[0] */ PACK( 0, 0 ), /* loops */
694  /* SHP[1] */ PACK( 0, 0 ), /* loops */
695  /* SHC[0] */ PACK( 1, 0 ),
696  /* SHC[1] */ PACK( 1, 0 ),
697  /* SHZ[0] */ PACK( 1, 0 ),
698  /* SHZ[1] */ PACK( 1, 0 ),
699  /* SHPIX */ PACK( 1, 0 ), /* loops */
700  /* IP */ PACK( 0, 0 ), /* loops */
701  /* MSIRP[0] */ PACK( 2, 0 ),
702  /* MSIRP[1] */ PACK( 2, 0 ),
703  /* AlignRP */ PACK( 0, 0 ), /* loops */
704  /* RTDG */ PACK( 0, 0 ),
705  /* MIAP[0] */ PACK( 2, 0 ),
706  /* MIAP[1] */ PACK( 2, 0 ),
707 
708  /* NPushB */ PACK( 0, 0 ),
709  /* NPushW */ PACK( 0, 0 ),
710  /* WS */ PACK( 2, 0 ),
711  /* RS */ PACK( 1, 1 ),
712  /* WCvtP */ PACK( 2, 0 ),
713  /* RCvt */ PACK( 1, 1 ),
714  /* GC[0] */ PACK( 1, 1 ),
715  /* GC[1] */ PACK( 1, 1 ),
716  /* SCFS */ PACK( 2, 0 ),
717  /* MD[0] */ PACK( 2, 1 ),
718  /* MD[1] */ PACK( 2, 1 ),
719  /* MPPEM */ PACK( 0, 1 ),
720  /* MPS */ PACK( 0, 1 ),
721  /* FlipON */ PACK( 0, 0 ),
722  /* FlipOFF */ PACK( 0, 0 ),
723  /* DEBUG */ PACK( 1, 0 ),
724 
725  /* LT */ PACK( 2, 1 ),
726  /* LTEQ */ PACK( 2, 1 ),
727  /* GT */ PACK( 2, 1 ),
728  /* GTEQ */ PACK( 2, 1 ),
729  /* EQ */ PACK( 2, 1 ),
730  /* NEQ */ PACK( 2, 1 ),
731  /* ODD */ PACK( 1, 1 ),
732  /* EVEN */ PACK( 1, 1 ),
733  /* IF */ PACK( 1, 0 ),
734  /* EIF */ PACK( 0, 0 ),
735  /* AND */ PACK( 2, 1 ),
736  /* OR */ PACK( 2, 1 ),
737  /* NOT */ PACK( 1, 1 ),
738  /* DeltaP1 */ PACK( 1, 0 ),
739  /* SDB */ PACK( 1, 0 ),
740  /* SDS */ PACK( 1, 0 ),
741 
742  /* ADD */ PACK( 2, 1 ),
743  /* SUB */ PACK( 2, 1 ),
744  /* DIV */ PACK( 2, 1 ),
745  /* MUL */ PACK( 2, 1 ),
746  /* ABS */ PACK( 1, 1 ),
747  /* NEG */ PACK( 1, 1 ),
748  /* FLOOR */ PACK( 1, 1 ),
749  /* CEILING */ PACK( 1, 1 ),
750  /* ROUND[0] */ PACK( 1, 1 ),
751  /* ROUND[1] */ PACK( 1, 1 ),
752  /* ROUND[2] */ PACK( 1, 1 ),
753  /* ROUND[3] */ PACK( 1, 1 ),
754  /* NROUND[0] */ PACK( 1, 1 ),
755  /* NROUND[1] */ PACK( 1, 1 ),
756  /* NROUND[2] */ PACK( 1, 1 ),
757  /* NROUND[3] */ PACK( 1, 1 ),
758 
759  /* WCvtF */ PACK( 2, 0 ),
760  /* DeltaP2 */ PACK( 1, 0 ),
761  /* DeltaP3 */ PACK( 1, 0 ),
762  /* DeltaCn[0] */ PACK( 1, 0 ),
763  /* DeltaCn[1] */ PACK( 1, 0 ),
764  /* DeltaCn[2] */ PACK( 1, 0 ),
765  /* SROUND */ PACK( 1, 0 ),
766  /* S45Round */ PACK( 1, 0 ),
767  /* JROT */ PACK( 2, 0 ),
768  /* JROF */ PACK( 2, 0 ),
769  /* ROFF */ PACK( 0, 0 ),
770  /* INS_$7B */ PACK( 0, 0 ),
771  /* RUTG */ PACK( 0, 0 ),
772  /* RDTG */ PACK( 0, 0 ),
773  /* SANGW */ PACK( 1, 0 ),
774  /* AA */ PACK( 1, 0 ),
775 
776  /* FlipPT */ PACK( 0, 0 ), /* loops */
777  /* FlipRgON */ PACK( 2, 0 ),
778  /* FlipRgOFF */ PACK( 2, 0 ),
779  /* INS_$83 */ PACK( 0, 0 ),
780  /* INS_$84 */ PACK( 0, 0 ),
781  /* ScanCTRL */ PACK( 1, 0 ),
782  /* SDPvTL[0] */ PACK( 2, 0 ),
783  /* SDPvTL[1] */ PACK( 2, 0 ),
784  /* GetINFO */ PACK( 1, 1 ),
785  /* IDEF */ PACK( 1, 0 ),
786  /* ROLL */ PACK( 3, 3 ),
787  /* MAX */ PACK( 2, 1 ),
788  /* MIN */ PACK( 2, 1 ),
789  /* ScanTYPE */ PACK( 1, 0 ),
790  /* InstCTRL */ PACK( 2, 0 ),
791  /* INS_$8F */ PACK( 0, 0 ),
792 
793  /* INS_$90 */ PACK( 0, 0 ),
794  /* GETVAR */ PACK( 0, 0 ), /* will be handled specially */
795  /* GETDATA */ PACK( 0, 1 ),
796  /* INS_$93 */ PACK( 0, 0 ),
797  /* INS_$94 */ PACK( 0, 0 ),
798  /* INS_$95 */ PACK( 0, 0 ),
799  /* INS_$96 */ PACK( 0, 0 ),
800  /* INS_$97 */ PACK( 0, 0 ),
801  /* INS_$98 */ PACK( 0, 0 ),
802  /* INS_$99 */ PACK( 0, 0 ),
803  /* INS_$9A */ PACK( 0, 0 ),
804  /* INS_$9B */ PACK( 0, 0 ),
805  /* INS_$9C */ PACK( 0, 0 ),
806  /* INS_$9D */ PACK( 0, 0 ),
807  /* INS_$9E */ PACK( 0, 0 ),
808  /* INS_$9F */ PACK( 0, 0 ),
809 
810  /* INS_$A0 */ PACK( 0, 0 ),
811  /* INS_$A1 */ PACK( 0, 0 ),
812  /* INS_$A2 */ PACK( 0, 0 ),
813  /* INS_$A3 */ PACK( 0, 0 ),
814  /* INS_$A4 */ PACK( 0, 0 ),
815  /* INS_$A5 */ PACK( 0, 0 ),
816  /* INS_$A6 */ PACK( 0, 0 ),
817  /* INS_$A7 */ PACK( 0, 0 ),
818  /* INS_$A8 */ PACK( 0, 0 ),
819  /* INS_$A9 */ PACK( 0, 0 ),
820  /* INS_$AA */ PACK( 0, 0 ),
821  /* INS_$AB */ PACK( 0, 0 ),
822  /* INS_$AC */ PACK( 0, 0 ),
823  /* INS_$AD */ PACK( 0, 0 ),
824  /* INS_$AE */ PACK( 0, 0 ),
825  /* INS_$AF */ PACK( 0, 0 ),
826 
827  /* PushB[0] */ PACK( 0, 1 ),
828  /* PushB[1] */ PACK( 0, 2 ),
829  /* PushB[2] */ PACK( 0, 3 ),
830  /* PushB[3] */ PACK( 0, 4 ),
831  /* PushB[4] */ PACK( 0, 5 ),
832  /* PushB[5] */ PACK( 0, 6 ),
833  /* PushB[6] */ PACK( 0, 7 ),
834  /* PushB[7] */ PACK( 0, 8 ),
835  /* PushW[0] */ PACK( 0, 1 ),
836  /* PushW[1] */ PACK( 0, 2 ),
837  /* PushW[2] */ PACK( 0, 3 ),
838  /* PushW[3] */ PACK( 0, 4 ),
839  /* PushW[4] */ PACK( 0, 5 ),
840  /* PushW[5] */ PACK( 0, 6 ),
841  /* PushW[6] */ PACK( 0, 7 ),
842  /* PushW[7] */ PACK( 0, 8 ),
843 
844  /* MDRP[00] */ PACK( 1, 0 ),
845  /* MDRP[01] */ PACK( 1, 0 ),
846  /* MDRP[02] */ PACK( 1, 0 ),
847  /* MDRP[03] */ PACK( 1, 0 ),
848  /* MDRP[04] */ PACK( 1, 0 ),
849  /* MDRP[05] */ PACK( 1, 0 ),
850  /* MDRP[06] */ PACK( 1, 0 ),
851  /* MDRP[07] */ PACK( 1, 0 ),
852  /* MDRP[08] */ PACK( 1, 0 ),
853  /* MDRP[09] */ PACK( 1, 0 ),
854  /* MDRP[10] */ PACK( 1, 0 ),
855  /* MDRP[11] */ PACK( 1, 0 ),
856  /* MDRP[12] */ PACK( 1, 0 ),
857  /* MDRP[13] */ PACK( 1, 0 ),
858  /* MDRP[14] */ PACK( 1, 0 ),
859  /* MDRP[15] */ PACK( 1, 0 ),
860 
861  /* MDRP[16] */ PACK( 1, 0 ),
862  /* MDRP[17] */ PACK( 1, 0 ),
863  /* MDRP[18] */ PACK( 1, 0 ),
864  /* MDRP[19] */ PACK( 1, 0 ),
865  /* MDRP[20] */ PACK( 1, 0 ),
866  /* MDRP[21] */ PACK( 1, 0 ),
867  /* MDRP[22] */ PACK( 1, 0 ),
868  /* MDRP[23] */ PACK( 1, 0 ),
869  /* MDRP[24] */ PACK( 1, 0 ),
870  /* MDRP[25] */ PACK( 1, 0 ),
871  /* MDRP[26] */ PACK( 1, 0 ),
872  /* MDRP[27] */ PACK( 1, 0 ),
873  /* MDRP[28] */ PACK( 1, 0 ),
874  /* MDRP[29] */ PACK( 1, 0 ),
875  /* MDRP[30] */ PACK( 1, 0 ),
876  /* MDRP[31] */ PACK( 1, 0 ),
877 
878  /* MIRP[00] */ PACK( 2, 0 ),
879  /* MIRP[01] */ PACK( 2, 0 ),
880  /* MIRP[02] */ PACK( 2, 0 ),
881  /* MIRP[03] */ PACK( 2, 0 ),
882  /* MIRP[04] */ PACK( 2, 0 ),
883  /* MIRP[05] */ PACK( 2, 0 ),
884  /* MIRP[06] */ PACK( 2, 0 ),
885  /* MIRP[07] */ PACK( 2, 0 ),
886  /* MIRP[08] */ PACK( 2, 0 ),
887  /* MIRP[09] */ PACK( 2, 0 ),
888  /* MIRP[10] */ PACK( 2, 0 ),
889  /* MIRP[11] */ PACK( 2, 0 ),
890  /* MIRP[12] */ PACK( 2, 0 ),
891  /* MIRP[13] */ PACK( 2, 0 ),
892  /* MIRP[14] */ PACK( 2, 0 ),
893  /* MIRP[15] */ PACK( 2, 0 ),
894 
895  /* MIRP[16] */ PACK( 2, 0 ),
896  /* MIRP[17] */ PACK( 2, 0 ),
897  /* MIRP[18] */ PACK( 2, 0 ),
898  /* MIRP[19] */ PACK( 2, 0 ),
899  /* MIRP[20] */ PACK( 2, 0 ),
900  /* MIRP[21] */ PACK( 2, 0 ),
901  /* MIRP[22] */ PACK( 2, 0 ),
902  /* MIRP[23] */ PACK( 2, 0 ),
903  /* MIRP[24] */ PACK( 2, 0 ),
904  /* MIRP[25] */ PACK( 2, 0 ),
905  /* MIRP[26] */ PACK( 2, 0 ),
906  /* MIRP[27] */ PACK( 2, 0 ),
907  /* MIRP[28] */ PACK( 2, 0 ),
908  /* MIRP[29] */ PACK( 2, 0 ),
909  /* MIRP[30] */ PACK( 2, 0 ),
910  /* MIRP[31] */ PACK( 2, 0 )
911  };
912 
913 
914 #ifdef FT_DEBUG_LEVEL_TRACE
915 
916  /* the first hex digit gives the length of the opcode name; the space */
917  /* after the digit is here just to increase readability of the source */
918  /* code */
919 
920  static
921  const char* const opcode_name[256] =
922  {
923  "7 SVTCA y",
924  "7 SVTCA x",
925  "8 SPvTCA y",
926  "8 SPvTCA x",
927  "8 SFvTCA y",
928  "8 SFvTCA x",
929  "8 SPvTL ||",
930  "7 SPvTL +",
931  "8 SFvTL ||",
932  "7 SFvTL +",
933  "5 SPvFS",
934  "5 SFvFS",
935  "3 GPv",
936  "3 GFv",
937  "6 SFvTPv",
938  "5 ISECT",
939 
940  "4 SRP0",
941  "4 SRP1",
942  "4 SRP2",
943  "4 SZP0",
944  "4 SZP1",
945  "4 SZP2",
946  "4 SZPS",
947  "5 SLOOP",
948  "3 RTG",
949  "4 RTHG",
950  "3 SMD",
951  "4 ELSE",
952  "4 JMPR",
953  "6 SCvTCi",
954  "5 SSwCi",
955  "3 SSW",
956 
957  "3 DUP",
958  "3 POP",
959  "5 CLEAR",
960  "4 SWAP",
961  "5 DEPTH",
962  "6 CINDEX",
963  "6 MINDEX",
964  "8 AlignPTS",
965  "7 INS_$28",
966  "3 UTP",
967  "8 LOOPCALL",
968  "4 CALL",
969  "4 FDEF",
970  "4 ENDF",
971  "7 MDAP[0]",
972  "7 MDAP[1]",
973 
974  "6 IUP[0]",
975  "6 IUP[1]",
976  "6 SHP[0]",
977  "6 SHP[1]",
978  "6 SHC[0]",
979  "6 SHC[1]",
980  "6 SHZ[0]",
981  "6 SHZ[1]",
982  "5 SHPIX",
983  "2 IP",
984  "8 MSIRP[0]",
985  "8 MSIRP[1]",
986  "7 AlignRP",
987  "4 RTDG",
988  "7 MIAP[0]",
989  "7 MIAP[1]",
990 
991  "6 NPushB",
992  "6 NPushW",
993  "2 WS",
994  "2 RS",
995  "5 WCvtP",
996  "4 RCvt",
997  "5 GC[0]",
998  "5 GC[1]",
999  "4 SCFS",
1000  "5 MD[0]",
1001  "5 MD[1]",
1002  "5 MPPEM",
1003  "3 MPS",
1004  "6 FlipON",
1005  "7 FlipOFF",
1006  "5 DEBUG",
1007 
1008  "2 LT",
1009  "4 LTEQ",
1010  "2 GT",
1011  "4 GTEQ",
1012  "2 EQ",
1013  "3 NEQ",
1014  "3 ODD",
1015  "4 EVEN",
1016  "2 IF",
1017  "3 EIF",
1018  "3 AND",
1019  "2 OR",
1020  "3 NOT",
1021  "7 DeltaP1",
1022  "3 SDB",
1023  "3 SDS",
1024 
1025  "3 ADD",
1026  "3 SUB",
1027  "3 DIV",
1028  "3 MUL",
1029  "3 ABS",
1030  "3 NEG",
1031  "5 FLOOR",
1032  "7 CEILING",
1033  "8 ROUND[0]",
1034  "8 ROUND[1]",
1035  "8 ROUND[2]",
1036  "8 ROUND[3]",
1037  "9 NROUND[0]",
1038  "9 NROUND[1]",
1039  "9 NROUND[2]",
1040  "9 NROUND[3]",
1041 
1042  "5 WCvtF",
1043  "7 DeltaP2",
1044  "7 DeltaP3",
1045  "A DeltaCn[0]",
1046  "A DeltaCn[1]",
1047  "A DeltaCn[2]",
1048  "6 SROUND",
1049  "8 S45Round",
1050  "4 JROT",
1051  "4 JROF",
1052  "4 ROFF",
1053  "7 INS_$7B",
1054  "4 RUTG",
1055  "4 RDTG",
1056  "5 SANGW",
1057  "2 AA",
1058 
1059  "6 FlipPT",
1060  "8 FlipRgON",
1061  "9 FlipRgOFF",
1062  "7 INS_$83",
1063  "7 INS_$84",
1064  "8 ScanCTRL",
1065  "9 SDPvTL[0]",
1066  "9 SDPvTL[1]",
1067  "7 GetINFO",
1068  "4 IDEF",
1069  "4 ROLL",
1070  "3 MAX",
1071  "3 MIN",
1072  "8 ScanTYPE",
1073  "8 InstCTRL",
1074  "7 INS_$8F",
1075 
1076  "7 INS_$90",
1077 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1078  "6 GETVAR",
1079  "7 GETDATA",
1080 #else
1081  "7 INS_$91",
1082  "7 INS_$92",
1083 #endif
1084  "7 INS_$93",
1085  "7 INS_$94",
1086  "7 INS_$95",
1087  "7 INS_$96",
1088  "7 INS_$97",
1089  "7 INS_$98",
1090  "7 INS_$99",
1091  "7 INS_$9A",
1092  "7 INS_$9B",
1093  "7 INS_$9C",
1094  "7 INS_$9D",
1095  "7 INS_$9E",
1096  "7 INS_$9F",
1097 
1098  "7 INS_$A0",
1099  "7 INS_$A1",
1100  "7 INS_$A2",
1101  "7 INS_$A3",
1102  "7 INS_$A4",
1103  "7 INS_$A5",
1104  "7 INS_$A6",
1105  "7 INS_$A7",
1106  "7 INS_$A8",
1107  "7 INS_$A9",
1108  "7 INS_$AA",
1109  "7 INS_$AB",
1110  "7 INS_$AC",
1111  "7 INS_$AD",
1112  "7 INS_$AE",
1113  "7 INS_$AF",
1114 
1115  "8 PushB[0]",
1116  "8 PushB[1]",
1117  "8 PushB[2]",
1118  "8 PushB[3]",
1119  "8 PushB[4]",
1120  "8 PushB[5]",
1121  "8 PushB[6]",
1122  "8 PushB[7]",
1123  "8 PushW[0]",
1124  "8 PushW[1]",
1125  "8 PushW[2]",
1126  "8 PushW[3]",
1127  "8 PushW[4]",
1128  "8 PushW[5]",
1129  "8 PushW[6]",
1130  "8 PushW[7]",
1131 
1132  "8 MDRP[00]",
1133  "8 MDRP[01]",
1134  "8 MDRP[02]",
1135  "8 MDRP[03]",
1136  "8 MDRP[04]",
1137  "8 MDRP[05]",
1138  "8 MDRP[06]",
1139  "8 MDRP[07]",
1140  "8 MDRP[08]",
1141  "8 MDRP[09]",
1142  "8 MDRP[10]",
1143  "8 MDRP[11]",
1144  "8 MDRP[12]",
1145  "8 MDRP[13]",
1146  "8 MDRP[14]",
1147  "8 MDRP[15]",
1148 
1149  "8 MDRP[16]",
1150  "8 MDRP[17]",
1151  "8 MDRP[18]",
1152  "8 MDRP[19]",
1153  "8 MDRP[20]",
1154  "8 MDRP[21]",
1155  "8 MDRP[22]",
1156  "8 MDRP[23]",
1157  "8 MDRP[24]",
1158  "8 MDRP[25]",
1159  "8 MDRP[26]",
1160  "8 MDRP[27]",
1161  "8 MDRP[28]",
1162  "8 MDRP[29]",
1163  "8 MDRP[30]",
1164  "8 MDRP[31]",
1165 
1166  "8 MIRP[00]",
1167  "8 MIRP[01]",
1168  "8 MIRP[02]",
1169  "8 MIRP[03]",
1170  "8 MIRP[04]",
1171  "8 MIRP[05]",
1172  "8 MIRP[06]",
1173  "8 MIRP[07]",
1174  "8 MIRP[08]",
1175  "8 MIRP[09]",
1176  "8 MIRP[10]",
1177  "8 MIRP[11]",
1178  "8 MIRP[12]",
1179  "8 MIRP[13]",
1180  "8 MIRP[14]",
1181  "8 MIRP[15]",
1182 
1183  "8 MIRP[16]",
1184  "8 MIRP[17]",
1185  "8 MIRP[18]",
1186  "8 MIRP[19]",
1187  "8 MIRP[20]",
1188  "8 MIRP[21]",
1189  "8 MIRP[22]",
1190  "8 MIRP[23]",
1191  "8 MIRP[24]",
1192  "8 MIRP[25]",
1193  "8 MIRP[26]",
1194  "8 MIRP[27]",
1195  "8 MIRP[28]",
1196  "8 MIRP[29]",
1197  "8 MIRP[30]",
1198  "8 MIRP[31]"
1199  };
1200 
1201 #endif /* FT_DEBUG_LEVEL_TRACE */
1202 
1203 
1204  static
1205  const FT_Char opcode_length[256] =
1206  {
1207  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1208  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1209  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1210  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1211 
1212  -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1213  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1214  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1215  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1216 
1217  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1218  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1219  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1220  2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1221 
1222  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1223  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1224  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1225  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1226  };
1227 
1228 #undef PACK
1229 
1230 
1231 #ifndef FT_CONFIG_OPTION_NO_ASSEMBLER
1232 
1233 #if defined( __arm__ ) && \
1234  ( defined( __thumb2__ ) || !defined( __thumb__ ) )
1235 
1236 #define TT_MulFix14 TT_MulFix14_arm
1237 
1238  static FT_Int32
1239  TT_MulFix14_arm( FT_Int32 a,
1240  FT_Int b )
1241  {
1242  FT_Int32 t, t2;
1243 
1244 
1245 #if defined( __CC_ARM ) || defined( __ARMCC__ )
1246 
1247  __asm
1248  {
1249  smull t2, t, b, a /* (lo=t2,hi=t) = a*b */
1250  mov a, t, asr #31 /* a = (hi >> 31) */
1251  add a, a, #0x2000 /* a += 0x2000 */
1252  adds t2, t2, a /* t2 += a */
1253  adc t, t, #0 /* t += carry */
1254  mov a, t2, lsr #14 /* a = t2 >> 14 */
1255  orr a, a, t, lsl #18 /* a |= t << 18 */
1256  }
1257 
1258 #elif defined( __GNUC__ )
1259 
1260  __asm__ __volatile__ (
1261  "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */
1262  "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */
1263 #if defined( __clang__ ) && defined( __thumb2__ )
1264  "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
1265 #else
1266  "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
1267 #endif
1268  "adds %1, %1, %0\n\t" /* %1 += %0 */
1269  "adc %2, %2, #0\n\t" /* %2 += carry */
1270  "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */
1271  "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */
1272  : "=r"(a), "=&r"(t2), "=&r"(t)
1273  : "r"(a), "r"(b)
1274  : "cc" );
1275 
1276 #endif
1277 
1278  return a;
1279  }
1280 
1281 #endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */
1282 
1283 #endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
1284 
1285 
1286 #if defined( __GNUC__ ) && \
1287  ( defined( __i386__ ) || defined( __x86_64__ ) )
1288 
1289 #define TT_MulFix14 TT_MulFix14_long_long
1290 
1291  /* Temporarily disable the warning that C90 doesn't support `long long'. */
1292 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1293 #pragma GCC diagnostic push
1294 #endif
1295 #pragma GCC diagnostic ignored "-Wlong-long"
1296 
1297  /* This is declared `noinline' because inlining the function results */
1298  /* in slower code. The `pure' attribute indicates that the result */
1299  /* only depends on the parameters. */
1300  static __attribute__(( noinline ))
1301  __attribute__(( pure )) FT_Int32
1302  TT_MulFix14_long_long( FT_Int32 a,
1303  FT_Int b )
1304  {
1305 
1306  long long ret = (long long)a * b;
1307 
1308  /* The following line assumes that right shifting of signed values */
1309  /* will actually preserve the sign bit. The exact behaviour is */
1310  /* undefined, but this is true on x86 and x86_64. */
1311  long long tmp = ret >> 63;
1312 
1313 
1314  ret += 0x2000 + tmp;
1315 
1316  return (FT_Int32)( ret >> 14 );
1317  }
1318 
1319 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1320 #pragma GCC diagnostic pop
1321 #endif
1322 
1323 #endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */
1324 
1325 
1326 #ifndef TT_MulFix14
1327 
1328  /* Compute (a*b)/2^14 with maximum accuracy and rounding. */
1329  /* This is optimized to be faster than calling FT_MulFix() */
1330  /* for platforms where sizeof(int) == 2. */
1331  static FT_Int32
1332  TT_MulFix14( FT_Int32 a,
1333  FT_Int b )
1334  {
1335  FT_Int32 sign;
1336  FT_UInt32 ah, al, mid, lo, hi;
1337 
1338 
1339  sign = a ^ b;
1340 
1341  if ( a < 0 )
1342  a = -a;
1343  if ( b < 0 )
1344  b = -b;
1345 
1346  ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1347  al = (FT_UInt32)( a & 0xFFFFU );
1348 
1349  lo = al * b;
1350  mid = ah * b;
1351  hi = mid >> 16;
1352  mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1353  lo += mid;
1354  if ( lo < mid )
1355  hi += 1;
1356 
1357  mid = ( lo >> 14 ) | ( hi << 18 );
1358 
1359  return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1360  }
1361 
1362 #endif /* !TT_MulFix14 */
1363 
1364 
1365 #if defined( __GNUC__ ) && \
1366  ( defined( __i386__ ) || \
1367  defined( __x86_64__ ) || \
1368  defined( __arm__ ) )
1369 
1370 #define TT_DotFix14 TT_DotFix14_long_long
1371 
1372 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1373 #pragma GCC diagnostic push
1374 #endif
1375 #pragma GCC diagnostic ignored "-Wlong-long"
1376 
1377  static __attribute__(( pure )) FT_Int32
1378  TT_DotFix14_long_long( FT_Int32 ax,
1379  FT_Int32 ay,
1380  FT_Int bx,
1381  FT_Int by )
1382  {
1383  /* Temporarily disable the warning that C90 doesn't support */
1384  /* `long long'. */
1385 
1386  long long temp1 = (long long)ax * bx;
1387  long long temp2 = (long long)ay * by;
1388 
1389 
1390  temp1 += temp2;
1391  temp2 = temp1 >> 63;
1392  temp1 += 0x2000 + temp2;
1393 
1394  return (FT_Int32)( temp1 >> 14 );
1395 
1396  }
1397 
1398 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1399 #pragma GCC diagnostic pop
1400 #endif
1401 
1402 #endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */
1403 
1404 
1405 #ifndef TT_DotFix14
1406 
1407  /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
1408  static FT_Int32
1409  TT_DotFix14( FT_Int32 ax,
1410  FT_Int32 ay,
1411  FT_Int bx,
1412  FT_Int by )
1413  {
1414  FT_Int32 m, s, hi1, hi2, hi;
1415  FT_UInt32 l, lo1, lo2, lo;
1416 
1417 
1418  /* compute ax*bx as 64-bit value */
1419  l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1420  m = ( ax >> 16 ) * bx;
1421 
1422  lo1 = l + ( (FT_UInt32)m << 16 );
1423  hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1424 
1425  /* compute ay*by as 64-bit value */
1426  l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1427  m = ( ay >> 16 ) * by;
1428 
1429  lo2 = l + ( (FT_UInt32)m << 16 );
1430  hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1431 
1432  /* add them */
1433  lo = lo1 + lo2;
1434  hi = hi1 + hi2 + ( lo < lo1 );
1435 
1436  /* divide the result by 2^14 with rounding */
1437  s = hi >> 31;
1438  l = lo + (FT_UInt32)s;
1439  hi += s + ( l < lo );
1440  lo = l;
1441 
1442  l = lo + 0x2000U;
1443  hi += ( l < lo );
1444 
1445  return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
1446  }
1447 
1448 #endif /* TT_DotFix14 */
1449 
1450 
1451  /*************************************************************************/
1452  /* */
1453  /* <Function> */
1454  /* Current_Ratio */
1455  /* */
1456  /* <Description> */
1457  /* Returns the current aspect ratio scaling factor depending on the */
1458  /* projection vector's state and device resolutions. */
1459  /* */
1460  /* <Return> */
1461  /* The aspect ratio in 16.16 format, always <= 1.0 . */
1462  /* */
1463  static FT_Long
1464  Current_Ratio( TT_ExecContext exc )
1465  {
1466  if ( !exc->tt_metrics.ratio )
1467  {
1468  if ( exc->GS.projVector.y == 0 )
1469  exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;
1470 
1471  else if ( exc->GS.projVector.x == 0 )
1472  exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;
1473 
1474  else
1475  {
1476  FT_F26Dot6 x, y;
1477 
1478 
1479  x = TT_MulFix14( exc->tt_metrics.x_ratio,
1480  exc->GS.projVector.x );
1481  y = TT_MulFix14( exc->tt_metrics.y_ratio,
1482  exc->GS.projVector.y );
1483  exc->tt_metrics.ratio = FT_Hypot( x, y );
1484  }
1485  }
1486  return exc->tt_metrics.ratio;
1487  }
1488 
1489 
1491  Current_Ppem( TT_ExecContext exc )
1492  {
1493  return exc->tt_metrics.ppem;
1494  }
1495 
1496 
1498  Current_Ppem_Stretched( TT_ExecContext exc )
1499  {
1500  return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );
1501  }
1502 
1503 
1504  /*************************************************************************/
1505  /* */
1506  /* Functions related to the control value table (CVT). */
1507  /* */
1508  /*************************************************************************/
1509 
1510 
1512  Read_CVT( TT_ExecContext exc,
1513  FT_ULong idx )
1514  {
1515  return exc->cvt[idx];
1516  }
1517 
1518 
1520  Read_CVT_Stretched( TT_ExecContext exc,
1521  FT_ULong idx )
1522  {
1523  return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
1524  }
1525 
1526 
1527  FT_CALLBACK_DEF( void )
1528  Write_CVT( TT_ExecContext exc,
1529  FT_ULong idx,
1530  FT_F26Dot6 value )
1531  {
1532  exc->cvt[idx] = value;
1533  }
1534 
1535 
1536  FT_CALLBACK_DEF( void )
1537  Write_CVT_Stretched( TT_ExecContext exc,
1538  FT_ULong idx,
1539  FT_F26Dot6 value )
1540  {
1541  exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
1542  }
1543 
1544 
1545  FT_CALLBACK_DEF( void )
1546  Move_CVT( TT_ExecContext exc,
1547  FT_ULong idx,
1548  FT_F26Dot6 value )
1549  {
1550  exc->cvt[idx] += value;
1551  }
1552 
1553 
1554  FT_CALLBACK_DEF( void )
1555  Move_CVT_Stretched( TT_ExecContext exc,
1556  FT_ULong idx,
1557  FT_F26Dot6 value )
1558  {
1559  exc->cvt[idx] += FT_DivFix( value, Current_Ratio( exc ) );
1560  }
1561 
1562 
1563  /*************************************************************************/
1564  /* */
1565  /* <Function> */
1566  /* GetShortIns */
1567  /* */
1568  /* <Description> */
1569  /* Returns a short integer taken from the instruction stream at */
1570  /* address IP. */
1571  /* */
1572  /* <Return> */
1573  /* Short read at code[IP]. */
1574  /* */
1575  /* <Note> */
1576  /* This one could become a macro. */
1577  /* */
1578  static FT_Short
1579  GetShortIns( TT_ExecContext exc )
1580  {
1581  /* Reading a byte stream so there is no endianness (DaveP) */
1582  exc->IP += 2;
1583  return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
1584  exc->code[exc->IP - 1] );
1585  }
1586 
1587 
1588  /*************************************************************************/
1589  /* */
1590  /* <Function> */
1591  /* Ins_Goto_CodeRange */
1592  /* */
1593  /* <Description> */
1594  /* Goes to a certain code range in the instruction stream. */
1595  /* */
1596  /* <Input> */
1597  /* aRange :: The index of the code range. */
1598  /* */
1599  /* aIP :: The new IP address in the code range. */
1600  /* */
1601  /* <Return> */
1602  /* SUCCESS or FAILURE. */
1603  /* */
1604  static FT_Bool
1605  Ins_Goto_CodeRange( TT_ExecContext exc,
1606  FT_Int aRange,
1607  FT_Long aIP )
1608  {
1610 
1611 
1612  if ( aRange < 1 || aRange > 3 )
1613  {
1614  exc->error = FT_THROW( Bad_Argument );
1615  return FAILURE;
1616  }
1617 
1618  range = &exc->codeRangeTable[aRange - 1];
1619 
1620  if ( !range->base ) /* invalid coderange */
1621  {
1622  exc->error = FT_THROW( Invalid_CodeRange );
1623  return FAILURE;
1624  }
1625 
1626  /* NOTE: Because the last instruction of a program may be a CALL */
1627  /* which will return to the first byte *after* the code */
1628  /* range, we test for aIP <= Size, instead of aIP < Size. */
1629 
1630  if ( aIP > range->size )
1631  {
1632  exc->error = FT_THROW( Code_Overflow );
1633  return FAILURE;
1634  }
1635 
1636  exc->code = range->base;
1637  exc->codeSize = range->size;
1638  exc->IP = aIP;
1639  exc->curRange = aRange;
1640 
1641  return SUCCESS;
1642  }
1643 
1644 
1645  /*************************************************************************/
1646  /* */
1647  /* <Function> */
1648  /* Direct_Move */
1649  /* */
1650  /* <Description> */
1651  /* Moves a point by a given distance along the freedom vector. The */
1652  /* point will be `touched'. */
1653  /* */
1654  /* <Input> */
1655  /* point :: The index of the point to move. */
1656  /* */
1657  /* distance :: The distance to apply. */
1658  /* */
1659  /* <InOut> */
1660  /* zone :: The affected glyph zone. */
1661  /* */
1662  /* <Note> */
1663  /* See `ttinterp.h' for details on backward compatibility mode. */
1664  /* `Touches' the point. */
1665  /* */
1666  static void
1667  Direct_Move( TT_ExecContext exc,
1669  FT_UShort point,
1671  {
1672  FT_F26Dot6 v;
1673 
1674 
1675  v = exc->GS.freeVector.x;
1676 
1677  if ( v != 0 )
1678  {
1679 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1680  if ( SUBPIXEL_HINTING_INFINALITY &&
1681  ( !exc->ignore_x_mode ||
1682  ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
1683  zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1685  v,
1686  exc->F_dot_P ) );
1687  else
1688 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1689 
1690 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1691  /* Exception to the post-IUP curfew: Allow the x component of */
1692  /* diagonal moves, but only post-IUP. DejaVu tries to adjust */
1693  /* diagonal stems like on `Z' and `z' post-IUP. */
1694  if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
1695  zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1697  v,
1698  exc->F_dot_P ) );
1699  else
1700 #endif
1701 
1702  if ( NO_SUBPIXEL_HINTING )
1703  zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1705  v,
1706  exc->F_dot_P ) );
1707 
1708  zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1709  }
1710 
1711  v = exc->GS.freeVector.y;
1712 
1713  if ( v != 0 )
1714  {
1715 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1716  if ( !( SUBPIXEL_HINTING_MINIMAL &&
1717  exc->backward_compatibility &&
1718  exc->iupx_called &&
1719  exc->iupy_called ) )
1720 #endif
1721  zone->cur[point].y = ADD_LONG( zone->cur[point].y,
1723  v,
1724  exc->F_dot_P ) );
1725 
1726  zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1727  }
1728  }
1729 
1730 
1731  /*************************************************************************/
1732  /* */
1733  /* <Function> */
1734  /* Direct_Move_Orig */
1735  /* */
1736  /* <Description> */
1737  /* Moves the *original* position of a point by a given distance along */
1738  /* the freedom vector. Obviously, the point will not be `touched'. */
1739  /* */
1740  /* <Input> */
1741  /* point :: The index of the point to move. */
1742  /* */
1743  /* distance :: The distance to apply. */
1744  /* */
1745  /* <InOut> */
1746  /* zone :: The affected glyph zone. */
1747  /* */
1748  static void
1749  Direct_Move_Orig( TT_ExecContext exc,
1751  FT_UShort point,
1753  {
1754  FT_F26Dot6 v;
1755 
1756 
1757  v = exc->GS.freeVector.x;
1758 
1759  if ( v != 0 )
1760  zone->org[point].x = ADD_LONG( zone->org[point].x,
1762  v,
1763  exc->F_dot_P ) );
1764 
1765  v = exc->GS.freeVector.y;
1766 
1767  if ( v != 0 )
1768  zone->org[point].y = ADD_LONG( zone->org[point].y,
1770  v,
1771  exc->F_dot_P ) );
1772  }
1773 
1774 
1775  /*************************************************************************/
1776  /* */
1777  /* Special versions of Direct_Move() */
1778  /* */
1779  /* The following versions are used whenever both vectors are both */
1780  /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1781  /* See `ttinterp.h' for details on backward compatibility mode. */
1782  /* */
1783  /*************************************************************************/
1784 
1785 
1786  static void
1787  Direct_Move_X( TT_ExecContext exc,
1789  FT_UShort point,
1791  {
1792 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1793  if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
1794  zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1795  else
1796 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1797 
1798 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1799  if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
1800  zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1801  else
1802 #endif
1803 
1804  if ( NO_SUBPIXEL_HINTING )
1805  zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1806 
1807  zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1808  }
1809 
1810 
1811  static void
1812  Direct_Move_Y( TT_ExecContext exc,
1814  FT_UShort point,
1816  {
1817  FT_UNUSED( exc );
1818 
1819 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1820  if ( !( SUBPIXEL_HINTING_MINIMAL &&
1821  exc->backward_compatibility &&
1822  exc->iupx_called && exc->iupy_called ) )
1823 #endif
1824  zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );
1825 
1826  zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1827  }
1828 
1829 
1830  /*************************************************************************/
1831  /* */
1832  /* Special versions of Direct_Move_Orig() */
1833  /* */
1834  /* The following versions are used whenever both vectors are both */
1835  /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1836  /* */
1837  /*************************************************************************/
1838 
1839 
1840  static void
1841  Direct_Move_Orig_X( TT_ExecContext exc,
1843  FT_UShort point,
1845  {
1846  FT_UNUSED( exc );
1847 
1848  zone->org[point].x = ADD_LONG( zone->org[point].x, distance );
1849  }
1850 
1851 
1852  static void
1853  Direct_Move_Orig_Y( TT_ExecContext exc,
1855  FT_UShort point,
1857  {
1858  FT_UNUSED( exc );
1859 
1860  zone->org[point].y = ADD_LONG( zone->org[point].y, distance );
1861  }
1862 
1863 
1864  /*************************************************************************/
1865  /* */
1866  /* <Function> */
1867  /* Round_None */
1868  /* */
1869  /* <Description> */
1870  /* Does not round, but adds engine compensation. */
1871  /* */
1872  /* <Input> */
1873  /* distance :: The distance (not) to round. */
1874  /* */
1875  /* compensation :: The engine compensation. */
1876  /* */
1877  /* <Return> */
1878  /* The compensated distance. */
1879  /* */
1880  /* <Note> */
1881  /* The TrueType specification says very few about the relationship */
1882  /* between rounding and engine compensation. However, it seems from */
1883  /* the description of super round that we should add the compensation */
1884  /* before rounding. */
1885  /* */
1886  static FT_F26Dot6
1887  Round_None( TT_ExecContext exc,
1889  FT_F26Dot6 compensation )
1890  {
1891  FT_F26Dot6 val;
1892 
1893  FT_UNUSED( exc );
1894 
1895 
1896  if ( distance >= 0 )
1897  {
1898  val = ADD_LONG( distance, compensation );
1899  if ( val < 0 )
1900  val = 0;
1901  }
1902  else
1903  {
1904  val = SUB_LONG( distance, compensation );
1905  if ( val > 0 )
1906  val = 0;
1907  }
1908  return val;
1909  }
1910 
1911 
1912  /*************************************************************************/
1913  /* */
1914  /* <Function> */
1915  /* Round_To_Grid */
1916  /* */
1917  /* <Description> */
1918  /* Rounds value to grid after adding engine compensation. */
1919  /* */
1920  /* <Input> */
1921  /* distance :: The distance to round. */
1922  /* */
1923  /* compensation :: The engine compensation. */
1924  /* */
1925  /* <Return> */
1926  /* Rounded distance. */
1927  /* */
1928  static FT_F26Dot6
1929  Round_To_Grid( TT_ExecContext exc,
1931  FT_F26Dot6 compensation )
1932  {
1933  FT_F26Dot6 val;
1934 
1935  FT_UNUSED( exc );
1936 
1937 
1938  if ( distance >= 0 )
1939  {
1940  val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );
1941  if ( val < 0 )
1942  val = 0;
1943  }
1944  else
1945  {
1946  val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,
1947  distance ) ) );
1948  if ( val > 0 )
1949  val = 0;
1950  }
1951 
1952  return val;
1953  }
1954 
1955 
1956  /*************************************************************************/
1957  /* */
1958  /* <Function> */
1959  /* Round_To_Half_Grid */
1960  /* */
1961  /* <Description> */
1962  /* Rounds value to half grid after adding engine compensation. */
1963  /* */
1964  /* <Input> */
1965  /* distance :: The distance to round. */
1966  /* */
1967  /* compensation :: The engine compensation. */
1968  /* */
1969  /* <Return> */
1970  /* Rounded distance. */
1971  /* */
1972  static FT_F26Dot6
1973  Round_To_Half_Grid( TT_ExecContext exc,
1975  FT_F26Dot6 compensation )
1976  {
1977  FT_F26Dot6 val;
1978 
1979  FT_UNUSED( exc );
1980 
1981 
1982  if ( distance >= 0 )
1983  {
1984  val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),
1985  32 );
1986  if ( val < 0 )
1987  val = 32;
1988  }
1989  else
1990  {
1991  val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,
1992  distance ) ),
1993  32 ) );
1994  if ( val > 0 )
1995  val = -32;
1996  }
1997 
1998  return val;
1999  }
2000 
2001 
2002  /*************************************************************************/
2003  /* */
2004  /* <Function> */
2005  /* Round_Down_To_Grid */
2006  /* */
2007  /* <Description> */
2008  /* Rounds value down to grid after adding engine compensation. */
2009  /* */
2010  /* <Input> */
2011  /* distance :: The distance to round. */
2012  /* */
2013  /* compensation :: The engine compensation. */
2014  /* */
2015  /* <Return> */
2016  /* Rounded distance. */
2017  /* */
2018  static FT_F26Dot6
2019  Round_Down_To_Grid( TT_ExecContext exc,
2021  FT_F26Dot6 compensation )
2022  {
2023  FT_F26Dot6 val;
2024 
2025  FT_UNUSED( exc );
2026 
2027 
2028  if ( distance >= 0 )
2029  {
2030  val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );
2031  if ( val < 0 )
2032  val = 0;
2033  }
2034  else
2035  {
2036  val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );
2037  if ( val > 0 )
2038  val = 0;
2039  }
2040 
2041  return val;
2042  }
2043 
2044 
2045  /*************************************************************************/
2046  /* */
2047  /* <Function> */
2048  /* Round_Up_To_Grid */
2049  /* */
2050  /* <Description> */
2051  /* Rounds value up to grid after adding engine compensation. */
2052  /* */
2053  /* <Input> */
2054  /* distance :: The distance to round. */
2055  /* */
2056  /* compensation :: The engine compensation. */
2057  /* */
2058  /* <Return> */
2059  /* Rounded distance. */
2060  /* */
2061  static FT_F26Dot6
2062  Round_Up_To_Grid( TT_ExecContext exc,
2064  FT_F26Dot6 compensation )
2065  {
2066  FT_F26Dot6 val;
2067 
2068  FT_UNUSED( exc );
2069 
2070 
2071  if ( distance >= 0 )
2072  {
2073  val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );
2074  if ( val < 0 )
2075  val = 0;
2076  }
2077  else
2078  {
2079  val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,
2080  distance ) ) );
2081  if ( val > 0 )
2082  val = 0;
2083  }
2084 
2085  return val;
2086  }
2087 
2088 
2089  /*************************************************************************/
2090  /* */
2091  /* <Function> */
2092  /* Round_To_Double_Grid */
2093  /* */
2094  /* <Description> */
2095  /* Rounds value to double grid after adding engine compensation. */
2096  /* */
2097  /* <Input> */
2098  /* distance :: The distance to round. */
2099  /* */
2100  /* compensation :: The engine compensation. */
2101  /* */
2102  /* <Return> */
2103  /* Rounded distance. */
2104  /* */
2105  static FT_F26Dot6
2106  Round_To_Double_Grid( TT_ExecContext exc,
2108  FT_F26Dot6 compensation )
2109  {
2110  FT_F26Dot6 val;
2111 
2112  FT_UNUSED( exc );
2113 
2114 
2115  if ( distance >= 0 )
2116  {
2117  val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );
2118  if ( val < 0 )
2119  val = 0;
2120  }
2121  else
2122  {
2123  val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),
2124  32 ) );
2125  if ( val > 0 )
2126  val = 0;
2127  }
2128 
2129  return val;
2130  }
2131 
2132 
2133  /*************************************************************************/
2134  /* */
2135  /* <Function> */
2136  /* Round_Super */
2137  /* */
2138  /* <Description> */
2139  /* Super-rounds value to grid after adding engine compensation. */
2140  /* */
2141  /* <Input> */
2142  /* distance :: The distance to round. */
2143  /* */
2144  /* compensation :: The engine compensation. */
2145  /* */
2146  /* <Return> */
2147  /* Rounded distance. */
2148  /* */
2149  /* <Note> */
2150  /* The TrueType specification says very little about the relationship */
2151  /* between rounding and engine compensation. However, it seems from */
2152  /* the description of super round that we should add the compensation */
2153  /* before rounding. */
2154  /* */
2155  static FT_F26Dot6
2156  Round_Super( TT_ExecContext exc,
2158  FT_F26Dot6 compensation )
2159  {
2160  FT_F26Dot6 val;
2161 
2162 
2163  if ( distance >= 0 )
2164  {
2165  val = ADD_LONG( distance,
2166  exc->threshold - exc->phase + compensation ) &
2167  -exc->period;
2168  val += exc->phase;
2169  if ( val < 0 )
2170  val = exc->phase;
2171  }
2172  else
2173  {
2174  val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,
2175  distance ) &
2176  -exc->period );
2177  val -= exc->phase;
2178  if ( val > 0 )
2179  val = -exc->phase;
2180  }
2181 
2182  return val;
2183  }
2184 
2185 
2186  /*************************************************************************/
2187  /* */
2188  /* <Function> */
2189  /* Round_Super_45 */
2190  /* */
2191  /* <Description> */
2192  /* Super-rounds value to grid after adding engine compensation. */
2193  /* */
2194  /* <Input> */
2195  /* distance :: The distance to round. */
2196  /* */
2197  /* compensation :: The engine compensation. */
2198  /* */
2199  /* <Return> */
2200  /* Rounded distance. */
2201  /* */
2202  /* <Note> */
2203  /* There is a separate function for Round_Super_45() as we may need */
2204  /* greater precision. */
2205  /* */
2206  static FT_F26Dot6
2207  Round_Super_45( TT_ExecContext exc,
2209  FT_F26Dot6 compensation )
2210  {
2211  FT_F26Dot6 val;
2212 
2213 
2214  if ( distance >= 0 )
2215  {
2216  val = ( ADD_LONG( distance,
2217  exc->threshold - exc->phase + compensation ) /
2218  exc->period ) * exc->period;
2219  val += exc->phase;
2220  if ( val < 0 )
2221  val = exc->phase;
2222  }
2223  else
2224  {
2225  val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,
2226  distance ) /
2227  exc->period ) * exc->period );
2228  val -= exc->phase;
2229  if ( val > 0 )
2230  val = -exc->phase;
2231  }
2232 
2233  return val;
2234  }
2235 
2236 
2237  /*************************************************************************/
2238  /* */
2239  /* <Function> */
2240  /* Compute_Round */
2241  /* */
2242  /* <Description> */
2243  /* Sets the rounding mode. */
2244  /* */
2245  /* <Input> */
2246  /* round_mode :: The rounding mode to be used. */
2247  /* */
2248  static void
2249  Compute_Round( TT_ExecContext exc,
2250  FT_Byte round_mode )
2251  {
2252  switch ( round_mode )
2253  {
2254  case TT_Round_Off:
2255  exc->func_round = (TT_Round_Func)Round_None;
2256  break;
2257 
2258  case TT_Round_To_Grid:
2259  exc->func_round = (TT_Round_Func)Round_To_Grid;
2260  break;
2261 
2262  case TT_Round_Up_To_Grid:
2263  exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
2264  break;
2265 
2266  case TT_Round_Down_To_Grid:
2267  exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
2268  break;
2269 
2270  case TT_Round_To_Half_Grid:
2271  exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
2272  break;
2273 
2275  exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
2276  break;
2277 
2278  case TT_Round_Super:
2279  exc->func_round = (TT_Round_Func)Round_Super;
2280  break;
2281 
2282  case TT_Round_Super_45:
2283  exc->func_round = (TT_Round_Func)Round_Super_45;
2284  break;
2285  }
2286  }
2287 
2288 
2289  /*************************************************************************/
2290  /* */
2291  /* <Function> */
2292  /* SetSuperRound */
2293  /* */
2294  /* <Description> */
2295  /* Sets Super Round parameters. */
2296  /* */
2297  /* <Input> */
2298  /* GridPeriod :: The grid period. */
2299  /* */
2300  /* selector :: The SROUND opcode. */
2301  /* */
2302  static void
2303  SetSuperRound( TT_ExecContext exc,
2304  FT_F2Dot14 GridPeriod,
2305  FT_Long selector )
2306  {
2307  switch ( (FT_Int)( selector & 0xC0 ) )
2308  {
2309  case 0:
2310  exc->period = GridPeriod / 2;
2311  break;
2312 
2313  case 0x40:
2314  exc->period = GridPeriod;
2315  break;
2316 
2317  case 0x80:
2318  exc->period = GridPeriod * 2;
2319  break;
2320 
2321  /* This opcode is reserved, but... */
2322  case 0xC0:
2323  exc->period = GridPeriod;
2324  break;
2325  }
2326 
2327  switch ( (FT_Int)( selector & 0x30 ) )
2328  {
2329  case 0:
2330  exc->phase = 0;
2331  break;
2332 
2333  case 0x10:
2334  exc->phase = exc->period / 4;
2335  break;
2336 
2337  case 0x20:
2338  exc->phase = exc->period / 2;
2339  break;
2340 
2341  case 0x30:
2342  exc->phase = exc->period * 3 / 4;
2343  break;
2344  }
2345 
2346  if ( ( selector & 0x0F ) == 0 )
2347  exc->threshold = exc->period - 1;
2348  else
2349  exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;
2350 
2351  /* convert to F26Dot6 format */
2352  exc->period >>= 8;
2353  exc->phase >>= 8;
2354  exc->threshold >>= 8;
2355  }
2356 
2357 
2358  /*************************************************************************/
2359  /* */
2360  /* <Function> */
2361  /* Project */
2362  /* */
2363  /* <Description> */
2364  /* Computes the projection of vector given by (v2-v1) along the */
2365  /* current projection vector. */
2366  /* */
2367  /* <Input> */
2368  /* v1 :: First input vector. */
2369  /* v2 :: Second input vector. */
2370  /* */
2371  /* <Return> */
2372  /* The distance in F26dot6 format. */
2373  /* */
2374  static FT_F26Dot6
2375  Project( TT_ExecContext exc,
2376  FT_Pos dx,
2377  FT_Pos dy )
2378  {
2379  return TT_DotFix14( dx, dy,
2380  exc->GS.projVector.x,
2381  exc->GS.projVector.y );
2382  }
2383 
2384 
2385  /*************************************************************************/
2386  /* */
2387  /* <Function> */
2388  /* Dual_Project */
2389  /* */
2390  /* <Description> */
2391  /* Computes the projection of the vector given by (v2-v1) along the */
2392  /* current dual vector. */
2393  /* */
2394  /* <Input> */
2395  /* v1 :: First input vector. */
2396  /* v2 :: Second input vector. */
2397  /* */
2398  /* <Return> */
2399  /* The distance in F26dot6 format. */
2400  /* */
2401  static FT_F26Dot6
2402  Dual_Project( TT_ExecContext exc,
2403  FT_Pos dx,
2404  FT_Pos dy )
2405  {
2406  return TT_DotFix14( dx, dy,
2407  exc->GS.dualVector.x,
2408  exc->GS.dualVector.y );
2409  }
2410 
2411 
2412  /*************************************************************************/
2413  /* */
2414  /* <Function> */
2415  /* Project_x */
2416  /* */
2417  /* <Description> */
2418  /* Computes the projection of the vector given by (v2-v1) along the */
2419  /* horizontal axis. */
2420  /* */
2421  /* <Input> */
2422  /* v1 :: First input vector. */
2423  /* v2 :: Second input vector. */
2424  /* */
2425  /* <Return> */
2426  /* The distance in F26dot6 format. */
2427  /* */
2428  static FT_F26Dot6
2429  Project_x( TT_ExecContext exc,
2430  FT_Pos dx,
2431  FT_Pos dy )
2432  {
2433  FT_UNUSED( exc );
2434  FT_UNUSED( dy );
2435 
2436  return dx;
2437  }
2438 
2439 
2440  /*************************************************************************/
2441  /* */
2442  /* <Function> */
2443  /* Project_y */
2444  /* */
2445  /* <Description> */
2446  /* Computes the projection of the vector given by (v2-v1) along the */
2447  /* vertical axis. */
2448  /* */
2449  /* <Input> */
2450  /* v1 :: First input vector. */
2451  /* v2 :: Second input vector. */
2452  /* */
2453  /* <Return> */
2454  /* The distance in F26dot6 format. */
2455  /* */
2456  static FT_F26Dot6
2457  Project_y( TT_ExecContext exc,
2458  FT_Pos dx,
2459  FT_Pos dy )
2460  {
2461  FT_UNUSED( exc );
2462  FT_UNUSED( dx );
2463 
2464  return dy;
2465  }
2466 
2467 
2468  /*************************************************************************/
2469  /* */
2470  /* <Function> */
2471  /* Compute_Funcs */
2472  /* */
2473  /* <Description> */
2474  /* Computes the projection and movement function pointers according */
2475  /* to the current graphics state. */
2476  /* */
2477  static void
2478  Compute_Funcs( TT_ExecContext exc )
2479  {
2480  if ( exc->GS.freeVector.x == 0x4000 )
2481  exc->F_dot_P = exc->GS.projVector.x;
2482  else if ( exc->GS.freeVector.y == 0x4000 )
2483  exc->F_dot_P = exc->GS.projVector.y;
2484  else
2485  exc->F_dot_P =
2486  ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
2487  (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
2488 
2489  if ( exc->GS.projVector.x == 0x4000 )
2490  exc->func_project = (TT_Project_Func)Project_x;
2491  else if ( exc->GS.projVector.y == 0x4000 )
2492  exc->func_project = (TT_Project_Func)Project_y;
2493  else
2494  exc->func_project = (TT_Project_Func)Project;
2495 
2496  if ( exc->GS.dualVector.x == 0x4000 )
2497  exc->func_dualproj = (TT_Project_Func)Project_x;
2498  else if ( exc->GS.dualVector.y == 0x4000 )
2499  exc->func_dualproj = (TT_Project_Func)Project_y;
2500  else
2501  exc->func_dualproj = (TT_Project_Func)Dual_Project;
2502 
2503  exc->func_move = (TT_Move_Func)Direct_Move;
2504  exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2505 
2506  if ( exc->F_dot_P == 0x4000L )
2507  {
2508  if ( exc->GS.freeVector.x == 0x4000 )
2509  {
2510  exc->func_move = (TT_Move_Func)Direct_Move_X;
2511  exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2512  }
2513  else if ( exc->GS.freeVector.y == 0x4000 )
2514  {
2515  exc->func_move = (TT_Move_Func)Direct_Move_Y;
2516  exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2517  }
2518  }
2519 
2520  /* at small sizes, F_dot_P can become too small, resulting */
2521  /* in overflows and `spikes' in a number of glyphs like `w'. */
2522 
2523  if ( FT_ABS( exc->F_dot_P ) < 0x400L )
2524  exc->F_dot_P = 0x4000L;
2525 
2526  /* Disable cached aspect ratio */
2527  exc->tt_metrics.ratio = 0;
2528  }
2529 
2530 
2531  /*************************************************************************/
2532  /* */
2533  /* <Function> */
2534  /* Normalize */
2535  /* */
2536  /* <Description> */
2537  /* Norms a vector. */
2538  /* */
2539  /* <Input> */
2540  /* Vx :: The horizontal input vector coordinate. */
2541  /* Vy :: The vertical input vector coordinate. */
2542  /* */
2543  /* <Output> */
2544  /* R :: The normed unit vector. */
2545  /* */
2546  /* <Return> */
2547  /* Returns FAILURE if a vector parameter is zero. */
2548  /* */
2549  /* <Note> */
2550  /* In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and */
2551  /* R is undefined. */
2552  /* */
2553  static FT_Bool
2554  Normalize( FT_F26Dot6 Vx,
2555  FT_F26Dot6 Vy,
2556  FT_UnitVector* R )
2557  {
2558  FT_Vector V;
2559 
2560 
2561  if ( Vx == 0 && Vy == 0 )
2562  {
2563  /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2564  /* to normalize the vector (0,0). Return immediately. */
2565  return SUCCESS;
2566  }
2567 
2568  V.x = Vx;
2569  V.y = Vy;
2570 
2571  FT_Vector_NormLen( &V );
2572 
2573  R->x = (FT_F2Dot14)( V.x / 4 );
2574  R->y = (FT_F2Dot14)( V.y / 4 );
2575 
2576  return SUCCESS;
2577  }
2578 
2579 
2580  /*************************************************************************/
2581  /* */
2582  /* Here we start with the implementation of the various opcodes. */
2583  /* */
2584  /*************************************************************************/
2585 
2586 
2587 #define ARRAY_BOUND_ERROR \
2588  do \
2589  { \
2590  exc->error = FT_THROW( Invalid_Reference ); \
2591  return; \
2592  } while (0)
2593 
2594 
2595  /*************************************************************************/
2596  /* */
2597  /* MPPEM[]: Measure Pixel Per EM */
2598  /* Opcode range: 0x4B */
2599  /* Stack: --> Euint16 */
2600  /* */
2601  static void
2602  Ins_MPPEM( TT_ExecContext exc,
2603  FT_Long* args )
2604  {
2605  args[0] = exc->func_cur_ppem( exc );
2606  }
2607 
2608 
2609  /*************************************************************************/
2610  /* */
2611  /* MPS[]: Measure Point Size */
2612  /* Opcode range: 0x4C */
2613  /* Stack: --> Euint16 */
2614  /* */
2615  static void
2616  Ins_MPS( TT_ExecContext exc,
2617  FT_Long* args )
2618  {
2619  if ( NO_SUBPIXEL_HINTING )
2620  {
2621  /* Microsoft's GDI bytecode interpreter always returns value 12; */
2622  /* we return the current PPEM value instead. */
2623  args[0] = exc->func_cur_ppem( exc );
2624  }
2625  else
2626  {
2627  /* A possible practical application of the MPS instruction is to */
2628  /* implement optical scaling and similar features, which should be */
2629  /* based on perceptual attributes, thus independent of the */
2630  /* resolution. */
2631  args[0] = exc->pointSize;
2632  }
2633  }
2634 
2635 
2636  /*************************************************************************/
2637  /* */
2638  /* DUP[]: DUPlicate the stack's top element */
2639  /* Opcode range: 0x20 */
2640  /* Stack: StkElt --> StkElt StkElt */
2641  /* */
2642  static void
2643  Ins_DUP( FT_Long* args )
2644  {
2645  args[1] = args[0];
2646  }
2647 
2648 
2649  /*************************************************************************/
2650  /* */
2651  /* POP[]: POP the stack's top element */
2652  /* Opcode range: 0x21 */
2653  /* Stack: StkElt --> */
2654  /* */
2655  static void
2656  Ins_POP( void )
2657  {
2658  /* nothing to do */
2659  }
2660 
2661 
2662  /*************************************************************************/
2663  /* */
2664  /* CLEAR[]: CLEAR the entire stack */
2665  /* Opcode range: 0x22 */
2666  /* Stack: StkElt... --> */
2667  /* */
2668  static void
2669  Ins_CLEAR( TT_ExecContext exc )
2670  {
2671  exc->new_top = 0;
2672  }
2673 
2674 
2675  /*************************************************************************/
2676  /* */
2677  /* SWAP[]: SWAP the stack's top two elements */
2678  /* Opcode range: 0x23 */
2679  /* Stack: 2 * StkElt --> 2 * StkElt */
2680  /* */
2681  static void
2682  Ins_SWAP( FT_Long* args )
2683  {
2684  FT_Long L;
2685 
2686 
2687  L = args[0];
2688  args[0] = args[1];
2689  args[1] = L;
2690  }
2691 
2692 
2693  /*************************************************************************/
2694  /* */
2695  /* DEPTH[]: return the stack DEPTH */
2696  /* Opcode range: 0x24 */
2697  /* Stack: --> uint32 */
2698  /* */
2699  static void
2700  Ins_DEPTH( TT_ExecContext exc,
2701  FT_Long* args )
2702  {
2703  args[0] = exc->top;
2704  }
2705 
2706 
2707  /*************************************************************************/
2708  /* */
2709  /* LT[]: Less Than */
2710  /* Opcode range: 0x50 */
2711  /* Stack: int32? int32? --> bool */
2712  /* */
2713  static void
2714  Ins_LT( FT_Long* args )
2715  {
2716  args[0] = ( args[0] < args[1] );
2717  }
2718 
2719 
2720  /*************************************************************************/
2721  /* */
2722  /* LTEQ[]: Less Than or EQual */
2723  /* Opcode range: 0x51 */
2724  /* Stack: int32? int32? --> bool */
2725  /* */
2726  static void
2727  Ins_LTEQ( FT_Long* args )
2728  {
2729  args[0] = ( args[0] <= args[1] );
2730  }
2731 
2732 
2733  /*************************************************************************/
2734  /* */
2735  /* GT[]: Greater Than */
2736  /* Opcode range: 0x52 */
2737  /* Stack: int32? int32? --> bool */
2738  /* */
2739  static void
2740  Ins_GT( FT_Long* args )
2741  {
2742  args[0] = ( args[0] > args[1] );
2743  }
2744 
2745 
2746  /*************************************************************************/
2747  /* */
2748  /* GTEQ[]: Greater Than or EQual */
2749  /* Opcode range: 0x53 */
2750  /* Stack: int32? int32? --> bool */
2751  /* */
2752  static void
2753  Ins_GTEQ( FT_Long* args )
2754  {
2755  args[0] = ( args[0] >= args[1] );
2756  }
2757 
2758 
2759  /*************************************************************************/
2760  /* */
2761  /* EQ[]: EQual */
2762  /* Opcode range: 0x54 */
2763  /* Stack: StkElt StkElt --> bool */
2764  /* */
2765  static void
2766  Ins_EQ( FT_Long* args )
2767  {
2768  args[0] = ( args[0] == args[1] );
2769  }
2770 
2771 
2772  /*************************************************************************/
2773  /* */
2774  /* NEQ[]: Not EQual */
2775  /* Opcode range: 0x55 */
2776  /* Stack: StkElt StkElt --> bool */
2777  /* */
2778  static void
2779  Ins_NEQ( FT_Long* args )
2780  {
2781  args[0] = ( args[0] != args[1] );
2782  }
2783 
2784 
2785  /*************************************************************************/
2786  /* */
2787  /* ODD[]: Is ODD */
2788  /* Opcode range: 0x56 */
2789  /* Stack: f26.6 --> bool */
2790  /* */
2791  static void
2792  Ins_ODD( TT_ExecContext exc,
2793  FT_Long* args )
2794  {
2795  args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 );
2796  }
2797 
2798 
2799  /*************************************************************************/
2800  /* */
2801  /* EVEN[]: Is EVEN */
2802  /* Opcode range: 0x57 */
2803  /* Stack: f26.6 --> bool */
2804  /* */
2805  static void
2806  Ins_EVEN( TT_ExecContext exc,
2807  FT_Long* args )
2808  {
2809  args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 );
2810  }
2811 
2812 
2813  /*************************************************************************/
2814  /* */
2815  /* AND[]: logical AND */
2816  /* Opcode range: 0x5A */
2817  /* Stack: uint32 uint32 --> uint32 */
2818  /* */
2819  static void
2820  Ins_AND( FT_Long* args )
2821  {
2822  args[0] = ( args[0] && args[1] );
2823  }
2824 
2825 
2826  /*************************************************************************/
2827  /* */
2828  /* OR[]: logical OR */
2829  /* Opcode range: 0x5B */
2830  /* Stack: uint32 uint32 --> uint32 */
2831  /* */
2832  static void
2833  Ins_OR( FT_Long* args )
2834  {
2835  args[0] = ( args[0] || args[1] );
2836  }
2837 
2838 
2839  /*************************************************************************/
2840  /* */
2841  /* NOT[]: logical NOT */
2842  /* Opcode range: 0x5C */
2843  /* Stack: StkElt --> uint32 */
2844  /* */
2845  static void
2846  Ins_NOT( FT_Long* args )
2847  {
2848  args[0] = !args[0];
2849  }
2850 
2851 
2852  /*************************************************************************/
2853  /* */
2854  /* ADD[]: ADD */
2855  /* Opcode range: 0x60 */
2856  /* Stack: f26.6 f26.6 --> f26.6 */
2857  /* */
2858  static void
2859  Ins_ADD( FT_Long* args )
2860  {
2861  args[0] = ADD_LONG( args[0], args[1] );
2862  }
2863 
2864 
2865  /*************************************************************************/
2866  /* */
2867  /* SUB[]: SUBtract */
2868  /* Opcode range: 0x61 */
2869  /* Stack: f26.6 f26.6 --> f26.6 */
2870  /* */
2871  static void
2872  Ins_SUB( FT_Long* args )
2873  {
2874  args[0] = SUB_LONG( args[0], args[1] );
2875  }
2876 
2877 
2878  /*************************************************************************/
2879  /* */
2880  /* DIV[]: DIVide */
2881  /* Opcode range: 0x62 */
2882  /* Stack: f26.6 f26.6 --> f26.6 */
2883  /* */
2884  static void
2885  Ins_DIV( TT_ExecContext exc,
2886  FT_Long* args )
2887  {
2888  if ( args[1] == 0 )
2889  exc->error = FT_THROW( Divide_By_Zero );
2890  else
2891  args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
2892  }
2893 
2894 
2895  /*************************************************************************/
2896  /* */
2897  /* MUL[]: MULtiply */
2898  /* Opcode range: 0x63 */
2899  /* Stack: f26.6 f26.6 --> f26.6 */
2900  /* */
2901  static void
2902  Ins_MUL( FT_Long* args )
2903  {
2904  args[0] = FT_MulDiv( args[0], args[1], 64L );
2905  }
2906 
2907 
2908  /*************************************************************************/
2909  /* */
2910  /* ABS[]: ABSolute value */
2911  /* Opcode range: 0x64 */
2912  /* Stack: f26.6 --> f26.6 */
2913  /* */
2914  static void
2915  Ins_ABS( FT_Long* args )
2916  {
2917  if ( args[0] < 0 )
2918  args[0] = NEG_LONG( args[0] );
2919  }
2920 
2921 
2922  /*************************************************************************/
2923  /* */
2924  /* NEG[]: NEGate */
2925  /* Opcode range: 0x65 */
2926  /* Stack: f26.6 --> f26.6 */
2927  /* */
2928  static void
2929  Ins_NEG( FT_Long* args )
2930  {
2931  args[0] = NEG_LONG( args[0] );
2932  }
2933 
2934 
2935  /*************************************************************************/
2936  /* */
2937  /* FLOOR[]: FLOOR */
2938  /* Opcode range: 0x66 */
2939  /* Stack: f26.6 --> f26.6 */
2940  /* */
2941  static void
2942  Ins_FLOOR( FT_Long* args )
2943  {
2944  args[0] = FT_PIX_FLOOR( args[0] );
2945  }
2946 
2947 
2948  /*************************************************************************/
2949  /* */
2950  /* CEILING[]: CEILING */
2951  /* Opcode range: 0x67 */
2952  /* Stack: f26.6 --> f26.6 */
2953  /* */
2954  static void
2955  Ins_CEILING( FT_Long* args )
2956  {
2957  args[0] = FT_PIX_CEIL( args[0] );
2958  }
2959 
2960 
2961  /*************************************************************************/
2962  /* */
2963  /* RS[]: Read Store */
2964  /* Opcode range: 0x43 */
2965  /* Stack: uint32 --> uint32 */
2966  /* */
2967  static void
2968  Ins_RS( TT_ExecContext exc,
2969  FT_Long* args )
2970  {
2971  FT_ULong I = (FT_ULong)args[0];
2972 
2973 
2974  if ( BOUNDSL( I, exc->storeSize ) )
2975  {
2976  if ( exc->pedantic_hinting )
2977  ARRAY_BOUND_ERROR;
2978  else
2979  args[0] = 0;
2980  }
2981  else
2982  {
2983 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2984  /* subpixel hinting - avoid Typeman Dstroke and */
2985  /* IStroke and Vacuform rounds */
2986  if ( SUBPIXEL_HINTING_INFINALITY &&
2987  exc->ignore_x_mode &&
2988  ( ( I == 24 &&
2989  ( exc->face->sph_found_func_flags &
2990  ( SPH_FDEF_SPACING_1 |
2991  SPH_FDEF_SPACING_2 ) ) ) ||
2992  ( I == 22 &&
2993  ( exc->sph_in_func_flags &
2994  SPH_FDEF_TYPEMAN_STROKES ) ) ||
2995  ( I == 8 &&
2996  ( exc->face->sph_found_func_flags &
2997  SPH_FDEF_VACUFORM_ROUND_1 ) &&
2998  exc->iup_called ) ) )
2999  args[0] = 0;
3000  else
3001 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3002  args[0] = exc->storage[I];
3003  }
3004  }
3005 
3006 
3007  /*************************************************************************/
3008  /* */
3009  /* WS[]: Write Store */
3010  /* Opcode range: 0x42 */
3011  /* Stack: uint32 uint32 --> */
3012  /* */
3013  static void
3014  Ins_WS( TT_ExecContext exc,
3015  FT_Long* args )
3016  {
3017  FT_ULong I = (FT_ULong)args[0];
3018 
3019 
3020  if ( BOUNDSL( I, exc->storeSize ) )
3021  {
3022  if ( exc->pedantic_hinting )
3023  ARRAY_BOUND_ERROR;
3024  }
3025  else
3026  exc->storage[I] = args[1];
3027  }
3028 
3029 
3030  /*************************************************************************/
3031  /* */
3032  /* WCVTP[]: Write CVT in Pixel units */
3033  /* Opcode range: 0x44 */
3034  /* Stack: f26.6 uint32 --> */
3035  /* */
3036  static void
3037  Ins_WCVTP( TT_ExecContext exc,
3038  FT_Long* args )
3039  {
3040  FT_ULong I = (FT_ULong)args[0];
3041 
3042 
3043  if ( BOUNDSL( I, exc->cvtSize ) )
3044  {
3045  if ( exc->pedantic_hinting )
3046  ARRAY_BOUND_ERROR;
3047  }
3048  else
3049  exc->func_write_cvt( exc, I, args[1] );
3050  }
3051 
3052 
3053  /*************************************************************************/
3054  /* */
3055  /* WCVTF[]: Write CVT in Funits */
3056  /* Opcode range: 0x70 */
3057  /* Stack: uint32 uint32 --> */
3058  /* */
3059  static void
3060  Ins_WCVTF( TT_ExecContext exc,
3061  FT_Long* args )
3062  {
3063  FT_ULong I = (FT_ULong)args[0];
3064 
3065 
3066  if ( BOUNDSL( I, exc->cvtSize ) )
3067  {
3068  if ( exc->pedantic_hinting )
3069  ARRAY_BOUND_ERROR;
3070  }
3071  else
3072  exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );
3073  }
3074 
3075 
3076  /*************************************************************************/
3077  /* */
3078  /* RCVT[]: Read CVT */
3079  /* Opcode range: 0x45 */
3080  /* Stack: uint32 --> f26.6 */
3081  /* */
3082  static void
3083  Ins_RCVT( TT_ExecContext exc,
3084  FT_Long* args )
3085  {
3086  FT_ULong I = (FT_ULong)args[0];
3087 
3088 
3089  if ( BOUNDSL( I, exc->cvtSize ) )
3090  {
3091  if ( exc->pedantic_hinting )
3092  ARRAY_BOUND_ERROR;
3093  else
3094  args[0] = 0;
3095  }
3096  else
3097  args[0] = exc->func_read_cvt( exc, I );
3098  }
3099 
3100 
3101  /*************************************************************************/
3102  /* */
3103  /* AA[]: Adjust Angle */
3104  /* Opcode range: 0x7F */
3105  /* Stack: uint32 --> */
3106  /* */
3107  static void
3108  Ins_AA( void )
3109  {
3110  /* intentionally no longer supported */
3111  }
3112 
3113 
3114  /*************************************************************************/
3115  /* */
3116  /* DEBUG[]: DEBUG. Unsupported. */
3117  /* Opcode range: 0x4F */
3118  /* Stack: uint32 --> */
3119  /* */
3120  /* Note: The original instruction pops a value from the stack. */
3121  /* */
3122  static void
3123  Ins_DEBUG( TT_ExecContext exc )
3124  {
3125  exc->error = FT_THROW( Debug_OpCode );
3126  }
3127 
3128 
3129  /*************************************************************************/
3130  /* */
3131  /* ROUND[ab]: ROUND value */
3132  /* Opcode range: 0x68-0x6B */
3133  /* Stack: f26.6 --> f26.6 */
3134  /* */
3135  static void
3136  Ins_ROUND( TT_ExecContext exc,
3137  FT_Long* args )
3138  {
3139  args[0] = exc->func_round(
3140  exc,
3141  args[0],
3142  exc->tt_metrics.compensations[exc->opcode - 0x68] );
3143  }
3144 
3145 
3146  /*************************************************************************/
3147  /* */
3148  /* NROUND[ab]: No ROUNDing of value */
3149  /* Opcode range: 0x6C-0x6F */
3150  /* Stack: f26.6 --> f26.6 */
3151  /* */
3152  static void
3153  Ins_NROUND( TT_ExecContext exc,
3154  FT_Long* args )
3155  {
3156  args[0] = Round_None(
3157  exc,
3158  args[0],
3159  exc->tt_metrics.compensations[exc->opcode - 0x6C] );
3160  }
3161 
3162 
3163  /*************************************************************************/
3164  /* */
3165  /* MAX[]: MAXimum */
3166  /* Opcode range: 0x8B */
3167  /* Stack: int32? int32? --> int32 */
3168  /* */
3169  static void
3170  Ins_MAX( FT_Long* args )
3171  {
3172  if ( args[1] > args[0] )
3173  args[0] = args[1];
3174  }
3175 
3176 
3177  /*************************************************************************/
3178  /* */
3179  /* MIN[]: MINimum */
3180  /* Opcode range: 0x8C */
3181  /* Stack: int32? int32? --> int32 */
3182  /* */
3183  static void
3184  Ins_MIN( FT_Long* args )
3185  {
3186  if ( args[1] < args[0] )
3187  args[0] = args[1];
3188  }
3189 
3190 
3191  /*************************************************************************/
3192  /* */
3193  /* MINDEX[]: Move INDEXed element */
3194  /* Opcode range: 0x26 */
3195  /* Stack: int32? --> StkElt */
3196  /* */
3197  static void
3198  Ins_MINDEX( TT_ExecContext exc,
3199  FT_Long* args )
3200  {
3201  FT_Long L, K;
3202 
3203 
3204  L = args[0];
3205 
3206  if ( L <= 0 || L > exc->args )
3207  {
3208  if ( exc->pedantic_hinting )
3209  exc->error = FT_THROW( Invalid_Reference );
3210  }
3211  else
3212  {
3213  K = exc->stack[exc->args - L];
3214 
3215  FT_ARRAY_MOVE( &exc->stack[exc->args - L ],
3216  &exc->stack[exc->args - L + 1],
3217  ( L - 1 ) );
3218 
3219  exc->stack[exc->args - 1] = K;
3220  }
3221  }
3222 
3223 
3224  /*************************************************************************/
3225  /* */
3226  /* CINDEX[]: Copy INDEXed element */
3227  /* Opcode range: 0x25 */
3228  /* Stack: int32 --> StkElt */
3229  /* */
3230  static void
3231  Ins_CINDEX( TT_ExecContext exc,
3232  FT_Long* args )
3233  {
3234  FT_Long L;
3235 
3236 
3237  L = args[0];
3238 
3239  if ( L <= 0 || L > exc->args )
3240  {
3241  if ( exc->pedantic_hinting )
3242  exc->error = FT_THROW( Invalid_Reference );
3243  args[0] = 0;
3244  }
3245  else
3246  args[0] = exc->stack[exc->args - L];
3247  }
3248 
3249 
3250  /*************************************************************************/
3251  /* */
3252  /* ROLL[]: ROLL top three elements */
3253  /* Opcode range: 0x8A */
3254  /* Stack: 3 * StkElt --> 3 * StkElt */
3255  /* */
3256  static void
3257  Ins_ROLL( FT_Long* args )
3258  {
3259  FT_Long A, B, C;
3260 
3261 
3262  A = args[2];
3263  B = args[1];
3264  C = args[0];
3265 
3266  args[2] = C;
3267  args[1] = A;
3268  args[0] = B;
3269  }
3270 
3271 
3272  /*************************************************************************/
3273  /* */
3274  /* MANAGING THE FLOW OF CONTROL */
3275  /* */
3276  /*************************************************************************/
3277 
3278 
3279  /*************************************************************************/
3280  /* */
3281  /* SLOOP[]: Set LOOP variable */
3282  /* Opcode range: 0x17 */
3283  /* Stack: int32? --> */
3284  /* */
3285  static void
3286  Ins_SLOOP( TT_ExecContext exc,
3287  FT_Long* args )
3288  {
3289  if ( args[0] < 0 )
3290  exc->error = FT_THROW( Bad_Argument );
3291  else
3292  exc->GS.loop = args[0];
3293  }
3294 
3295 
3296  static FT_Bool
3297  SkipCode( TT_ExecContext exc )
3298  {
3299  exc->IP += exc->length;
3300 
3301  if ( exc->IP < exc->codeSize )
3302  {
3303  exc->opcode = exc->code[exc->IP];
3304 
3305  exc->length = opcode_length[exc->opcode];
3306  if ( exc->length < 0 )
3307  {
3308  if ( exc->IP + 1 >= exc->codeSize )
3309  goto Fail_Overflow;
3310  exc->length = 2 - exc->length * exc->code[exc->IP + 1];
3311  }
3312 
3313  if ( exc->IP + exc->length <= exc->codeSize )
3314  return SUCCESS;
3315  }
3316 
3317  Fail_Overflow:
3318  exc->error = FT_THROW( Code_Overflow );
3319  return FAILURE;
3320  }
3321 
3322 
3323  /*************************************************************************/
3324  /* */
3325  /* IF[]: IF test */
3326  /* Opcode range: 0x58 */
3327  /* Stack: StkElt --> */
3328  /* */
3329  static void
3330  Ins_IF( TT_ExecContext exc,
3331  FT_Long* args )
3332  {
3333  FT_Int nIfs;
3334  FT_Bool Out;
3335 
3336 
3337  if ( args[0] != 0 )
3338  return;
3339 
3340  nIfs = 1;
3341  Out = 0;
3342 
3343  do
3344  {
3345  if ( SkipCode( exc ) == FAILURE )
3346  return;
3347 
3348  switch ( exc->opcode )
3349  {
3350  case 0x58: /* IF */
3351  nIfs++;
3352  break;
3353 
3354  case 0x1B: /* ELSE */
3355  Out = FT_BOOL( nIfs == 1 );
3356  break;
3357 
3358  case 0x59: /* EIF */
3359  nIfs--;
3360  Out = FT_BOOL( nIfs == 0 );
3361  break;
3362  }
3363  } while ( Out == 0 );
3364  }
3365 
3366 
3367  /*************************************************************************/
3368  /* */
3369  /* ELSE[]: ELSE */
3370  /* Opcode range: 0x1B */
3371  /* Stack: --> */
3372  /* */
3373  static void
3374  Ins_ELSE( TT_ExecContext exc )
3375  {
3376  FT_Int nIfs;
3377 
3378 
3379  nIfs = 1;
3380 
3381  do
3382  {
3383  if ( SkipCode( exc ) == FAILURE )
3384  return;
3385 
3386  switch ( exc->opcode )
3387  {
3388  case 0x58: /* IF */
3389  nIfs++;
3390  break;
3391 
3392  case 0x59: /* EIF */
3393  nIfs--;
3394  break;
3395  }
3396  } while ( nIfs != 0 );
3397  }
3398 
3399 
3400  /*************************************************************************/
3401  /* */
3402  /* EIF[]: End IF */
3403  /* Opcode range: 0x59 */
3404  /* Stack: --> */
3405  /* */
3406  static void
3407  Ins_EIF( void )
3408  {
3409  /* nothing to do */
3410  }
3411 
3412 
3413  /*************************************************************************/
3414  /* */
3415  /* JMPR[]: JuMP Relative */
3416  /* Opcode range: 0x1C */
3417  /* Stack: int32 --> */
3418  /* */
3419  static void
3420  Ins_JMPR( TT_ExecContext exc,
3421  FT_Long* args )
3422  {
3423  if ( args[0] == 0 && exc->args == 0 )
3424  {
3425  exc->error = FT_THROW( Bad_Argument );
3426  return;
3427  }
3428 
3429  exc->IP += args[0];
3430  if ( exc->IP < 0 ||
3431  ( exc->callTop > 0 &&
3432  exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
3433  {
3434  exc->error = FT_THROW( Bad_Argument );
3435  return;
3436  }
3437 
3438  exc->step_ins = FALSE;
3439 
3440  if ( args[0] < 0 )
3441  {
3442  if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
3443  exc->error = FT_THROW( Execution_Too_Long );
3444  }
3445  }
3446 
3447 
3448  /*************************************************************************/
3449  /* */
3450  /* JROT[]: Jump Relative On True */
3451  /* Opcode range: 0x78 */
3452  /* Stack: StkElt int32 --> */
3453  /* */
3454  static void
3455  Ins_JROT( TT_ExecContext exc,
3456  FT_Long* args )
3457  {
3458  if ( args[1] != 0 )
3459  Ins_JMPR( exc, args );
3460  }
3461 
3462 
3463  /*************************************************************************/
3464  /* */
3465  /* JROF[]: Jump Relative On False */
3466  /* Opcode range: 0x79 */
3467  /* Stack: StkElt int32 --> */
3468  /* */
3469  static void
3470  Ins_JROF( TT_ExecContext exc,
3471  FT_Long* args )
3472  {
3473  if ( args[1] == 0 )
3474  Ins_JMPR( exc, args );
3475  }
3476 
3477 
3478  /*************************************************************************/
3479  /* */
3480  /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
3481  /* */
3482  /*************************************************************************/
3483 
3484 
3485  /*************************************************************************/
3486  /* */
3487  /* FDEF[]: Function DEFinition */
3488  /* Opcode range: 0x2C */
3489  /* Stack: uint32 --> */
3490  /* */
3491  static void
3492  Ins_FDEF( TT_ExecContext exc,
3493  FT_Long* args )
3494  {
3495  FT_ULong n;
3496  TT_DefRecord* rec;
3498 
3499 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3500  /* arguments to opcodes are skipped by `SKIP_Code' */
3501  FT_Byte opcode_pattern[9][12] = {
3502  /* #0 inline delta function 1 */
3503  {
3504  0x4B, /* PPEM */
3505  0x53, /* GTEQ */
3506  0x23, /* SWAP */
3507  0x4B, /* PPEM */
3508  0x51, /* LTEQ */
3509  0x5A, /* AND */
3510  0x58, /* IF */
3511  0x38, /* SHPIX */
3512  0x1B, /* ELSE */
3513  0x21, /* POP */
3514  0x21, /* POP */
3515  0x59 /* EIF */
3516  },
3517  /* #1 inline delta function 2 */
3518  {
3519  0x4B, /* PPEM */
3520  0x54, /* EQ */
3521  0x58, /* IF */
3522  0x38, /* SHPIX */
3523  0x1B, /* ELSE */
3524  0x21, /* POP */
3525  0x21, /* POP */
3526  0x59 /* EIF */
3527  },
3528  /* #2 diagonal stroke function */
3529  {
3530  0x20, /* DUP */
3531  0x20, /* DUP */
3532  0xB0, /* PUSHB_1 */
3533  /* 1 */
3534  0x60, /* ADD */
3535  0x46, /* GC_cur */
3536  0xB0, /* PUSHB_1 */
3537  /* 64 */
3538  0x23, /* SWAP */
3539  0x42 /* WS */
3540  },
3541  /* #3 VacuFormRound function */
3542  {
3543  0x45, /* RCVT */
3544  0x23, /* SWAP */
3545  0x46, /* GC_cur */
3546  0x60, /* ADD */
3547  0x20, /* DUP */
3548  0xB0 /* PUSHB_1 */
3549  /* 38 */
3550  },
3551  /* #4 TTFautohint bytecode (old) */
3552  {
3553  0x20, /* DUP */
3554  0x64, /* ABS */
3555  0xB0, /* PUSHB_1 */
3556  /* 32 */
3557  0x60, /* ADD */
3558  0x66, /* FLOOR */
3559  0x23, /* SWAP */
3560  0xB0 /* PUSHB_1 */
3561  },
3562  /* #5 spacing function 1 */
3563  {
3564  0x01, /* SVTCA_x */
3565  0xB0, /* PUSHB_1 */
3566  /* 24 */
3567  0x43, /* RS */
3568  0x58 /* IF */
3569  },
3570  /* #6 spacing function 2 */
3571  {
3572  0x01, /* SVTCA_x */
3573  0x18, /* RTG */
3574  0xB0, /* PUSHB_1 */
3575  /* 24 */
3576  0x43, /* RS */
3577  0x58 /* IF */
3578  },
3579  /* #7 TypeMan Talk DiagEndCtrl function */
3580  {
3581  0x01, /* SVTCA_x */
3582  0x20, /* DUP */
3583  0xB0, /* PUSHB_1 */
3584  /* 3 */
3585  0x25, /* CINDEX */
3586  },
3587  /* #8 TypeMan Talk Align */
3588  {
3589  0x06, /* SPVTL */
3590  0x7D, /* RDTG */
3591  },
3592  };
3593  FT_UShort opcode_patterns = 9;
3594  FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
3595  FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
3596  FT_UShort i;
3597 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3598 
3599 
3600  /* FDEF is only allowed in `prep' or `fpgm' */
3601  if ( exc->curRange == tt_coderange_glyph )
3602  {
3603  exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
3604  return;
3605  }
3606 
3607  /* some font programs are broken enough to redefine functions! */
3608  /* We will then parse the current table. */
3609 
3610  rec = exc->FDefs;
3611  limit = rec + exc->numFDefs;
3612  n = (FT_ULong)args[0];
3613 
3614  for ( ; rec < limit; rec++ )
3615  {
3616  if ( rec->opc == n )
3617  break;
3618  }
3619 
3620  if ( rec == limit )
3621  {
3622  /* check that there is enough room for new functions */
3623  if ( exc->numFDefs >= exc->maxFDefs )
3624  {
3625  exc->error = FT_THROW( Too_Many_Function_Defs );
3626  return;
3627  }
3628  exc->numFDefs++;
3629  }
3630 
3631  /* Although FDEF takes unsigned 32-bit integer, */
3632  /* func # must be within unsigned 16-bit integer */
3633  if ( n > 0xFFFFU )
3634  {
3635  exc->error = FT_THROW( Too_Many_Function_Defs );
3636  return;
3637  }
3638 
3639  rec->range = exc->curRange;
3640  rec->opc = (FT_UInt16)n;
3641  rec->start = exc->IP + 1;
3642  rec->active = TRUE;
3643  rec->inline_delta = FALSE;
3644  rec->sph_fdef_flags = 0x0000;
3645 
3646  if ( n > exc->maxFunc )
3647  exc->maxFunc = (FT_UInt16)n;
3648 
3649 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3650  /* We don't know for sure these are typeman functions, */
3651  /* however they are only active when RS 22 is called */
3652  if ( n >= 64 && n <= 66 )
3653  rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
3654 #endif
3655 
3656  /* Now skip the whole function definition. */
3657  /* We don't allow nested IDEFS & FDEFs. */
3658 
3659  while ( SkipCode( exc ) == SUCCESS )
3660  {
3661 
3662 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3663 
3664  if ( SUBPIXEL_HINTING_INFINALITY )
3665  {
3666  for ( i = 0; i < opcode_patterns; i++ )
3667  {
3668  if ( opcode_pointer[i] < opcode_size[i] &&
3669  exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
3670  {
3671  opcode_pointer[i] += 1;
3672 
3673  if ( opcode_pointer[i] == opcode_size[i] )
3674  {
3675  FT_TRACE6(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
3676  i, n,
3677  exc->face->root.family_name,
3678  exc->face->root.style_name ));
3679 
3680  switch ( i )
3681  {
3682  case 0:
3683  rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1;
3684  exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
3685  break;
3686 
3687  case 1:
3688  rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2;
3689  exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
3690  break;
3691 
3692  case 2:
3693  switch ( n )
3694  {
3695  /* needs to be implemented still */
3696  case 58:
3697  rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE;
3698  exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
3699  }
3700  break;
3701 
3702  case 3:
3703  switch ( n )
3704  {
3705  case 0:
3706  rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1;
3707  exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
3708  }
3709  break;
3710 
3711  case 4:
3712  /* probably not necessary to detect anymore */
3713  rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1;
3714  exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
3715  break;
3716 
3717  case 5:
3718  switch ( n )
3719  {
3720  case 0:
3721  case 1:
3722  case 2:
3723  case 4:
3724  case 7:
3725  case 8:
3726  rec->sph_fdef_flags |= SPH_FDEF_SPACING_1;
3727  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
3728  }
3729  break;
3730 
3731  case 6:
3732  switch ( n )
3733  {
3734  case 0:
3735  case 1:
3736  case 2:
3737  case 4:
3738  case 7:
3739  case 8:
3740  rec->sph_fdef_flags |= SPH_FDEF_SPACING_2;
3741  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
3742  }
3743  break;
3744 
3745  case 7:
3746  rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
3747  exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
3748  break;
3749 
3750  case 8:
3751 #if 0
3752  rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
3753  exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
3754 #endif
3755  break;
3756  }
3757  opcode_pointer[i] = 0;
3758  }
3759  }
3760 
3761  else
3762  opcode_pointer[i] = 0;
3763  }
3764 
3765  /* Set sph_compatibility_mode only when deltas are detected */
3766  exc->face->sph_compatibility_mode =
3767  ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
3768  ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
3769  }
3770 
3771 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3772 
3773  switch ( exc->opcode )
3774  {
3775  case 0x89: /* IDEF */
3776  case 0x2C: /* FDEF */
3777  exc->error = FT_THROW( Nested_DEFS );
3778  return;
3779 
3780  case 0x2D: /* ENDF */
3781  rec->end = exc->IP;
3782  return;
3783  }
3784  }
3785  }
3786 
3787 
3788  /*************************************************************************/
3789  /* */
3790  /* ENDF[]: END Function definition */
3791  /* Opcode range: 0x2D */
3792  /* Stack: --> */
3793  /* */
3794  static void
3795  Ins_ENDF( TT_ExecContext exc )
3796  {
3797  TT_CallRec* pRec;
3798 
3799 
3800 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3801  exc->sph_in_func_flags = 0x0000;
3802 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3803 
3804  if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */
3805  {
3806  exc->error = FT_THROW( ENDF_In_Exec_Stream );
3807  return;
3808  }
3809 
3810  exc->callTop--;
3811 
3812  pRec = &exc->callStack[exc->callTop];
3813 
3814  pRec->Cur_Count--;
3815 
3816  exc->step_ins = FALSE;
3817 
3818  if ( pRec->Cur_Count > 0 )
3819  {
3820  exc->callTop++;
3821  exc->IP = pRec->Def->start;
3822  }
3823  else
3824  /* Loop through the current function */
3825  Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );
3826 
3827  /* Exit the current call frame. */
3828 
3829  /* NOTE: If the last instruction of a program is a */
3830  /* CALL or LOOPCALL, the return address is */
3831  /* always out of the code range. This is a */
3832  /* valid address, and it is why we do not test */
3833  /* the result of Ins_Goto_CodeRange() here! */
3834  }
3835 
3836 
3837  /*************************************************************************/
3838  /* */
3839  /* CALL[]: CALL function */
3840  /* Opcode range: 0x2B */
3841  /* Stack: uint32? --> */
3842  /* */
3843  static void
3844  Ins_CALL( TT_ExecContext exc,
3845  FT_Long* args )
3846  {
3847  FT_ULong F;
3848  TT_CallRec* pCrec;
3849  TT_DefRecord* def;
3850 
3851 
3852  /* first of all, check the index */
3853 
3854  F = (FT_ULong)args[0];
3855  if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3856  goto Fail;
3857 
3858  /* Except for some old Apple fonts, all functions in a TrueType */
3859  /* font are defined in increasing order, starting from 0. This */
3860  /* means that we normally have */
3861  /* */
3862  /* exc->maxFunc+1 == exc->numFDefs */
3863  /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */
3864  /* */
3865  /* If this isn't true, we need to look up the function table. */
3866 
3867  def = exc->FDefs + F;
3868  if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )
3869  {
3870  /* look up the FDefs table */
3872 
3873 
3874  def = exc->FDefs;
3875  limit = def + exc->numFDefs;
3876 
3877  while ( def < limit && def->opc != F )
3878  def++;
3879 
3880  if ( def == limit )
3881  goto Fail;
3882  }
3883 
3884  /* check that the function is active */
3885  if ( !def->active )
3886  goto Fail;
3887 
3888 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3889  if ( SUBPIXEL_HINTING_INFINALITY &&
3890  exc->ignore_x_mode &&
3891  ( ( exc->iup_called &&
3892  ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
3893  ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) )
3894  goto Fail;
3895  else
3896  exc->sph_in_func_flags = def->sph_fdef_flags;
3897 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3898 
3899  /* check the call stack */
3900  if ( exc->callTop >= exc->callSize )
3901  {
3902  exc->error = FT_THROW( Stack_Overflow );
3903  return;
3904  }
3905 
3906  pCrec = exc->callStack + exc->callTop;
3907 
3908  pCrec->Caller_Range = exc->curRange;
3909  pCrec->Caller_IP = exc->IP + 1;
3910  pCrec->Cur_Count = 1;
3911  pCrec->Def = def;
3912 
3913  exc->callTop++;
3914 
3915  Ins_Goto_CodeRange( exc, def->range, def->start );
3916 
3917  exc->step_ins = FALSE;
3918 
3919  return;
3920 
3921  Fail:
3922  exc->error = FT_THROW( Invalid_Reference );
3923  }
3924 
3925 
3926  /*************************************************************************/
3927  /* */
3928  /* LOOPCALL[]: LOOP and CALL function */
3929  /* Opcode range: 0x2A */
3930  /* Stack: uint32? Eint16? --> */
3931  /* */
3932  static void
3933  Ins_LOOPCALL( TT_ExecContext exc,
3934  FT_Long* args )
3935  {
3936  FT_ULong F;
3937  TT_CallRec* pCrec;
3938  TT_DefRecord* def;
3939 
3940 
3941  /* first of all, check the index */
3942  F = (FT_ULong)args[1];
3943  if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3944  goto Fail;
3945 
3946  /* Except for some old Apple fonts, all functions in a TrueType */
3947  /* font are defined in increasing order, starting from 0. This */
3948  /* means that we normally have */
3949  /* */
3950  /* exc->maxFunc+1 == exc->numFDefs */
3951  /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */
3952  /* */
3953  /* If this isn't true, we need to look up the function table. */
3954 
3955  def = exc->FDefs + F;
3956  if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )
3957  {
3958  /* look up the FDefs table */
3960 
3961 
3962  def = exc->FDefs;
3963  limit = def + exc->numFDefs;
3964 
3965  while ( def < limit && def->opc != F )
3966  def++;
3967 
3968  if ( def == limit )
3969  goto Fail;
3970  }
3971 
3972  /* check that the function is active */
3973  if ( !def->active )
3974  goto Fail;
3975 
3976 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3977  if ( SUBPIXEL_HINTING_INFINALITY &&
3978  exc->ignore_x_mode &&
3979  ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
3980  goto Fail;
3981  else
3982  exc->sph_in_func_flags = def->sph_fdef_flags;
3983 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3984 
3985  /* check stack */
3986  if ( exc->callTop >= exc->callSize )
3987  {
3988  exc->error = FT_THROW( Stack_Overflow );
3989  return;
3990  }
3991 
3992  if ( args[0] > 0 )
3993  {
3994  pCrec = exc->callStack + exc->callTop;
3995 
3996  pCrec->Caller_Range = exc->curRange;
3997  pCrec->Caller_IP = exc->IP + 1;
3998  pCrec->Cur_Count = (FT_Int)args[0];
3999  pCrec->Def = def;
4000 
4001  exc->callTop++;
4002 
4003  Ins_Goto_CodeRange( exc, def->range, def->start );
4004 
4005  exc->step_ins = FALSE;
4006 
4007  exc->loopcall_counter += (FT_ULong)args[0];
4008  if ( exc->loopcall_counter > exc->loopcall_counter_max )
4009  exc->error = FT_THROW( Execution_Too_Long );
4010  }
4011 
4012  return;
4013 
4014  Fail:
4015  exc->error = FT_THROW( Invalid_Reference );
4016  }
4017 
4018 
4019  /*************************************************************************/
4020  /* */
4021  /* IDEF[]: Instruction DEFinition */
4022  /* Opcode range: 0x89 */
4023  /* Stack: Eint8 --> */
4024  /* */
4025  static void
4026  Ins_IDEF( TT_ExecContext exc,
4027  FT_Long* args )
4028  {
4029  TT_DefRecord* def;
4031 
4032 
4033  /* we enable IDEF only in `prep' or `fpgm' */
4034  if ( exc->curRange == tt_coderange_glyph )
4035  {
4036  exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
4037  return;
4038  }
4039 
4040  /* First of all, look for the same function in our table */
4041 
4042  def = exc->IDefs;
4043  limit = def + exc->numIDefs;
4044 
4045  for ( ; def < limit; def++ )
4046  if ( def->opc == (FT_ULong)args[0] )
4047  break;
4048 
4049  if ( def == limit )
4050  {
4051  /* check that there is enough room for a new instruction */
4052  if ( exc->numIDefs >= exc->maxIDefs )
4053  {
4054  exc->error = FT_THROW( Too_Many_Instruction_Defs );
4055  return;
4056  }
4057  exc->numIDefs++;
4058  }
4059 
4060  /* opcode must be unsigned 8-bit integer */
4061  if ( 0 > args[0] || args[0] > 0x00FF )
4062  {
4063  exc->error = FT_THROW( Too_Many_Instruction_Defs );
4064  return;
4065  }
4066 
4067  def->opc = (FT_Byte)args[0];
4068  def->start = exc->IP + 1;
4069  def->range = exc->curRange;
4070  def->active = TRUE;
4071 
4072  if ( (FT_ULong)args[0] > exc->maxIns )
4073  exc->maxIns = (FT_Byte)args[0];
4074 
4075  /* Now skip the whole function definition. */
4076  /* We don't allow nested IDEFs & FDEFs. */
4077 
4078  while ( SkipCode( exc ) == SUCCESS )
4079  {
4080  switch ( exc->opcode )
4081  {
4082  case 0x89: /* IDEF */
4083  case 0x2C: /* FDEF */
4084  exc->error = FT_THROW( Nested_DEFS );
4085  return;
4086  case 0x2D: /* ENDF */
4087  def->end = exc->IP;
4088  return;
4089  }
4090  }
4091  }
4092 
4093 
4094  /*************************************************************************/
4095  /* */
4096  /* PUSHING DATA ONTO THE INTERPRETER STACK */
4097  /* */
4098  /*************************************************************************/
4099 
4100 
4101  /*************************************************************************/
4102  /* */
4103  /* NPUSHB[]: PUSH N Bytes */
4104  /* Opcode range: 0x40 */
4105  /* Stack: --> uint32... */
4106  /* */
4107  static void
4108  Ins_NPUSHB( TT_ExecContext exc,
4109  FT_Long* args )
4110  {
4111  FT_UShort L, K;
4112 
4113 
4114  L = (FT_UShort)exc->code[exc->IP + 1];
4115 
4116  if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4117  {
4118  exc->error = FT_THROW( Stack_Overflow );
4119  return;
4120  }
4121 
4122  for ( K = 1; K <= L; K++ )
4123  args[K - 1] = exc->code[exc->IP + K + 1];
4124 
4125  exc->new_top += L;
4126  }
4127 
4128 
4129  /*************************************************************************/
4130  /* */
4131  /* NPUSHW[]: PUSH N Words */
4132  /* Opcode range: 0x41 */
4133  /* Stack: --> int32... */
4134  /* */
4135  static void
4136  Ins_NPUSHW( TT_ExecContext exc,
4137  FT_Long* args )
4138  {
4139  FT_UShort L, K;
4140 
4141 
4142  L = (FT_UShort)exc->code[exc->IP + 1];
4143 
4144  if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4145  {
4146  exc->error = FT_THROW( Stack_Overflow );
4147  return;
4148  }
4149 
4150  exc->IP += 2;
4151 
4152  for ( K = 0; K < L; K++ )
4153  args[K] = GetShortIns( exc );
4154 
4155  exc->step_ins = FALSE;
4156  exc->new_top += L;
4157  }
4158 
4159 
4160  /*************************************************************************/
4161  /* */
4162  /* PUSHB[abc]: PUSH Bytes */
4163  /* Opcode range: 0xB0-0xB7 */
4164  /* Stack: --> uint32... */
4165  /* */
4166  static void
4167  Ins_PUSHB( TT_ExecContext exc,
4168  FT_Long* args )
4169  {
4170  FT_UShort L, K;
4171 
4172 
4173  L = (FT_UShort)( exc->opcode - 0xB0 + 1 );
4174 
4175  if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4176  {
4177  exc->error = FT_THROW( Stack_Overflow );
4178  return;
4179  }
4180 
4181  for ( K = 1; K <= L; K++ )
4182  args[K - 1] = exc->code[exc->IP + K];
4183  }
4184 
4185 
4186  /*************************************************************************/
4187  /* */
4188  /* PUSHW[abc]: PUSH Words */
4189  /* Opcode range: 0xB8-0xBF */
4190  /* Stack: --> int32... */
4191  /* */
4192  static void
4193  Ins_PUSHW( TT_ExecContext exc,
4194  FT_Long* args )
4195  {
4196  FT_UShort L, K;
4197 
4198 
4199  L = (FT_UShort)( exc->opcode - 0xB8 + 1 );
4200 
4201  if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4202  {
4203  exc->error = FT_THROW( Stack_Overflow );
4204  return;
4205  }
4206 
4207  exc->IP++;
4208 
4209  for ( K = 0; K < L; K++ )
4210  args[K] = GetShortIns( exc );
4211 
4212  exc->step_ins = FALSE;
4213  }
4214 
4215 
4216  /*************************************************************************/
4217  /* */
4218  /* MANAGING THE GRAPHICS STATE */
4219  /* */
4220  /*************************************************************************/
4221 
4222 
4223  static FT_Bool
4224  Ins_SxVTL( TT_ExecContext exc,
4225  FT_UShort aIdx1,
4226  FT_UShort aIdx2,
4227  FT_UnitVector* Vec )
4228  {
4229  FT_Long A, B, C;
4230  FT_Vector* p1;
4231  FT_Vector* p2;
4232 
4233  FT_Byte opcode = exc->opcode;
4234 
4235 
4236  if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
4237  BOUNDS( aIdx2, exc->zp1.n_points ) )
4238  {
4239  if ( exc->pedantic_hinting )
4240  exc->error = FT_THROW( Invalid_Reference );
4241  return FAILURE;
4242  }
4243 
4244  p1 = exc->zp1.cur + aIdx2;
4245  p2 = exc->zp2.cur + aIdx1;
4246 
4247  A = SUB_LONG( p1->x, p2->x );
4248  B = SUB_LONG( p1->y, p2->y );
4249 
4250  /* If p1 == p2, SPvTL and SFvTL behave the same as */
4251  /* SPvTCA[X] and SFvTCA[X], respectively. */
4252  /* */
4253  /* Confirmed by Greg Hitchcock. */
4254 
4255  if ( A == 0 && B == 0 )
4256  {
4257  A = 0x4000;
4258  opcode = 0;
4259  }
4260 
4261  if ( ( opcode & 1 ) != 0 )
4262  {
4263  C = B; /* counter clockwise rotation */
4264  B = A;
4265  A = NEG_LONG( C );
4266  }
4267 
4268  Normalize( A, B, Vec );
4269 
4270  return SUCCESS;
4271  }
4272 
4273 
4274  /*************************************************************************/
4275  /* */
4276  /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
4277  /* Opcode range: 0x00-0x01 */
4278  /* Stack: --> */
4279  /* */
4280  /* SPvTCA[a]: Set PVector to Coordinate Axis */
4281  /* Opcode range: 0x02-0x03 */
4282  /* Stack: --> */
4283  /* */
4284  /* SFvTCA[a]: Set FVector to Coordinate Axis */
4285  /* Opcode range: 0x04-0x05 */
4286  /* Stack: --> */
4287  /* */
4288  static void
4289  Ins_SxyTCA( TT_ExecContext exc )
4290  {
4291  FT_Short AA, BB;
4292 
4293  FT_Byte opcode = exc->opcode;
4294 
4295 
4296  AA = (FT_Short)( ( opcode & 1 ) << 14 );
4297  BB = (FT_Short)( AA ^ 0x4000 );
4298 
4299  if ( opcode < 4 )
4300  {
4301  exc->GS.projVector.x = AA;
4302  exc->GS.projVector.y = BB;
4303 
4304  exc->GS.dualVector.x = AA;
4305  exc->GS.dualVector.y = BB;
4306  }
4307 
4308  if ( ( opcode & 2 ) == 0 )
4309  {
4310  exc->GS.freeVector.x = AA;
4311  exc->GS.freeVector.y = BB;
4312  }
4313 
4314  Compute_Funcs( exc );
4315  }
4316 
4317 
4318  /*************************************************************************/
4319  /* */
4320  /* SPvTL[a]: Set PVector To Line */
4321  /* Opcode range: 0x06-0x07 */
4322  /* Stack: uint32 uint32 --> */
4323  /* */
4324  static void
4325  Ins_SPVTL( TT_ExecContext exc,
4326  FT_Long* args )
4327  {
4328  if ( Ins_SxVTL( exc,
4329  (FT_UShort)args[1],
4330  (FT_UShort)args[0],
4331  &exc->GS.projVector ) == SUCCESS )
4332  {
4333  exc->GS.dualVector = exc->GS.projVector;
4334  Compute_Funcs( exc );
4335  }
4336  }
4337 
4338 
4339  /*************************************************************************/
4340  /* */
4341  /* SFvTL[a]: Set FVector To Line */
4342  /* Opcode range: 0x08-0x09 */
4343  /* Stack: uint32 uint32 --> */
4344  /* */
4345  static void
4346  Ins_SFVTL( TT_ExecContext exc,
4347  FT_Long* args )
4348  {
4349  if ( Ins_SxVTL( exc,
4350  (FT_UShort)args[1],
4351  (FT_UShort)args[0],
4352  &exc->GS.freeVector ) == SUCCESS )
4353  {
4354  Compute_Funcs( exc );
4355  }
4356  }
4357 
4358 
4359  /*************************************************************************/
4360  /* */
4361  /* SFvTPv[]: Set FVector To PVector */
4362  /* Opcode range: 0x0E */
4363  /* Stack: --> */
4364  /* */
4365  static void
4366  Ins_SFVTPV( TT_ExecContext exc )
4367  {
4368  exc->GS.freeVector = exc->GS.projVector;
4369  Compute_Funcs( exc );
4370  }
4371 
4372 
4373  /*************************************************************************/
4374  /* */
4375  /* SPvFS[]: Set PVector From Stack */
4376  /* Opcode range: 0x0A */
4377  /* Stack: f2.14 f2.14 --> */
4378  /* */
4379  static void
4380  Ins_SPVFS( TT_ExecContext exc,
4381  FT_Long* args )
4382  {
4383  FT_Short S;
4384  FT_Long X, Y;
4385 
4386 
4387  /* Only use low 16bits, then sign extend */
4388  S = (FT_Short)args[1];
4389  Y = (FT_Long)S;
4390  S = (FT_Short)args[0];
4391  X = (FT_Long)S;
4392 
4393  Normalize( X, Y, &exc->GS.projVector );
4394 
4395  exc->GS.dualVector = exc->GS.projVector;
4396  Compute_Funcs( exc );
4397  }
4398 
4399 
4400  /*************************************************************************/
4401  /* */
4402  /* SFvFS[]: Set FVector From Stack */
4403  /* Opcode range: 0x0B */
4404  /* Stack: f2.14 f2.14 --> */
4405  /* */
4406  static void
4407  Ins_SFVFS( TT_ExecContext exc,
4408  FT_Long* args )
4409  {
4410  FT_Short S;
4411  FT_Long X, Y;
4412 
4413 
4414  /* Only use low 16bits, then sign extend */
4415  S = (FT_Short)args[1];
4416  Y = (FT_Long)S;
4417  S = (FT_Short)args[0];
4418  X = S;
4419 
4420  Normalize( X, Y, &exc->GS.freeVector );
4421  Compute_Funcs( exc );
4422  }
4423 
4424 
4425  /*************************************************************************/
4426  /* */
4427  /* GPv[]: Get Projection Vector */
4428  /* Opcode range: 0x0C */
4429  /* Stack: ef2.14 --> ef2.14 */
4430  /* */
4431  static void
4432  Ins_GPV( TT_ExecContext exc,
4433  FT_Long* args )
4434  {
4435  args[0] = exc->GS.projVector.x;
4436  args[1] = exc->GS.projVector.y;
4437  }
4438 
4439 
4440  /*************************************************************************/
4441  /* */
4442  /* GFv[]: Get Freedom Vector */
4443  /* Opcode range: 0x0D */
4444  /* Stack: ef2.14 --> ef2.14 */
4445  /* */
4446  static void
4447  Ins_GFV( TT_ExecContext exc,
4448  FT_Long* args )
4449  {
4450  args[0] = exc->GS.freeVector.x;
4451  args[1] = exc->GS.freeVector.y;
4452  }
4453 
4454 
4455  /*************************************************************************/
4456  /* */
4457  /* SRP0[]: Set Reference Point 0 */
4458  /* Opcode range: 0x10 */
4459  /* Stack: uint32 --> */
4460  /* */
4461  static void
4462  Ins_SRP0( TT_ExecContext exc,
4463  FT_Long* args )
4464  {
4465  exc->GS.rp0 = (FT_UShort)args[0];
4466  }
4467 
4468 
4469  /*************************************************************************/
4470  /* */
4471  /* SRP1[]: Set Reference Point 1 */
4472  /* Opcode range: 0x11 */
4473  /* Stack: uint32 --> */
4474  /* */
4475  static void
4476  Ins_SRP1( TT_ExecContext exc,
4477  FT_Long* args )
4478  {
4479  exc->GS.rp1 = (FT_UShort)args[0];
4480  }
4481 
4482 
4483  /*************************************************************************/
4484  /* */
4485  /* SRP2[]: Set Reference Point 2 */
4486  /* Opcode range: 0x12 */
4487  /* Stack: uint32 --> */
4488  /* */
4489  static void
4490  Ins_SRP2( TT_ExecContext exc,
4491  FT_Long* args )
4492  {
4493  exc->GS.rp2 = (FT_UShort)args[0];
4494  }
4495 
4496 
4497  /*************************************************************************/
4498  /* */
4499  /* SMD[]: Set Minimum Distance */
4500  /* Opcode range: 0x1A */
4501  /* Stack: f26.6 --> */
4502  /* */
4503  static void
4504  Ins_SMD( TT_ExecContext exc,
4505  FT_Long* args )
4506  {
4507  exc->GS.minimum_distance = args[0];
4508  }
4509 
4510 
4511  /*************************************************************************/
4512  /* */
4513  /* SCVTCI[]: Set Control Value Table Cut In */
4514  /* Opcode range: 0x1D */
4515  /* Stack: f26.6 --> */
4516  /* */
4517  static void
4518  Ins_SCVTCI( TT_ExecContext exc,
4519  FT_Long* args )
4520  {
4522  }
4523 
4524 
4525  /*************************************************************************/
4526  /* */
4527  /* SSWCI[]: Set Single Width Cut In */
4528  /* Opcode range: 0x1E */
4529  /* Stack: f26.6 --> */
4530  /* */
4531  static void
4532  Ins_SSWCI( TT_ExecContext exc,
4533  FT_Long* args )
4534  {
4535  exc->GS.single_width_cutin = (FT_F26Dot6)args[0];
4536  }
4537 
4538 
4539  /*************************************************************************/
4540  /* */
4541  /* SSW[]: Set Single Width */
4542  /* Opcode range: 0x1F */
4543  /* Stack: int32? --> */
4544  /* */
4545  static void
4546  Ins_SSW( TT_ExecContext exc,
4547  FT_Long* args )
4548  {
4549  exc->GS.single_width_value = FT_MulFix( args[0],
4550  exc->tt_metrics.scale );
4551  }
4552 
4553 
4554  /*************************************************************************/
4555  /* */
4556  /* FLIPON[]: Set auto-FLIP to ON */
4557  /* Opcode range: 0x4D */
4558  /* Stack: --> */
4559  /* */
4560  static void
4561  Ins_FLIPON( TT_ExecContext exc )
4562  {
4563  exc->GS.auto_flip = TRUE;
4564  }
4565 
4566 
4567  /*************************************************************************/
4568  /* */
4569  /* FLIPOFF[]: Set auto-FLIP to OFF */
4570  /* Opcode range: 0x4E */
4571  /* Stack: --> */
4572  /* */
4573  static void
4574  Ins_FLIPOFF( TT_ExecContext exc )
4575  {
4576  exc->GS.auto_flip = FALSE;
4577  }
4578 
4579 
4580  /*************************************************************************/
4581  /* */
4582  /* SANGW[]: Set ANGle Weight */
4583  /* Opcode range: 0x7E */
4584  /* Stack: uint32 --> */
4585  /* */
4586  static void
4587  Ins_SANGW( void )
4588  {
4589  /* instruction not supported anymore */
4590  }
4591 
4592 
4593  /*************************************************************************/
4594  /* */
4595  /* SDB[]: Set Delta Base */
4596  /* Opcode range: 0x5E */
4597  /* Stack: uint32 --> */
4598  /* */
4599  static void
4600  Ins_SDB( TT_ExecContext exc,
4601  FT_Long* args )
4602  {
4603  exc->GS.delta_base = (FT_UShort)args[0];
4604  }
4605 
4606 
4607  /*************************************************************************/
4608  /* */
4609  /* SDS[]: Set Delta Shift */
4610  /* Opcode range: 0x5F */
4611  /* Stack: uint32 --> */
4612  /* */
4613  static void
4614  Ins_SDS( TT_ExecContext exc,
4615  FT_Long* args )
4616  {
4617  if ( (FT_ULong)args[0] > 6UL )
4618  exc->error = FT_THROW( Bad_Argument );
4619  else
4620  exc->GS.delta_shift = (FT_UShort)args[0];
4621  }
4622 
4623 
4624  /*************************************************************************/
4625  /* */
4626  /* RTHG[]: Round To Half Grid */
4627  /* Opcode range: 0x19 */
4628  /* Stack: --> */
4629  /* */
4630  static void
4631  Ins_RTHG( TT_ExecContext exc )
4632  {
4634  exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
4635  }
4636 
4637 
4638  /*************************************************************************/
4639  /* */
4640  /* RTG[]: Round To Grid */
4641  /* Opcode range: 0x18 */
4642  /* Stack: --> */
4643  /* */
4644  static void
4645  Ins_RTG( TT_ExecContext exc )
4646  {
4648  exc->func_round = (TT_Round_Func)Round_To_Grid;
4649  }
4650 
4651 
4652  /*************************************************************************/
4653  /* RTDG[]: Round To Double Grid */
4654  /* Opcode range: 0x3D */
4655  /* Stack: --> */
4656  /* */
4657  static void
4658  Ins_RTDG( TT_ExecContext exc )
4659  {
4661  exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
4662  }
4663 
4664 
4665  /*************************************************************************/
4666  /* RUTG[]: Round Up To Grid */
4667  /* Opcode range: 0x7C */
4668  /* Stack: --> */
4669  /* */
4670  static void
4671  Ins_RUTG( TT_ExecContext exc )
4672  {
4674  exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
4675  }
4676 
4677 
4678  /*************************************************************************/
4679  /* */
4680  /* RDTG[]: Round Down To Grid */
4681  /* Opcode range: 0x7D */
4682  /* Stack: --> */
4683  /* */
4684  static void
4685  Ins_RDTG( TT_ExecContext exc )
4686  {
4688  exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
4689  }
4690 
4691 
4692  /*************************************************************************/
4693  /* */
4694  /* ROFF[]: Round OFF */
4695  /* Opcode range: 0x7A */
4696  /* Stack: --> */
4697  /* */
4698  static void
4699  Ins_ROFF( TT_ExecContext exc )
4700  {
4701  exc->GS.round_state = TT_Round_Off;
4702  exc->func_round = (TT_Round_Func)Round_None;
4703  }
4704 
4705 
4706  /*************************************************************************/
4707  /* */
4708  /* SROUND[]: Super ROUND */
4709  /* Opcode range: 0x76 */
4710  /* Stack: Eint8 --> */
4711  /* */
4712  static void
4713  Ins_SROUND( TT_ExecContext exc,
4714  FT_Long* args )
4715  {
4716  SetSuperRound( exc, 0x4000, args[0] );
4717 
4718  exc->GS.round_state = TT_Round_Super;
4719  exc->func_round = (TT_Round_Func)Round_Super;
4720  }
4721 
4722 
4723  /*************************************************************************/
4724  /* */
4725  /* S45ROUND[]: Super ROUND 45 degrees */
4726  /* Opcode range: 0x77 */
4727  /* Stack: uint32 --> */
4728  /* */
4729  static void
4730  Ins_S45ROUND( TT_ExecContext exc,
4731  FT_Long* args )
4732  {
4733  SetSuperRound( exc, 0x2D41, args[0] );
4734 
4736  exc->func_round = (TT_Round_Func)Round_Super_45;
4737  }
4738 
4739 
4740  /*************************************************************************/
4741  /* */
4742  /* GC[a]: Get Coordinate projected onto */
4743  /* Opcode range: 0x46-0x47 */
4744  /* Stack: uint32 --> f26.6 */
4745  /* */
4746  /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
4747  /* along the dual projection vector! */
4748  /* */
4749  static void
4750  Ins_GC( TT_ExecContext exc,
4751  FT_Long* args )
4752  {
4753  FT_ULong L;
4754  FT_F26Dot6 R;
4755 
4756 
4757  L = (FT_ULong)args[0];
4758 
4759  if ( BOUNDSL( L, exc->zp2.n_points ) )
4760  {
4761  if ( exc->pedantic_hinting )
4762  exc->error = FT_THROW( Invalid_Reference );
4763  R = 0;
4764  }
4765  else
4766  {
4767  if ( exc->opcode & 1 )
4768  R = FAST_DUALPROJ( &exc->zp2.org[L] );
4769  else
4770  R = FAST_PROJECT( &exc->zp2.cur[L] );
4771  }
4772 
4773  args[0] = R;
4774  }
4775 
4776 
4777  /*************************************************************************/
4778  /* */
4779  /* SCFS[]: Set Coordinate From Stack */
4780  /* Opcode range: 0x48 */
4781  /* Stack: f26.6 uint32 --> */
4782  /* */
4783  /* Formula: */
4784  /* */
4785  /* OA := OA + ( value - OA.p )/( f.p ) * f */
4786  /* */
4787  static void
4788  Ins_SCFS( TT_ExecContext exc,
4789  FT_Long* args )
4790  {
4791  FT_Long K;
4792  FT_UShort L;
4793 
4794 
4795  L = (FT_UShort)args[0];
4796 
4797  if ( BOUNDS( L, exc->zp2.n_points ) )
4798  {
4799  if ( exc->pedantic_hinting )
4800  exc->error = FT_THROW( Invalid_Reference );
4801  return;
4802  }
4803 
4804  K = FAST_PROJECT( &exc->zp2.cur[L] );
4805 
4806  exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );
4807 
4808  /* UNDOCUMENTED! The MS rasterizer does that with */
4809  /* twilight points (confirmed by Greg Hitchcock) */
4810  if ( exc->GS.gep2 == 0 )
4811  exc->zp2.org[L] = exc->zp2.cur[L];
4812  }
4813 
4814 
4815  /*************************************************************************/
4816  /* */
4817  /* MD[a]: Measure Distance */
4818  /* Opcode range: 0x49-0x4A */
4819  /* Stack: uint32 uint32 --> f26.6 */
4820  /* */
4821  /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
4822  /* the dual projection vector. */
4823  /* */
4824  /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
4825  /* 0 => measure distance in original outline */
4826  /* 1 => measure distance in grid-fitted outline */
4827  /* */
4828  /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
4829  /* */
4830  static void
4831  Ins_MD( TT_ExecContext exc,
4832  FT_Long* args )
4833  {
4834  FT_UShort K, L;
4835  FT_F26Dot6 D;
4836 
4837 
4838  K = (FT_UShort)args[1];
4839  L = (FT_UShort)args[0];
4840 
4841  if ( BOUNDS( L, exc->zp0.n_points ) ||
4842  BOUNDS( K, exc->zp1.n_points ) )
4843  {
4844  if ( exc->pedantic_hinting )
4845  exc->error = FT_THROW( Invalid_Reference );
4846  D = 0;
4847  }
4848  else
4849  {
4850  if ( exc->opcode & 1 )
4851  D = PROJECT( exc->zp0.cur + L, exc->zp1.cur + K );
4852  else
4853  {
4854  /* XXX: UNDOCUMENTED: twilight zone special case */
4855 
4856  if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )
4857  {
4858  FT_Vector* vec1 = exc->zp0.org + L;
4859  FT_Vector* vec2 = exc->zp1.org + K;
4860 
4861 
4862  D = DUALPROJ( vec1, vec2 );
4863  }
4864  else
4865  {
4866  FT_Vector* vec1 = exc->zp0.orus + L;
4867  FT_Vector* vec2 = exc->zp1.orus + K;
4868 
4869 
4870  if ( exc->metrics.x_scale == exc->metrics.y_scale )
4871  {
4872  /* this should be faster */
4873  D = DUALPROJ( vec1, vec2 );
4874  D = FT_MulFix( D, exc->metrics.x_scale );
4875  }
4876  else
4877  {
4878  FT_Vector vec;
4879 
4880 
4881  vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale );
4882  vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );
4883 
4884  D = FAST_DUALPROJ( &vec );
4885  }
4886  }
4887  }
4888  }
4889 
4890 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
4891  /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
4892  if ( SUBPIXEL_HINTING_INFINALITY &&
4893  exc->ignore_x_mode &&
4894  FT_ABS( D ) == 64 )
4895  D += 1;
4896 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
4897 
4898  args[0] = D;
4899  }
4900 
4901 
4902  /*************************************************************************/
4903  /* */
4904  /* SDPvTL[a]: Set Dual PVector to Line */
4905  /* Opcode range: 0x86-0x87 */
4906  /* Stack: uint32 uint32 --> */
4907  /* */
4908  static void
4909  Ins_SDPVTL( TT_ExecContext exc,
4910  FT_Long* args )
4911  {
4912  FT_Long A, B, C;
4913  FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4914 
4915  FT_Byte opcode = exc->opcode;
4916 
4917 
4918  p1 = (FT_UShort)args[1];
4919  p2 = (FT_UShort)args[0];
4920 
4921  if ( BOUNDS( p2, exc->zp1.n_points ) ||
4922  BOUNDS( p1, exc->zp2.n_points ) )
4923  {
4924  if ( exc->pedantic_hinting )
4925  exc->error = FT_THROW( Invalid_Reference );
4926  return;
4927  }
4928 
4929  {
4930  FT_Vector* v1 = exc->zp1.org + p2;
4931  FT_Vector* v2 = exc->zp2.org + p1;
4932 
4933 
4934  A = SUB_LONG( v1->x, v2->x );
4935  B = SUB_LONG( v1->y, v2->y );
4936 
4937  /* If v1 == v2, SDPvTL behaves the same as */
4938  /* SVTCA[X], respectively. */
4939  /* */
4940  /* Confirmed by Greg Hitchcock. */
4941 
4942  if ( A == 0 && B == 0 )
4943  {
4944  A = 0x4000;
4945  opcode = 0;
4946  }
4947  }
4948 
4949  if ( ( opcode & 1 ) != 0 )
4950  {
4951  C = B; /* counter clockwise rotation */
4952  B = A;
4953  A = NEG_LONG( C );
4954  }
4955 
4956  Normalize( A, B, &exc->GS.dualVector );
4957 
4958  {
4959  FT_Vector* v1 = exc->zp1.cur + p2;
4960  FT_Vector* v2 = exc->zp2.cur + p1;
4961 
4962 
4963  A = SUB_LONG( v1->x, v2->x );
4964  B = SUB_LONG( v1->y, v2->y );
4965 
4966  if ( A == 0 && B == 0 )
4967  {
4968  A = 0x4000;
4969  opcode = 0;
4970  }
4971  }
4972 
4973  if ( ( opcode & 1 ) != 0 )
4974  {
4975  C = B; /* counter clockwise rotation */
4976  B = A;
4977  A = NEG_LONG( C );
4978  }
4979 
4980  Normalize( A, B, &exc->GS.projVector );
4981  Compute_Funcs( exc );
4982  }
4983 
4984 
4985  /*************************************************************************/
4986  /* */
4987  /* SZP0[]: Set Zone Pointer 0 */
4988  /* Opcode range: 0x13 */
4989  /* Stack: uint32 --> */
4990  /* */
4991  static void
4992  Ins_SZP0( TT_ExecContext exc,
4993  FT_Long* args )
4994  {
4995  switch ( (FT_Int)args[0] )
4996  {
4997  case 0:
4998  exc->zp0 = exc->twilight;
4999  break;
5000 
5001  case 1:
5002  exc->zp0 = exc->pts;
5003  break;
5004 
5005  default:
5006  if ( exc->pedantic_hinting )
5007  exc->error = FT_THROW( Invalid_Reference );
5008  return;
5009  }
5010 
5011  exc->GS.gep0 = (FT_UShort)args[0];
5012  }
5013 
5014 
5015  /*************************************************************************/
5016  /* */
5017  /* SZP1[]: Set Zone Pointer 1 */
5018  /* Opcode range: 0x14 */
5019  /* Stack: uint32 --> */
5020  /* */
5021  static void
5022  Ins_SZP1( TT_ExecContext exc,
5023  FT_Long* args )
5024  {
5025  switch ( (FT_Int)args[0] )
5026  {
5027  case 0:
5028  exc->zp1 = exc->twilight;
5029  break;
5030 
5031  case 1:
5032  exc->zp1 = exc->pts;
5033  break;
5034 
5035  default:
5036  if ( exc->pedantic_hinting )
5037  exc->error = FT_THROW( Invalid_Reference );
5038  return;
5039  }
5040 
5041  exc->GS.gep1 = (FT_UShort)args[0];
5042  }
5043 
5044 
5045  /*************************************************************************/
5046  /* */
5047  /* SZP2[]: Set Zone Pointer 2 */
5048  /* Opcode range: 0x15 */
5049  /* Stack: uint32 --> */
5050  /* */
5051  static void
5052  Ins_SZP2( TT_ExecContext exc,
5053  FT_Long* args )
5054  {
5055  switch ( (FT_Int)args[0] )
5056  {
5057  case 0:
5058  exc->zp2 = exc->twilight;
5059  break;
5060 
5061  case 1:
5062  exc->zp2 = exc->pts;
5063  break;
5064 
5065  default:
5066  if ( exc->pedantic_hinting )
5067  exc->error = FT_THROW( Invalid_Reference );
5068  return;
5069  }
5070 
5071  exc->GS.gep2 = (FT_UShort)args[0];
5072  }
5073 
5074 
5075  /*************************************************************************/
5076  /* */
5077  /* SZPS[]: Set Zone PointerS */
5078  /* Opcode range: 0x16 */
5079  /* Stack: uint32 --> */
5080  /* */
5081  static void
5082  Ins_SZPS( TT_ExecContext exc,
5083  FT_Long* args )
5084  {
5085  switch ( (FT_Int)args[0] )
5086  {
5087  case 0:
5088  exc->zp0 = exc->twilight;
5089  break;
5090 
5091  case 1:
5092  exc->zp0 = exc->pts;
5093  break;
5094 
5095  default:
5096  if ( exc->pedantic_hinting )
5097  exc->error = FT_THROW( Invalid_Reference );
5098  return;
5099  }
5100 
5101  exc->zp1 = exc->zp0;
5102  exc->zp2 = exc->zp0;
5103 
5104  exc->GS.gep0 = (FT_UShort)args[0];
5105  exc->GS.gep1 = (FT_UShort)args[0];
5106  exc->GS.gep2 = (FT_UShort)args[0];
5107  }
5108 
5109 
5110  /*************************************************************************/
5111  /* */
5112  /* INSTCTRL[]: INSTruction ConTRoL */
5113  /* Opcode range: 0x8E */
5114  /* Stack: int32 int32 --> */
5115  /* */
5116  static void
5117  Ins_INSTCTRL( TT_ExecContext exc,
5118  FT_Long* args )
5119  {
5120  FT_ULong K, L, Kf;
5121 
5122 
5123  K = (FT_ULong)args[1];
5124  L = (FT_ULong)args[0];
5125 
5126  /* selector values cannot be `OR'ed; */
5127  /* they are indices starting with index 1, not flags */
5128  if ( K < 1 || K > 3 )
5129  {
5130  if ( exc->pedantic_hinting )
5131  exc->error = FT_THROW( Invalid_Reference );
5132  return;
5133  }
5134 
5135  /* convert index to flag value */
5136  Kf = 1 << ( K - 1 );
5137 
5138  if ( L != 0 )
5139  {
5140  /* arguments to selectors look like flag values */
5141  if ( L != Kf )
5142  {
5143  if ( exc->pedantic_hinting )
5144  exc->error = FT_THROW( Invalid_Reference );
5145  return;
5146  }
5147  }
5148 
5149  exc->GS.instruct_control &= ~(FT_Byte)Kf;
5150  exc->GS.instruct_control |= (FT_Byte)L;
5151 
5152  if ( K == 3 )
5153  {
5154 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5155  /* INSTCTRL modifying flag 3 also has an effect */
5156  /* outside of the CVT program */
5157  if ( SUBPIXEL_HINTING_INFINALITY )
5158  exc->ignore_x_mode = FT_BOOL( L == 4 );
5159 #endif
5160 
5161 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5162  /* Native ClearType fonts sign a waiver that turns off all backward */
5163  /* compatibility hacks and lets them program points to the grid like */
5164  /* it's 1996. They might sign a waiver for just one glyph, though. */
5165  if ( SUBPIXEL_HINTING_MINIMAL )
5166  exc->backward_compatibility = !FT_BOOL( L == 4 );
5167 #endif
5168  }
5169  }
5170 
5171 
5172  /*************************************************************************/
5173  /* */
5174  /* SCANCTRL[]: SCAN ConTRoL */
5175  /* Opcode range: 0x85 */
5176  /* Stack: uint32? --> */
5177  /* */
5178  static void
5179  Ins_SCANCTRL( TT_ExecContext exc,
5180  FT_Long* args )
5181  {
5182  FT_Int A;
5183 
5184 
5185  /* Get Threshold */
5186  A = (FT_Int)( args[0] & 0xFF );
5187 
5188  if ( A == 0xFF )
5189  {
5190  exc->GS.scan_control = TRUE;
5191  return;
5192  }
5193  else if ( A == 0 )
5194  {
5195  exc->GS.scan_control = FALSE;
5196  return;
5197  }
5198 
5199  if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )
5200  exc->GS.scan_control = TRUE;
5201 
5202  if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )
5203  exc->GS.scan_control = TRUE;
5204 
5205  if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )
5206  exc->GS.scan_control = TRUE;
5207 
5208  if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )
5209  exc->GS.scan_control = FALSE;
5210 
5211  if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )
5212  exc->GS.scan_control = FALSE;
5213 
5214  if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )
5215  exc->GS.scan_control = FALSE;
5216  }
5217 
5218 
5219  /*************************************************************************/
5220  /* */
5221  /* SCANTYPE[]: SCAN TYPE */
5222  /* Opcode range: 0x8D */
5223  /* Stack: uint16 --> */
5224  /* */
5225  static void
5226  Ins_SCANTYPE( TT_ExecContext exc,
5227  FT_Long* args )
5228  {
5229  if ( args[0] >= 0 )
5230  exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;
5231  }
5232 
5233 
5234  /*************************************************************************/
5235  /* */
5236  /* MANAGING OUTLINES */
5237  /* */
5238  /*************************************************************************/
5239 
5240 
5241  /*************************************************************************/
5242  /* */
5243  /* FLIPPT[]: FLIP PoinT */
5244  /* Opcode range: 0x80 */
5245  /* Stack: uint32... --> */
5246  /* */
5247  static void
5248  Ins_FLIPPT( TT_ExecContext exc )
5249  {
5250  FT_UShort point;
5251 
5252 
5253 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5254  /* See `ttinterp.h' for details on backward compatibility mode. */
5255  if ( SUBPIXEL_HINTING_MINIMAL &&
5256  exc->backward_compatibility &&
5257  exc->iupx_called &&
5258  exc->iupy_called )
5259  goto Fail;
5260 #endif
5261 
5262  if ( exc->top < exc->GS.loop )
5263  {
5264  if ( exc->pedantic_hinting )
5265  exc->error = FT_THROW( Too_Few_Arguments );
5266  goto Fail;
5267  }
5268 
5269  while ( exc->GS.loop > 0 )
5270  {
5271  exc->args--;
5272 
5273  point = (FT_UShort)exc->stack[exc->args];
5274 
5275  if ( BOUNDS( point, exc->pts.n_points ) )
5276  {
5277  if ( exc->pedantic_hinting )
5278  {
5279  exc->error = FT_THROW( Invalid_Reference );
5280  return;
5281  }
5282  }
5283  else
5284  exc->pts.tags[point] ^= FT_CURVE_TAG_ON;
5285 
5286  exc->GS.loop--;
5287  }
5288 
5289  Fail:
5290  exc->GS.loop = 1;
5291  exc->new_top = exc->args;
5292  }
5293 
5294 
5295  /*************************************************************************/
5296  /* */
5297  /* FLIPRGON[]: FLIP RanGe ON */
5298  /* Opcode range: 0x81 */
5299  /* Stack: uint32 uint32 --> */
5300  /* */
5301  static void
5302  Ins_FLIPRGON( TT_ExecContext exc,
5303  FT_Long* args )
5304  {
5305  FT_UShort I, K, L;
5306 
5307 
5308 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5309  /* See `ttinterp.h' for details on backward compatibility mode. */
5310  if ( SUBPIXEL_HINTING_MINIMAL &&
5311  exc->backward_compatibility &&
5312  exc->iupx_called &&
5313  exc->iupy_called )
5314  return;
5315 #endif
5316 
5317  K = (FT_UShort)args[1];
5318  L = (FT_UShort)args[0];
5319 
5320  if ( BOUNDS( K, exc->pts.n_points ) ||
5321  BOUNDS( L, exc->pts.n_points ) )
5322  {
5323  if ( exc->pedantic_hinting )
5324  exc->error = FT_THROW( Invalid_Reference );
5325  return;
5326  }
5327 
5328  for ( I = L; I <= K; I++ )
5329  exc->pts.tags[I] |= FT_CURVE_TAG_ON;
5330  }
5331 
5332 
5333  /*************************************************************************/
5334  /* */
5335  /* FLIPRGOFF: FLIP RanGe OFF */
5336  /* Opcode range: 0x82 */
5337  /* Stack: uint32 uint32 --> */
5338  /* */
5339  static void
5340  Ins_FLIPRGOFF( TT_ExecContext exc,
5341  FT_Long* args )
5342  {
5343  FT_UShort I, K, L;
5344 
5345 
5346 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5347  /* See `ttinterp.h' for details on backward compatibility mode. */
5348  if ( SUBPIXEL_HINTING_MINIMAL &&
5349  exc->backward_compatibility &&
5350  exc->iupx_called &&
5351  exc->iupy_called )
5352  return;
5353 #endif
5354 
5355  K = (FT_UShort)args[1];
5356  L = (FT_UShort)args[0];
5357 
5358  if ( BOUNDS( K, exc->pts.n_points ) ||
5359  BOUNDS( L, exc->pts.n_points ) )
5360  {
5361  if ( exc->pedantic_hinting )
5362  exc->error = FT_THROW( Invalid_Reference );
5363  return;
5364  }
5365 
5366  for ( I = L; I <= K; I++ )
5367  exc->pts.tags[I] &= ~FT_CURVE_TAG_ON;
5368  }
5369 
5370 
5371  static FT_Bool
5372  Compute_Point_Displacement( TT_ExecContext exc,
5373  FT_F26Dot6* x,
5374  FT_F26Dot6* y,
5376  FT_UShort* refp )
5377  {
5378  TT_GlyphZoneRec zp;
5379  FT_UShort p;
5380  FT_F26Dot6 d;
5381 
5382 
5383  if ( exc->opcode & 1 )
5384  {
5385  zp = exc->zp0;
5386  p = exc->GS.rp1;
5387  }
5388  else
5389  {
5390  zp = exc->zp1;
5391  p = exc->GS.rp2;
5392  }
5393 
5394  if ( BOUNDS( p, zp.n_points ) )
5395  {
5396  if ( exc->pedantic_hinting )
5397  exc->error = FT_THROW( Invalid_Reference );
5398  *refp = 0;
5399  return FAILURE;
5400  }
5401 
5402  *zone = zp;
5403  *refp = p;
5404 
5405  d = PROJECT( zp.cur + p, zp.org + p );
5406 
5407  *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P );
5408  *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P );
5409 
5410  return SUCCESS;
5411  }
5412 
5413 
5414  /* See `ttinterp.h' for details on backward compatibility mode. */
5415  static void
5416  Move_Zp2_Point( TT_ExecContext exc,
5417  FT_UShort point,
5418  FT_F26Dot6 dx,
5419  FT_F26Dot6 dy,
5420  FT_Bool touch )
5421  {
5422  if ( exc->GS.freeVector.x != 0 )
5423  {
5424 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5425  if ( !( SUBPIXEL_HINTING_MINIMAL &&
5426  exc->backward_compatibility ) )
5427 #endif
5428  exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx );
5429 
5430  if ( touch )
5432  }
5433 
5434  if ( exc->GS.freeVector.y != 0 )
5435  {
5436 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5437  if ( !( SUBPIXEL_HINTING_MINIMAL &&
5438  exc->backward_compatibility &&
5439  exc->iupx_called &&
5440  exc->iupy_called ) )
5441 #endif
5442  exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );
5443 
5444  if ( touch )
5446  }
5447  }
5448 
5449 
5450  /*************************************************************************/
5451  /* */
5452  /* SHP[a]: SHift Point by the last point */
5453  /* Opcode range: 0x32-0x33 */
5454  /* Stack: uint32... --> */
5455  /* */
5456  static void
5457  Ins_SHP( TT_ExecContext exc )
5458  {
5459  TT_GlyphZoneRec zp;
5460  FT_UShort refp;
5461 
5462  FT_F26Dot6 dx, dy;
5463  FT_UShort point;
5464 
5465 
5466  if ( exc->top < exc->GS.loop )
5467  {
5468  if ( exc->pedantic_hinting )
5469  exc->error = FT_THROW( Invalid_Reference );
5470  goto Fail;
5471  }
5472 
5473  if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5474  return;
5475 
5476  while ( exc->GS.loop > 0 )
5477  {
5478  exc->args--;
5479  point = (FT_UShort)exc->stack[exc->args];
5480 
5481  if ( BOUNDS( point, exc->zp2.n_points ) )
5482  {
5483  if ( exc->pedantic_hinting )
5484  {
5485  exc->error = FT_THROW( Invalid_Reference );
5486  return;
5487  }
5488  }
5489  else
5490 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5491  /* doesn't follow Cleartype spec but produces better result */
5492  if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
5493  Move_Zp2_Point( exc, point, 0, dy, TRUE );
5494  else
5495 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5496  Move_Zp2_Point( exc, point, dx, dy, TRUE );
5497 
5498  exc->GS.loop--;
5499  }
5500 
5501  Fail:
5502  exc->GS.loop = 1;
5503  exc->new_top = exc->args;
5504  }
5505 
5506 
5507  /*************************************************************************/
5508  /* */
5509  /* SHC[a]: SHift Contour */
5510  /* Opcode range: 0x34-35 */
5511  /* Stack: uint32 --> */
5512  /* */
5513  /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
5514  /* contour in the twilight zone, namely contour number */
5515  /* zero which includes all points of it. */
5516  /* */
5517  static void
5518  Ins_SHC( TT_ExecContext exc,
5519  FT_Long* args )
5520  {
5521  TT_GlyphZoneRec zp;
5522  FT_UShort refp;
5523  FT_F26Dot6 dx, dy;
5524 
5525  FT_Short contour, bounds;
5526  FT_UShort start, limit, i;
5527 
5528 
5529  contour = (FT_Short)args[0];
5530  bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
5531 
5532  if (