ReactOS 0.4.15-dev-7953-g1f49173
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,
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,
172 void* base,
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,
280 {
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 {
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,
387 TT_Size size )
388 {
389 FT_Int i;
390 FT_ULong tmp;
391 TT_MaxProfile* maxp;
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 {
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,
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,
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,
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,
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,
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
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
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,
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,
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
1808 }
1809
1810
1811 static void
1812 Direct_Move_Y( TT_ExecContext exc,
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
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,
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,
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 {
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 {
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 {
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 {
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 {
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 {
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 {
2161
2162
2163 if ( distance >= 0 )
2164 {
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 {
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
2263 exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
2264 break;
2265
2267 exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
2268 break;
2269
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 {
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 {
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 {
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
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 {
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,
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;
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;
5527
5528
5529 contour = (FT_Short)args[0];
5530 bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
5531
5532 if ( BOUNDS( contour, bounds ) )
5533 {
5534 if ( exc->pedantic_hinting )
5535 exc->error = FT_THROW( Invalid_Reference );
5536 return;
5537 }
5538
5539 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5540 return;
5541
5542 if ( contour == 0 )
5543 start = 0;
5544 else
5545 start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
5546 exc->zp2.first_point );
5547
5548 /* we use the number of points if in the twilight zone */
5549 if ( exc->GS.gep2 == 0 )
5550 limit = exc->zp2.n_points;
5551 else
5552 limit = (FT_UShort)( exc->zp2.contours[contour] -
5553 exc->zp2.first_point + 1 );
5554
5555 for ( i = start; i < limit; i++ )
5556 {
5557 if ( zp.cur != exc->zp2.cur || refp != i )
5558 Move_Zp2_Point( exc, i, dx, dy, TRUE );
5559 }
5560 }
5561
5562
5563 /*************************************************************************/
5564 /* */
5565 /* SHZ[a]: SHift Zone */
5566 /* Opcode range: 0x36-37 */
5567 /* Stack: uint32 --> */
5568 /* */
5569 static void
5570 Ins_SHZ( TT_ExecContext exc,
5571 FT_Long* args )
5572 {
5573 TT_GlyphZoneRec zp;
5574 FT_UShort refp;
5575 FT_F26Dot6 dx,
5576 dy;
5577
5578 FT_UShort limit, i;
5579
5580
5581 if ( BOUNDS( args[0], 2 ) )
5582 {
5583 if ( exc->pedantic_hinting )
5584 exc->error = FT_THROW( Invalid_Reference );
5585 return;
5586 }
5587
5588 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5589 return;
5590
5591 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5592 /* Twilight zone has no real contours, so use `n_points'. */
5593 /* Normal zone's `n_points' includes phantoms, so must */
5594 /* use end of last contour. */
5595 if ( exc->GS.gep2 == 0 )
5596 limit = (FT_UShort)exc->zp2.n_points;
5597 else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
5598 limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
5599 else
5600 limit = 0;
5601
5602 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5603 for ( i = 0; i < limit; i++ )
5604 {
5605 if ( zp.cur != exc->zp2.cur || refp != i )
5606 Move_Zp2_Point( exc, i, dx, dy, FALSE );
5607 }
5608 }
5609
5610
5611 /*************************************************************************/
5612 /* */
5613 /* SHPIX[]: SHift points by a PIXel amount */
5614 /* Opcode range: 0x38 */
5615 /* Stack: f26.6 uint32... --> */
5616 /* */
5617 static void
5618 Ins_SHPIX( TT_ExecContext exc,
5619 FT_Long* args )
5620 {
5621 FT_F26Dot6 dx, dy;
5623#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5624 FT_Int B1, B2;
5625#endif
5626#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5627 FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||
5628 exc->GS.gep1 == 0 ||
5629 exc->GS.gep2 == 0 );
5630#endif
5631
5632
5633
5634 if ( exc->top < exc->GS.loop + 1 )
5635 {
5636 if ( exc->pedantic_hinting )
5637 exc->error = FT_THROW( Invalid_Reference );
5638 goto Fail;
5639 }
5640
5641 dx = TT_MulFix14( args[0], exc->GS.freeVector.x );
5642 dy = TT_MulFix14( args[0], exc->GS.freeVector.y );
5643
5644 while ( exc->GS.loop > 0 )
5645 {
5646 exc->args--;
5647
5648 point = (FT_UShort)exc->stack[exc->args];
5649
5650 if ( BOUNDS( point, exc->zp2.n_points ) )
5651 {
5652 if ( exc->pedantic_hinting )
5653 {
5654 exc->error = FT_THROW( Invalid_Reference );
5655 return;
5656 }
5657 }
5658 else
5659#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5660 if ( SUBPIXEL_HINTING_INFINALITY )
5661 {
5662 /* If not using ignore_x_mode rendering, allow ZP2 move. */
5663 /* If inline deltas aren't allowed, skip ZP2 move. */
5664 /* If using ignore_x_mode rendering, allow ZP2 point move if: */
5665 /* - freedom vector is y and sph_compatibility_mode is off */
5666 /* - the glyph is composite and the move is in the Y direction */
5667 /* - the glyph is specifically set to allow SHPIX moves */
5668 /* - the move is on a previously Y-touched point */
5669
5670 if ( exc->ignore_x_mode )
5671 {
5672 /* save point for later comparison */
5673 if ( exc->GS.freeVector.y != 0 )
5674 B1 = exc->zp2.cur[point].y;
5675 else
5676 B1 = exc->zp2.cur[point].x;
5677
5678 if ( !exc->face->sph_compatibility_mode &&
5679 exc->GS.freeVector.y != 0 )
5680 {
5681 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5682
5683 /* save new point */
5684 if ( exc->GS.freeVector.y != 0 )
5685 {
5686 B2 = exc->zp2.cur[point].y;
5687
5688 /* reverse any disallowed moves */
5689 if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
5690 ( B1 & 63 ) != 0 &&
5691 ( B2 & 63 ) != 0 &&
5692 B1 != B2 )
5693 Move_Zp2_Point( exc,
5694 point,
5695 NEG_LONG( dx ),
5696 NEG_LONG( dy ),
5697 TRUE );
5698 }
5699 }
5700 else if ( exc->face->sph_compatibility_mode )
5701 {
5702 if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
5703 {
5704 dx = FT_PIX_ROUND( B1 + dx ) - B1;
5705 dy = FT_PIX_ROUND( B1 + dy ) - B1;
5706 }
5707
5708 /* skip post-iup deltas */
5709 if ( exc->iup_called &&
5710 ( ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
5711 ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
5712 goto Skip;
5713
5714 if ( !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
5715 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
5716 ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
5717 ( exc->sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) )
5718 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5719
5720 /* save new point */
5721 if ( exc->GS.freeVector.y != 0 )
5722 {
5723 B2 = exc->zp2.cur[point].y;
5724
5725 /* reverse any disallowed moves */
5726 if ( ( B1 & 63 ) == 0 &&
5727 ( B2 & 63 ) != 0 &&
5728 B1 != B2 )
5729 Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE );
5730 }
5731 }
5732 else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
5733 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5734 }
5735 else
5736 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5737 }
5738 else
5739#endif
5740#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5741 if ( SUBPIXEL_HINTING_MINIMAL &&
5742 exc->backward_compatibility )
5743 {
5744 /* Special case: allow SHPIX to move points in the twilight zone. */
5745 /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */
5746 /* fonts such as older versions of Rokkitt and DTL Argo T Light */
5747 /* that would glitch severely after calling ALIGNRP after a */
5748 /* blocked SHPIX. */
5749 if ( in_twilight ||
5750 ( !( exc->iupx_called && exc->iupy_called ) &&
5751 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
5752 ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) )
5753 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5754 }
5755 else
5756#endif
5757 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5758
5759#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5760 Skip:
5761#endif
5762 exc->GS.loop--;
5763 }
5764
5765 Fail:
5766 exc->GS.loop = 1;
5767 exc->new_top = exc->args;
5768 }
5769
5770
5771 /*************************************************************************/
5772 /* */
5773 /* MSIRP[a]: Move Stack Indirect Relative Position */
5774 /* Opcode range: 0x3A-0x3B */
5775 /* Stack: f26.6 uint32 --> */
5776 /* */
5777 static void
5778 Ins_MSIRP( TT_ExecContext exc,
5779 FT_Long* args )
5780 {
5781 FT_UShort point = 0;
5783#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5784 FT_F26Dot6 control_value_cutin = 0;
5785
5786
5787 if ( SUBPIXEL_HINTING_INFINALITY )
5788 {
5789 control_value_cutin = exc->GS.control_value_cutin;
5790
5791 if ( exc->ignore_x_mode &&
5792 exc->GS.freeVector.x != 0 &&
5793 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
5794 control_value_cutin = 0;
5795 }
5796#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5797
5798 point = (FT_UShort)args[0];
5799
5800 if ( BOUNDS( point, exc->zp1.n_points ) ||
5801 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
5802 {
5803 if ( exc->pedantic_hinting )
5804 exc->error = FT_THROW( Invalid_Reference );
5805 return;
5806 }
5807
5808 /* UNDOCUMENTED! The MS rasterizer does that with */
5809 /* twilight points (confirmed by Greg Hitchcock) */
5810 if ( exc->GS.gep1 == 0 )
5811 {
5812 exc->zp1.org[point] = exc->zp0.org[exc->GS.rp0];
5813 exc->func_move_orig( exc, &exc->zp1, point, args[1] );
5814 exc->zp1.cur[point] = exc->zp1.org[point];
5815 }
5816
5817 distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
5818
5819#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5820 /* subpixel hinting - make MSIRP respect CVT cut-in; */
5821 if ( SUBPIXEL_HINTING_INFINALITY &&
5822 exc->ignore_x_mode &&
5823 exc->GS.freeVector.x != 0 &&
5824 FT_ABS( SUB_LONG( distance, args[1] ) ) >= control_value_cutin )
5825 distance = args[1];
5826#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5827
5828 exc->func_move( exc,
5829 &exc->zp1,
5830 point,
5831 SUB_LONG( args[1], distance ) );
5832
5833 exc->GS.rp1 = exc->GS.rp0;
5834 exc->GS.rp2 = point;
5835
5836 if ( ( exc->opcode & 1 ) != 0 )
5837 exc->GS.rp0 = point;
5838 }
5839
5840
5841 /*************************************************************************/
5842 /* */
5843 /* MDAP[a]: Move Direct Absolute Point */
5844 /* Opcode range: 0x2E-0x2F */
5845 /* Stack: uint32 --> */
5846 /* */
5847 static void
5848 Ins_MDAP( TT_ExecContext exc,
5849 FT_Long* args )
5850 {
5852 FT_F26Dot6 cur_dist;
5854
5855
5856 point = (FT_UShort)args[0];
5857
5858 if ( BOUNDS( point, exc->zp0.n_points ) )
5859 {
5860 if ( exc->pedantic_hinting )
5861 exc->error = FT_THROW( Invalid_Reference );
5862 return;
5863 }
5864
5865 if ( ( exc->opcode & 1 ) != 0 )
5866 {
5867 cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );
5868#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5869 if ( SUBPIXEL_HINTING_INFINALITY &&
5870 exc->ignore_x_mode &&
5871 exc->GS.freeVector.x != 0 )
5872 distance = Round_None(
5873 exc,
5874 cur_dist,
5875 exc->tt_metrics.compensations[0] ) - cur_dist;
5876 else
5877#endif
5878 distance = exc->func_round(
5879 exc,
5880 cur_dist,
5881 exc->tt_metrics.compensations[0] ) - cur_dist;
5882 }
5883 else
5884 distance = 0;
5885
5886 exc->func_move( exc, &exc->zp0, point, distance );
5887
5888 exc->GS.rp0 = point;
5889 exc->GS.rp1 = point;
5890 }
5891
5892
5893 /*************************************************************************/
5894 /* */
5895 /* MIAP[a]: Move Indirect Absolute Point */
5896 /* Opcode range: 0x3E-0x3F */
5897 /* Stack: uint32 uint32 --> */
5898 /* */
5899 static void
5900 Ins_MIAP( TT_ExecContext exc,
5901 FT_Long* args )
5902 {
5903 FT_ULong cvtEntry;
5906 FT_F26Dot6 org_dist;
5907 FT_F26Dot6 control_value_cutin;
5908
5909
5910 control_value_cutin = exc->GS.control_value_cutin;
5911 cvtEntry = (FT_ULong)args[1];
5912 point = (FT_UShort)args[0];
5913
5914#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5915 if ( SUBPIXEL_HINTING_INFINALITY &&
5916 exc->ignore_x_mode &&
5917 exc->GS.freeVector.x != 0 &&
5918 exc->GS.freeVector.y == 0 &&
5919 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
5920 control_value_cutin = 0;
5921#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5922
5923 if ( BOUNDS( point, exc->zp0.n_points ) ||
5924 BOUNDSL( cvtEntry, exc->cvtSize ) )
5925 {
5926 if ( exc->pedantic_hinting )
5927 exc->error = FT_THROW( Invalid_Reference );
5928 goto Fail;
5929 }
5930
5931 /* UNDOCUMENTED! */
5932 /* */
5933 /* The behaviour of an MIAP instruction is quite different when used */
5934 /* in the twilight zone. */
5935 /* */
5936 /* First, no control value cut-in test is performed as it would fail */
5937 /* anyway. Second, the original point, i.e. (org_x,org_y) of */
5938 /* zp0.point, is set to the absolute, unrounded distance found in the */
5939 /* CVT. */
5940 /* */
5941 /* This is used in the CVT programs of the Microsoft fonts Arial, */
5942 /* Times, etc., in order to re-adjust some key font heights. It */
5943 /* allows the use of the IP instruction in the twilight zone, which */
5944 /* otherwise would be invalid according to the specification. */
5945 /* */
5946 /* We implement it with a special sequence for the twilight zone. */
5947 /* This is a bad hack, but it seems to work. */
5948 /* */
5949 /* Confirmed by Greg Hitchcock. */
5950
5951 distance = exc->func_read_cvt( exc, cvtEntry );
5952
5953 if ( exc->GS.gep0 == 0 ) /* If in twilight zone */
5954 {
5955#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5956 /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
5957 /* Determined via experimentation and may be incorrect... */
5958 if ( !( SUBPIXEL_HINTING_INFINALITY &&
5959 ( exc->ignore_x_mode &&
5960 exc->face->sph_compatibility_mode ) ) )
5961#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5962 exc->zp0.org[point].x = TT_MulFix14( distance,
5963 exc->GS.freeVector.x );
5964 exc->zp0.org[point].y = TT_MulFix14( distance,
5965 exc->GS.freeVector.y ),
5966 exc->zp0.cur[point] = exc->zp0.org[point];
5967 }
5968#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5969 if ( SUBPIXEL_HINTING_INFINALITY &&
5970 exc->ignore_x_mode &&
5971 ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
5972 distance > 0 &&
5973 exc->GS.freeVector.y != 0 )
5974 distance = 0;
5975#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5976
5977 org_dist = FAST_PROJECT( &exc->zp0.cur[point] );
5978
5979 if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */
5980 {
5981 if ( FT_ABS( distance - org_dist ) > control_value_cutin )
5982 distance = org_dist;
5983
5984#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5985 if ( SUBPIXEL_HINTING_INFINALITY &&
5986 exc->ignore_x_mode &&
5987 exc->GS.freeVector.x != 0 )
5988 distance = Round_None( exc,
5989 distance,
5990 exc->tt_metrics.compensations[0] );
5991 else
5992#endif
5993 distance = exc->func_round( exc,
5994 distance,
5995 exc->tt_metrics.compensations[0] );
5996 }
5997
5998 exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
5999
6000 Fail:
6001 exc->GS.rp0 = point;
6002 exc->GS.rp1 = point;
6003 }
6004
6005
6006 /*************************************************************************/
6007 /* */
6008 /* MDRP[abcde]: Move Direct Relative Point */
6009 /* Opcode range: 0xC0-0xDF */
6010 /* Stack: uint32 --> */
6011 /* */
6012 static void
6013 Ins_MDRP( TT_ExecContext exc,
6014 FT_Long* args )
6015 {
6016 FT_UShort point = 0;
6017 FT_F26Dot6 org_dist, distance, minimum_distance;
6018
6019
6020 minimum_distance = exc->GS.minimum_distance;
6021
6022#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6023 if ( SUBPIXEL_HINTING_INFINALITY &&
6024 exc->ignore_x_mode &&
6025 exc->GS.freeVector.x != 0 &&
6026 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6027 minimum_distance = 0;
6028#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6029
6030 point = (FT_UShort)args[0];
6031
6032 if ( BOUNDS( point, exc->zp1.n_points ) ||
6033 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6034 {
6035 if ( exc->pedantic_hinting )
6036 exc->error = FT_THROW( Invalid_Reference );
6037 goto Fail;
6038 }
6039
6040 /* XXX: Is there some undocumented feature while in the */
6041 /* twilight zone? */
6042
6043 /* XXX: UNDOCUMENTED: twilight zone special case */
6044
6045 if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )
6046 {
6047 FT_Vector* vec1 = &exc->zp1.org[point];
6048 FT_Vector* vec2 = &exc->zp0.org[exc->GS.rp0];
6049
6050
6051 org_dist = DUALPROJ( vec1, vec2 );
6052 }
6053 else
6054 {
6055 FT_Vector* vec1 = &exc->zp1.orus[point];
6056 FT_Vector* vec2 = &exc->zp0.orus[exc->GS.rp0];
6057
6058
6059 if ( exc->metrics.x_scale == exc->metrics.y_scale )
6060 {
6061 /* this should be faster */
6062 org_dist = DUALPROJ( vec1, vec2 );
6063 org_dist = FT_MulFix( org_dist, exc->metrics.x_scale );
6064 }
6065 else
6066 {
6067 FT_Vector vec;
6068
6069
6070 vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ),
6071 exc->metrics.x_scale );
6072 vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ),
6073 exc->metrics.y_scale );
6074
6075 org_dist = FAST_DUALPROJ( &vec );
6076 }
6077 }
6078
6079 /* single width cut-in test */
6080
6081 /* |org_dist - single_width_value| < single_width_cutin */
6082 if ( exc->GS.single_width_cutin > 0 &&
6083 org_dist < exc->GS.single_width_value +
6084 exc->GS.single_width_cutin &&
6085 org_dist > exc->GS.single_width_value -
6086 exc->GS.single_width_cutin )
6087 {
6088 if ( org_dist >= 0 )
6089 org_dist = exc->GS.single_width_value;
6090 else
6091 org_dist = -exc->GS.single_width_value;
6092 }
6093
6094 /* round flag */
6095
6096 if ( ( exc->opcode & 4 ) != 0 )
6097 {
6098#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6099 if ( SUBPIXEL_HINTING_INFINALITY &&
6100 exc->ignore_x_mode &&
6101 exc->GS.freeVector.x != 0 )
6102 distance = Round_None(
6103 exc,
6104 org_dist,
6105 exc->tt_metrics.compensations[exc->opcode & 3] );
6106 else
6107#endif
6108 distance = exc->func_round(
6109 exc,
6110 org_dist,
6111 exc->tt_metrics.compensations[exc->opcode & 3] );
6112 }
6113 else
6114 distance = Round_None(
6115 exc,
6116 org_dist,
6117 exc->tt_metrics.compensations[exc->opcode & 3] );
6118
6119 /* minimum distance flag */
6120
6121 if ( ( exc->opcode & 8 ) != 0 )
6122 {
6123 if ( org_dist >= 0 )
6124 {
6125 if ( distance < minimum_distance )
6126 distance = minimum_distance;
6127 }
6128 else
6129 {
6130 if ( distance > NEG_LONG( minimum_distance ) )
6131 distance = NEG_LONG( minimum_distance );
6132 }
6133 }
6134
6135 /* now move the point */
6136
6137 org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
6138
6139 exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );
6140
6141 Fail:
6142 exc->GS.rp1 = exc->GS.rp0;
6143 exc->GS.rp2 = point;
6144
6145 if ( ( exc->opcode & 16 ) != 0 )
6146 exc->GS.rp0 = point;
6147 }
6148
6149
6150 /*************************************************************************/
6151 /* */
6152 /* MIRP[abcde]: Move Indirect Relative Point */
6153 /* Opcode range: 0xE0-0xFF */
6154 /* Stack: int32? uint32 --> */
6155 /* */
6156 static void
6157 Ins_MIRP( TT_ExecContext exc,
6158 FT_Long* args )
6159 {
6161 FT_ULong cvtEntry;
6162
6163 FT_F26Dot6 cvt_dist,
6164 distance,
6165 cur_dist,
6166 org_dist,
6167 control_value_cutin,
6168 minimum_distance;
6169#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6170 FT_Int B1 = 0; /* pacify compiler */
6171 FT_Int B2 = 0;
6172 FT_Bool reverse_move = FALSE;
6173#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6174
6175
6176 minimum_distance = exc->GS.minimum_distance;
6177 control_value_cutin = exc->GS.control_value_cutin;
6178 point = (FT_UShort)args[0];
6179 cvtEntry = (FT_ULong)( args[1] + 1 );
6180
6181#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6182 if ( SUBPIXEL_HINTING_INFINALITY &&
6183 exc->ignore_x_mode &&
6184 exc->GS.freeVector.x != 0 &&
6185 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6186 control_value_cutin = minimum_distance = 0;
6187#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6188
6189 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6190
6191 if ( BOUNDS( point, exc->zp1.n_points ) ||
6192 BOUNDSL( cvtEntry, exc->cvtSize + 1 ) ||
6193 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6194 {
6195 if ( exc->pedantic_hinting )
6196 exc->error = FT_THROW( Invalid_Reference );
6197 goto Fail;
6198 }
6199
6200 if ( !cvtEntry )
6201 cvt_dist = 0;
6202 else
6203 cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );
6204
6205 /* single width test */
6206
6207 if ( FT_ABS( cvt_dist - exc->GS.single_width_value ) <
6208 exc->GS.single_width_cutin )
6209 {
6210 if ( cvt_dist >= 0 )
6211 cvt_dist = exc->GS.single_width_value;
6212 else
6213 cvt_dist = -exc->GS.single_width_value;
6214 }
6215
6216 /* UNDOCUMENTED! The MS rasterizer does that with */
6217 /* twilight points (confirmed by Greg Hitchcock) */
6218 if ( exc->GS.gep1 == 0 )
6219 {
6220 exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x +
6221 TT_MulFix14( cvt_dist,
6222 exc->GS.freeVector.x );
6223 exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y +
6224 TT_MulFix14( cvt_dist,
6225 exc->GS.freeVector.y );
6226 exc->zp1.cur[point] = exc->zp1.org[point];
6227 }
6228
6229 org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );
6230 cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );
6231
6232 /* auto-flip test */
6233
6234 if ( exc->GS.auto_flip )
6235 {
6236 if ( ( org_dist ^ cvt_dist ) < 0 )
6237 cvt_dist = -cvt_dist;
6238 }
6239
6240#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6241 if ( SUBPIXEL_HINTING_INFINALITY &&
6242 exc->ignore_x_mode &&
6243 exc->GS.freeVector.y != 0 &&
6244 ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6245 {
6246 if ( cur_dist < -64 )
6247 cvt_dist -= 16;
6248 else if ( cur_dist > 64 && cur_dist < 84 )
6249 cvt_dist += 32;
6250 }
6251#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6252
6253 /* control value cut-in and round */
6254
6255 if ( ( exc->opcode & 4 ) != 0 )
6256 {
6257 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6258 /* refer to the same zone. */
6259
6260 if ( exc->GS.gep0 == exc->GS.gep1 )
6261 {
6262 /* XXX: According to Greg Hitchcock, the following wording is */
6263 /* the right one: */
6264 /* */
6265 /* When the absolute difference between the value in */
6266 /* the table [CVT] and the measurement directly from */
6267 /* the outline is _greater_ than the cut_in value, the */
6268 /* outline measurement is used. */
6269 /* */
6270 /* This is from `instgly.doc'. The description in */
6271 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6272 /* it implies `>=' instead of `>'. */
6273
6274 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6275 cvt_dist = org_dist;
6276 }
6277
6278 distance = exc->func_round(
6279 exc,
6280 cvt_dist,
6281 exc->tt_metrics.compensations[exc->opcode & 3] );
6282 }
6283 else
6284 {
6285
6286#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6287 /* do cvt cut-in always in MIRP for sph */
6288 if ( SUBPIXEL_HINTING_INFINALITY &&
6289 exc->ignore_x_mode &&
6290 exc->GS.gep0 == exc->GS.gep1 )
6291 {
6292 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6293 cvt_dist = org_dist;
6294 }
6295#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6296
6297 distance = Round_None(
6298 exc,
6299 cvt_dist,
6300 exc->tt_metrics.compensations[exc->opcode & 3] );
6301 }
6302
6303 /* minimum distance test */
6304
6305 if ( ( exc->opcode & 8 ) != 0 )
6306 {
6307 if ( org_dist >= 0 )
6308 {
6309 if ( distance < minimum_distance )
6310 distance = minimum_distance;
6311 }
6312 else
6313 {
6314 if ( distance > NEG_LONG( minimum_distance ) )
6315 distance = NEG_LONG( minimum_distance );
6316 }
6317 }
6318
6319#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6320 if ( SUBPIXEL_HINTING_INFINALITY )
6321 {
6322 B1 = exc->zp1.cur[point].y;
6323
6324 /* Round moves if necessary */
6325 if ( exc->ignore_x_mode &&
6326 exc->GS.freeVector.y != 0 &&
6327 ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
6328 distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
6329
6330 if ( exc->ignore_x_mode &&
6331 exc->GS.freeVector.y != 0 &&
6332 ( exc->opcode & 16 ) == 0 &&
6333 ( exc->opcode & 8 ) == 0 &&
6334 ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
6335 distance += 64;
6336 }
6337#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6338
6339 exc->func_move( exc,
6340 &exc->zp1,
6341 point,
6342 SUB_LONG( distance, cur_dist ) );
6343
6344#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6345 if ( SUBPIXEL_HINTING_INFINALITY )
6346 {
6347 B2 = exc->zp1.cur[point].y;
6348
6349 /* Reverse move if necessary */
6350 if ( exc->ignore_x_mode )
6351 {
6352 if ( exc->face->sph_compatibility_mode &&
6353 exc->GS.freeVector.y != 0 &&
6354 ( B1 & 63 ) == 0 &&
6355 ( B2 & 63 ) != 0 )
6356 reverse_move = TRUE;
6357
6358 if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6359 exc->GS.freeVector.y != 0 &&
6360 ( B2 & 63 ) != 0 &&
6361 ( B1 & 63 ) != 0 )
6362 reverse_move = TRUE;
6363 }
6364
6365 if ( reverse_move )
6366 exc->func_move( exc,
6367 &exc->zp1,
6368 point,
6369 SUB_LONG( cur_dist, distance ) );
6370 }
6371
6372#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6373
6374 Fail:
6375 exc->GS.rp1 = exc->GS.rp0;
6376
6377 if ( ( exc->opcode & 16 ) != 0 )
6378 exc->GS.rp0 = point;
6379
6380 exc->GS.rp2 = point;
6381 }
6382
6383
6384 /*************************************************************************/
6385 /* */
6386 /* ALIGNRP[]: ALIGN Relative Point */
6387 /* Opcode range: 0x3C */
6388 /* Stack: uint32 uint32... --> */
6389 /* */
6390 static void
6391 Ins_ALIGNRP( TT_ExecContext exc )
6392 {
6395
6396
6397#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6398 if ( SUBPIXEL_HINTING_INFINALITY &&
6399 exc->ignore_x_mode &&
6400 exc->iup_called &&
6401 ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6402 {
6403 exc->error = FT_THROW( Invalid_Reference );
6404 goto Fail;
6405 }
6406#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6407
6408 if ( exc->top < exc->GS.loop ||
6409 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6410 {
6411 if ( exc->pedantic_hinting )
6412 exc->error = FT_THROW( Invalid_Reference );
6413 goto Fail;
6414 }
6415
6416 while ( exc->GS.loop > 0 )
6417 {
6418 exc->args--;
6419
6420 point = (FT_UShort)exc->stack[exc->args];
6421
6422 if ( BOUNDS( point, exc->zp1.n_points ) )
6423 {
6424 if ( exc->pedantic_hinting )
6425 {
6426 exc->error = FT_THROW( Invalid_Reference );
6427 return;
6428 }
6429 }
6430 else
6431 {
6432 distance = PROJECT( exc->zp1.cur + point,
6433 exc->zp0.cur + exc->GS.rp0 );
6434
6435 exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
6436 }
6437
6438 exc->GS.loop--;
6439 }
6440
6441 Fail:
6442 exc->GS.loop = 1;
6443 exc->new_top = exc->args;
6444 }
6445
6446
6447 /*************************************************************************/
6448 /* */
6449 /* ISECT[]: moves point to InterSECTion */
6450 /* Opcode range: 0x0F */
6451 /* Stack: 5 * uint32 --> */
6452 /* */
6453 static void
6454 Ins_ISECT( TT_ExecContext exc,
6455 FT_Long* args )
6456 {
6458 a0, a1,
6459 b0, b1;
6460
6461 FT_F26Dot6 discriminant, dotproduct;
6462
6463 FT_F26Dot6 dx, dy,
6464 dax, day,
6465 dbx, dby;
6466
6468
6469 FT_Vector R;
6470
6471
6472 point = (FT_UShort)args[0];
6473
6474 a0 = (FT_UShort)args[1];
6475 a1 = (FT_UShort)args[2];
6476 b0 = (FT_UShort)args[3];
6477 b1 = (FT_UShort)args[4];
6478
6479 if ( BOUNDS( b0, exc->zp0.n_points ) ||
6480 BOUNDS( b1, exc->zp0.n_points ) ||
6481 BOUNDS( a0, exc->zp1.n_points ) ||
6482 BOUNDS( a1, exc->zp1.n_points ) ||
6483 BOUNDS( point, exc->zp2.n_points ) )
6484 {
6485 if ( exc->pedantic_hinting )
6486 exc->error = FT_THROW( Invalid_Reference );
6487 return;
6488 }
6489
6490 /* Cramer's rule */
6491
6492 dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x );
6493 dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y );
6494
6495 dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x );
6496 day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y );
6497
6498 dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x );
6499 dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y );
6500
6501 discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ),
6502 FT_MulDiv( day, dbx, 0x40 ) );
6503 dotproduct = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ),
6504 FT_MulDiv( day, dby, 0x40 ) );
6505
6506 /* The discriminant above is actually a cross product of vectors */
6507 /* da and db. Together with the dot product, they can be used as */
6508 /* surrogates for sine and cosine of the angle between the vectors. */
6509 /* Indeed, */
6510 /* dotproduct = |da||db|cos(angle) */
6511 /* discriminant = |da||db|sin(angle) . */
6512 /* We use these equations to reject grazing intersections by */
6513 /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
6514 if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) )
6515 {
6516 val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ),
6517 FT_MulDiv( dy, dbx, 0x40 ) );
6518
6519 R.x = FT_MulDiv( val, dax, discriminant );
6520 R.y = FT_MulDiv( val, day, discriminant );
6521
6522 /* XXX: Block in backward_compatibility and/or post-IUP? */
6523 exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );
6524 exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );
6525 }
6526 else
6527 {
6528 /* else, take the middle of the middles of A and B */
6529
6530 /* XXX: Block in backward_compatibility and/or post-IUP? */
6531 exc->zp2.cur[point].x =
6532 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),
6533 ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;
6534 exc->zp2.cur[point].y =
6535 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),
6536 ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;
6537 }
6538
6540 }
6541
6542
6543 /*************************************************************************/
6544 /* */
6545 /* ALIGNPTS[]: ALIGN PoinTS */
6546 /* Opcode range: 0x27 */
6547 /* Stack: uint32 uint32 --> */
6548 /* */
6549 static void
6550 Ins_ALIGNPTS( TT_ExecContext exc,
6551 FT_Long* args )
6552 {
6553 FT_UShort p1, p2;
6555
6556
6557 p1 = (FT_UShort)args[0];
6558 p2 = (FT_UShort)args[1];
6559
6560 if ( BOUNDS( p1, exc->zp1.n_points ) ||
6561 BOUNDS( p2, exc->zp0.n_points ) )
6562 {
6563 if ( exc->pedantic_hinting )
6564 exc->error = FT_THROW( Invalid_Reference );
6565 return;
6566 }
6567
6568 distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;
6569
6570 exc->func_move( exc, &exc->zp1, p1, distance );
6571 exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );
6572 }
6573
6574
6575 /*************************************************************************/
6576 /* */
6577 /* IP[]: Interpolate Point */
6578 /* Opcode range: 0x39 */
6579 /* Stack: uint32... --> */
6580 /* */
6581
6582 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6583
6584 static void
6585 Ins_IP( TT_ExecContext exc )
6586 {
6587 FT_F26Dot6 old_range, cur_range;
6588 FT_Vector* orus_base;
6589 FT_Vector* cur_base;
6590 FT_Int twilight;
6591
6592
6593 if ( exc->top < exc->GS.loop )
6594 {
6595 if ( exc->pedantic_hinting )
6596 exc->error = FT_THROW( Invalid_Reference );
6597 goto Fail;
6598 }
6599
6600 /*
6601 * We need to deal in a special way with the twilight zone.
6602 * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0),
6603 * for every n.
6604 */
6605 twilight = ( exc->GS.gep0 == 0 ||
6606 exc->GS.gep1 == 0 ||
6607 exc->GS.gep2 == 0 );
6608
6609 if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )
6610 {
6611 if ( exc->pedantic_hinting )
6612 exc->error = FT_THROW( Invalid_Reference );
6613 goto Fail;
6614 }
6615
6616 if ( twilight )
6617 orus_base = &exc->zp0.org[exc->GS.rp1];
6618 else
6619 orus_base = &exc->zp0.orus[exc->GS.rp1];
6620
6621 cur_base = &exc->zp0.cur[exc->GS.rp1];
6622
6623 /* XXX: There are some glyphs in some braindead but popular */
6624 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6625 /* calling IP[] with bad values of rp[12]. */
6626 /* Do something sane when this odd thing happens. */
6627 if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ||
6628 BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )
6629 {
6630 old_range = 0;
6631 cur_range = 0;
6632 }
6633 else
6634 {
6635 if ( twilight )
6636 old_range = DUALPROJ( &exc->zp1.org[exc->GS.rp2], orus_base );
6637 else if ( exc->metrics.x_scale == exc->metrics.y_scale )
6638 old_range = DUALPROJ( &exc->zp1.orus[exc->GS.rp2], orus_base );
6639 else
6640 {
6641 FT_Vector vec;
6642
6643
6644 vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x,
6645 orus_base->x ),
6646 exc->metrics.x_scale );
6647 vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y,
6648 orus_base->y ),
6649 exc->metrics.y_scale );
6650
6651 old_range = FAST_DUALPROJ( &vec );
6652 }
6653
6654 cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base );
6655 }
6656
6657 for ( ; exc->GS.loop > 0; exc->GS.loop-- )
6658 {
6659 FT_UInt point = (FT_UInt)exc->stack[--exc->args];
6660 FT_F26Dot6 org_dist, cur_dist, new_dist;
6661
6662
6663 /* check point bounds */
6664 if ( BOUNDS( point, exc->zp2.n_points ) )
6665 {
6666 if ( exc->pedantic_hinting )
6667 {
6668 exc->error = FT_THROW( Invalid_Reference );
6669 return;
6670 }
6671 continue;
6672 }
6673
6674 if ( twilight )
6675 org_dist = DUALPROJ( &exc->zp2.org[point], orus_base );
6676 else if ( exc->metrics.x_scale == exc->metrics.y_scale )
6677 org_dist = DUALPROJ( &exc->zp2.orus[point], orus_base );
6678 else
6679 {
6680 FT_Vector vec;
6681
6682
6683 vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x,
6684 orus_base->x ),
6685 exc->metrics.x_scale );
6686 vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y,
6687 orus_base->y ),
6688 exc->metrics.y_scale );
6689
6690 org_dist = FAST_DUALPROJ( &vec );
6691 }
6692
6693 cur_dist = PROJECT( &exc->zp2.cur[point], cur_base );
6694
6695 if ( org_dist )
6696 {
6697 if ( old_range )
6698 new_dist = FT_MulDiv( org_dist, cur_range, old_range );
6699 else
6700 {
6701 /* This is the same as what MS does for the invalid case: */
6702 /* */
6703 /* delta = (Original_Pt - Original_RP1) - */
6704 /* (Current_Pt - Current_RP1) ; */
6705 /* */
6706 /* In FreeType speak: */
6707 /* */
6708 /* delta = org_dist - cur_dist . */
6709 /* */
6710 /* We move `point' by `new_dist - cur_dist' after leaving */
6711 /* this block, thus we have */
6712 /* */
6713 /* new_dist - cur_dist = delta , */
6714 /* new_dist - cur_dist = org_dist - cur_dist , */
6715 /* new_dist = org_dist . */
6716
6717 new_dist = org_dist;
6718 }
6719 }
6720 else
6721 new_dist = 0;
6722
6723 exc->func_move( exc,
6724 &exc->zp2,
6726 SUB_LONG( new_dist, cur_dist ) );
6727 }
6728
6729 Fail:
6730 exc->GS.loop = 1;
6731 exc->new_top = exc->args;
6732 }
6733
6734
6735 /*************************************************************************/
6736 /* */
6737 /* UTP[a]: UnTouch Point */
6738 /* Opcode range: 0x29 */
6739 /* Stack: uint32 --> */
6740 /* */
6741 static void
6742 Ins_UTP( TT_ExecContext exc,
6743 FT_Long* args )
6744 {
6746 FT_Byte mask;
6747
6748
6749 point = (FT_UShort)args[0];
6750
6751 if ( BOUNDS( point, exc->zp0.n_points ) )
6752 {
6753 if ( exc->pedantic_hinting )
6754 exc->error = FT_THROW( Invalid_Reference );
6755 return;
6756 }
6757
6758 mask = 0xFF;
6759
6760 if ( exc->GS.freeVector.x != 0 )
6761 mask &= ~FT_CURVE_TAG_TOUCH_X;
6762
6763 if ( exc->GS.freeVector.y != 0 )
6764 mask &= ~FT_CURVE_TAG_TOUCH_Y;
6765
6766 exc->zp0.tags[point] &= mask;
6767 }
6768
6769
6770 /* Local variables for Ins_IUP: */
6771 typedef struct IUP_WorkerRec_
6772 {
6773 FT_Vector* orgs; /* original and current coordinate */
6774 FT_Vector* curs; /* arrays */
6775 FT_Vector* orus;
6776 FT_UInt max_points;
6777
6778 } IUP_WorkerRec, *IUP_Worker;
6779
6780
6781 static void
6782 _iup_worker_shift( IUP_Worker worker,
6783 FT_UInt p1,
6784 FT_UInt p2,
6785 FT_UInt p )
6786 {
6787 FT_UInt i;
6788 FT_F26Dot6 dx;
6789
6790
6791 dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x );
6792 if ( dx != 0 )
6793 {
6794 for ( i = p1; i < p; i++ )
6795 worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );
6796
6797 for ( i = p + 1; i <= p2; i++ )
6798 worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );
6799 }
6800 }
6801
6802
6803 static void
6804 _iup_worker_interpolate( IUP_Worker worker,
6805 FT_UInt p1,
6806 FT_UInt p2,
6807 FT_UInt ref1,
6808 FT_UInt ref2 )
6809 {
6810 FT_UInt i;
6811 FT_F26Dot6 orus1, orus2, org1, org2, cur1, cur2, delta1, delta2;
6812
6813
6814 if ( p1 > p2 )
6815 return;
6816
6817 if ( BOUNDS( ref1, worker->max_points ) ||
6818 BOUNDS( ref2, worker->max_points ) )
6819 return;
6820
6821 orus1 = worker->orus[ref1].x;
6822 orus2 = worker->orus[ref2].x;
6823
6824 if ( orus1 > orus2 )
6825 {
6826 FT_F26Dot6 tmp_o;
6827 FT_UInt tmp_r;
6828
6829
6830 tmp_o = orus1;
6831 orus1 = orus2;
6832 orus2 = tmp_o;
6833
6834 tmp_r = ref1;
6835 ref1 = ref2;
6836 ref2 = tmp_r;
6837 }
6838
6839 org1 = worker->orgs[ref1].x;
6840 org2 = worker->orgs[ref2].x;
6841 cur1 = worker->curs[ref1].x;
6842 cur2 = worker->curs[ref2].x;
6843 delta1 = SUB_LONG( cur1, org1 );
6844 delta2 = SUB_LONG( cur2, org2 );
6845
6846 if ( cur1 == cur2 || orus1 == orus2 )
6847 {
6848
6849 /* trivial snap or shift of untouched points */
6850 for ( i = p1; i <= p2; i++ )
6851 {
6852 FT_F26Dot6 x = worker->orgs[i].x;
6853
6854
6855 if ( x <= org1 )
6856 x = ADD_LONG( x, delta1 );
6857
6858 else if ( x >= org2 )
6859 x = ADD_LONG( x, delta2 );
6860
6861 else
6862 x = cur1;
6863
6864 worker->curs[i].x = x;
6865 }
6866 }
6867 else
6868 {
6869 FT_Fixed scale = 0;
6870 FT_Bool scale_valid = 0;
6871
6872
6873 /* interpolation */
6874 for ( i = p1; i <= p2; i++ )
6875 {
6876 FT_F26Dot6 x = worker->orgs[i].x;
6877
6878
6879 if ( x <= org1 )
6880 x = ADD_LONG( x, delta1 );
6881
6882 else if ( x >= org2 )
6883 x = ADD_LONG( x, delta2 );
6884
6885 else
6886 {
6887 if ( !scale_valid )
6888 {
6889 scale_valid = 1;
6890 scale = FT_DivFix( SUB_LONG( cur2, cur1 ),
6891 SUB_LONG( orus2, orus1 ) );
6892 }
6893
6894 x = ADD_LONG( cur1,
6895 FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),
6896 scale ) );
6897 }
6898 worker->curs[i].x = x;
6899 }
6900 }
6901 }
6902
6903
6904 /*************************************************************************/
6905 /* */
6906 /* IUP[a]: Interpolate Untouched Points */
6907 /* Opcode range: 0x30-0x31 */
6908 /* Stack: --> */
6909 /* */
6910 static void
6911 Ins_IUP( TT_ExecContext exc )
6912 {
6913 IUP_WorkerRec V;
6914 FT_Byte mask;
6915
6916 FT_UInt first_point; /* first point of contour */
6917 FT_UInt end_point; /* end point (last+1) of contour */
6918
6919 FT_UInt first_touched; /* first touched point in contour */
6920 FT_UInt cur_touched; /* current touched point in contour */
6921
6922 FT_UInt point; /* current point */
6923 FT_Short contour; /* current contour */
6924
6925
6926#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
6927 /* See `ttinterp.h' for details on backward compatibility mode. */
6928 /* Allow IUP until it has been called on both axes. Immediately */
6929 /* return on subsequent ones. */
6930 if ( SUBPIXEL_HINTING_MINIMAL &&
6931 exc->backward_compatibility )
6932 {
6933 if ( exc->iupx_called && exc->iupy_called )
6934 return;
6935
6936 if ( exc->opcode & 1 )
6937 exc->iupx_called = TRUE;
6938 else
6939 exc->iupy_called = TRUE;
6940 }
6941#endif
6942
6943 /* ignore empty outlines */
6944 if ( exc->pts.n_contours == 0 )
6945 return;
6946
6947 if ( exc->opcode & 1 )
6948 {
6950 V.orgs = exc->pts.org;
6951 V.curs = exc->pts.cur;
6952 V.orus = exc->pts.orus;
6953 }
6954 else
6955 {
6957 V.orgs = (FT_Vector*)( (FT_Pos*)exc->pts.org + 1 );
6958 V.curs = (FT_Vector*)( (FT_Pos*)exc->pts.cur + 1 );
6959 V.orus = (FT_Vector*)( (FT_Pos*)exc->pts.orus + 1 );
6960 }
6961 V.max_points = exc->pts.n_points;
6962
6963 contour = 0;
6964 point = 0;
6965
6966#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6967 if ( SUBPIXEL_HINTING_INFINALITY &&
6968 exc->ignore_x_mode )
6969 {
6970 exc->iup_called = TRUE;
6971 if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
6972 return;
6973 }
6974#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6975
6976 do
6977 {
6978 end_point = exc->pts.contours[contour] - exc->pts.first_point;
6979 first_point = point;
6980
6981 if ( BOUNDS( end_point, exc->pts.n_points ) )
6982 end_point = exc->pts.n_points - 1;
6983
6984 while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 )
6985 point++;
6986
6987 if ( point <= end_point )
6988 {
6989 first_touched = point;
6990 cur_touched = point;
6991
6992 point++;
6993
6994 while ( point <= end_point )
6995 {
6996 if ( ( exc->pts.tags[point] & mask ) != 0 )
6997 {
6998 _iup_worker_interpolate( &V,
6999 cur_touched + 1,
7000 point - 1,
7001 cur_touched,
7002 point );
7003 cur_touched = point;
7004 }
7005
7006 point++;
7007 }
7008
7009 if ( cur_touched == first_touched )
7010 _iup_worker_shift( &V, first_point, end_point, cur_touched );
7011 else
7012 {
7013 _iup_worker_interpolate( &V,
7014 (FT_UShort)( cur_touched + 1 ),
7015 end_point,
7016 cur_touched,
7017 first_touched );
7018
7019 if ( first_touched > 0 )
7020 _iup_worker_interpolate( &V,
7021 first_point,
7022 first_touched - 1,
7023 cur_touched,
7024 first_touched );
7025 }
7026 }
7027 contour++;
7028 } while ( contour < exc->pts.n_contours );
7029 }
7030
7031
7032 /*************************************************************************/
7033 /* */
7034 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
7035 /* Opcode range: 0x5D,0x71,0x72 */
7036 /* Stack: uint32 (2 * uint32)... --> */
7037 /* */
7038 static void
7039 Ins_DELTAP( TT_ExecContext exc,
7040 FT_Long* args )
7041 {
7042 FT_ULong nump, k;
7043 FT_UShort A;
7044 FT_ULong C, P;
7045 FT_Long B;
7046#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7047 FT_UShort B1, B2;
7048
7049
7050 if ( SUBPIXEL_HINTING_INFINALITY &&
7051 exc->ignore_x_mode &&
7052 exc->iup_called &&
7053 ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7054 goto Fail;
7055#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7056
7057 P = (FT_ULong)exc->func_cur_ppem( exc );
7058 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
7059 than once, thus UShort isn't enough */
7060
7061 for ( k = 1; k <= nump; k++ )
7062 {
7063 if ( exc->args < 2 )
7064 {
7065 if ( exc->pedantic_hinting )
7066 exc->error = FT_THROW( Too_Few_Arguments );
7067 exc->args = 0;
7068 goto Fail;
7069 }
7070
7071 exc->args -= 2;
7072
7073 A = (FT_UShort)exc->stack[exc->args + 1];
7074 B = exc->stack[exc->args];
7075
7076 /* XXX: Because some popular fonts contain some invalid DeltaP */
7077 /* instructions, we simply ignore them when the stacked */
7078 /* point reference is off limit, rather than returning an */
7079 /* error. As a delta instruction doesn't change a glyph */
7080 /* in great ways, this shouldn't be a problem. */
7081
7082 if ( !BOUNDS( A, exc->zp0.n_points ) )
7083 {
7084 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7085
7086 switch ( exc->opcode )
7087 {
7088 case 0x5D:
7089 break;
7090
7091 case 0x71:
7092 C += 16;
7093 break;
7094
7095 case 0x72:
7096 C += 32;
7097 break;
7098 }
7099
7100 C += exc->GS.delta_base;
7101
7102 if ( P == C )
7103 {
7104 B = ( (FT_ULong)B & 0xF ) - 8;
7105 if ( B >= 0 )
7106 B++;
7107 B *= 1L << ( 6 - exc->GS.delta_shift );
7108
7109#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7110
7111 if ( SUBPIXEL_HINTING_INFINALITY )
7112 {
7113 /*
7114 * Allow delta move if
7115 *
7116 * - not using ignore_x_mode rendering,
7117 * - glyph is specifically set to allow it, or
7118 * - glyph is composite and freedom vector is not in subpixel
7119 * direction.
7120 */
7121 if ( !exc->ignore_x_mode ||
7122 ( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
7123 ( exc->is_composite && exc->GS.freeVector.y != 0 ) )
7124 exc->func_move( exc, &exc->zp0, A, B );
7125
7126 /* Otherwise, apply subpixel hinting and compatibility mode */
7127 /* rules, always skipping deltas in subpixel direction. */
7128 else if ( exc->ignore_x_mode && exc->GS.freeVector.y != 0 )
7129 {
7130 /* save the y value of the point now; compare after move */
7131 B1 = (FT_UShort)exc->zp0.cur[A].y;
7132
7133 /* Standard subpixel hinting: Allow y move for y-touched */
7134 /* points. This messes up DejaVu ... */
7135 if ( !exc->face->sph_compatibility_mode &&
7136 ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7137 exc->func_move( exc, &exc->zp0, A, B );
7138
7139 /* compatibility mode */
7140 else if ( exc->face->sph_compatibility_mode &&
7141 !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
7142 {
7143 if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
7144 B = FT_PIX_ROUND( B1 + B ) - B1;
7145
7146 /* Allow delta move if using sph_compatibility_mode, */
7147 /* IUP has not been called, and point is touched on Y. */
7148 if ( !exc->iup_called &&
7149 ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7150 exc->func_move( exc, &exc->zp0, A, B );
7151 }
7152
7153 B2 = (FT_UShort)exc->zp0.cur[A].y;
7154
7155 /* Reverse this move if it results in a disallowed move */
7156 if ( exc->GS.freeVector.y != 0 &&
7157 ( ( exc->face->sph_compatibility_mode &&
7158 ( B1 & 63 ) == 0 &&
7159 ( B2 & 63 ) != 0 ) ||
7160 ( ( exc->sph_tweak_flags &
7161 SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
7162 ( B1 & 63 ) != 0 &&
7163 ( B2 & 63 ) != 0 ) ) )
7164 exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) );
7165 }
7166 }
7167 else
7168#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7169
7170 {
7171
7172#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7173 /* See `ttinterp.h' for details on backward compatibility */
7174 /* mode. */
7175 if ( SUBPIXEL_HINTING_MINIMAL &&
7176 exc->backward_compatibility )
7177 {
7178 if ( !( exc->iupx_called && exc->iupy_called ) &&
7179 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
7180 ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )
7181 exc->func_move( exc, &exc->zp0, A, B );
7182 }
7183 else
7184#endif
7185 exc->func_move( exc, &exc->zp0, A, B );
7186 }
7187 }
7188 }
7189 else
7190 if ( exc->pedantic_hinting )
7191 exc->error = FT_THROW( Invalid_Reference );
7192 }
7193
7194 Fail:
7195 exc->new_top = exc->args;
7196 }
7197
7198
7199 /*************************************************************************/
7200 /* */
7201 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
7202 /* Opcode range: 0x73,0x74,0x75 */
7203 /* Stack: uint32 (2 * uint32)... --> */
7204 /* */
7205 static void
7206 Ins_DELTAC( TT_ExecContext exc,
7207 FT_Long* args )
7208 {
7209 FT_ULong nump, k;
7210 FT_ULong A, C, P;
7211 FT_Long B;
7212
7213
7214 P = (FT_ULong)exc->func_cur_ppem( exc );
7215 nump = (FT_ULong)args[0];
7216
7217 for ( k = 1; k <= nump; k++ )
7218 {
7219 if ( exc->args < 2 )
7220 {
7221 if ( exc->pedantic_hinting )
7222 exc->error = FT_THROW( Too_Few_Arguments );
7223 exc->args = 0;
7224 goto Fail;
7225 }
7226
7227 exc->args -= 2;
7228
7229 A = (FT_ULong)exc->stack[exc->args + 1];
7230 B = exc->stack[exc->args];
7231
7232 if ( BOUNDSL( A, exc->cvtSize ) )
7233 {
7234 if ( exc->pedantic_hinting )
7235 {
7236 exc->error = FT_THROW( Invalid_Reference );
7237 return;
7238 }
7239 }
7240 else
7241 {
7242 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7243
7244 switch ( exc->opcode )
7245 {
7246 case 0x73:
7247 break;
7248
7249 case 0x74:
7250 C += 16;
7251 break;
7252
7253 case 0x75:
7254 C += 32;
7255 break;
7256 }
7257
7258 C += exc->GS.delta_base;
7259
7260 if ( P == C )
7261 {
7262 B = ( (FT_ULong)B & 0xF ) - 8;
7263 if ( B >= 0 )
7264 B++;
7265 B *= 1L << ( 6 - exc->GS.delta_shift );
7266
7267 exc->func_move_cvt( exc, A, B );
7268 }
7269 }
7270 }
7271
7272 Fail:
7273 exc->new_top = exc->args;
7274 }
7275
7276
7277 /*************************************************************************/
7278 /* */
7279 /* MISC. INSTRUCTIONS */
7280 /* */
7281 /*************************************************************************/
7282
7283
7284 /*************************************************************************/
7285 /* */
7286 /* GETINFO[]: GET INFOrmation */
7287 /* Opcode range: 0x88 */
7288 /* Stack: uint32 --> uint32 */
7289 /* */
7290 /* XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May */
7291 /* 2015) not documented in the OpenType specification. */
7292 /* */
7293 /* Selector bit 11 is incorrectly described as bit 8, while the */
7294 /* real meaning of bit 8 (vertical LCD subpixels) stays */
7295 /* undocumented. The same mistake can be found in Greg Hitchcock's */
7296 /* whitepaper. */
7297 /* */
7298 static void
7299 Ins_GETINFO( TT_ExecContext exc,
7300 FT_Long* args )
7301 {
7302 FT_Long K;
7304
7305
7306 K = 0;
7307
7308#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7309 /********************************/
7310 /* RASTERIZER VERSION */
7311 /* Selector Bit: 0 */
7312 /* Return Bit(s): 0-7 */
7313 /* */
7314 if ( SUBPIXEL_HINTING_INFINALITY &&
7315 ( args[0] & 1 ) != 0 &&
7316 exc->subpixel_hinting )
7317 {
7318 if ( exc->ignore_x_mode )
7319 {
7320 /* if in ClearType backward compatibility mode, */
7321 /* we sometimes change the TrueType version dynamically */
7322 K = exc->rasterizer_version;
7323 FT_TRACE6(( "Setting rasterizer version %d\n",
7324 exc->rasterizer_version ));
7325 }
7326 else
7328 }
7329 else
7330#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7331 if ( ( args[0] & 1 ) != 0 )
7332 K = driver->interpreter_version;
7333
7334 /********************************/
7335 /* GLYPH ROTATED */
7336 /* Selector Bit: 1 */
7337 /* Return Bit(s): 8 */
7338 /* */
7339 if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )
7340 K |= 1 << 8;
7341
7342 /********************************/
7343 /* GLYPH STRETCHED */
7344 /* Selector Bit: 2 */
7345 /* Return Bit(s): 9 */
7346 /* */
7347 if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )
7348 K |= 1 << 9;
7349
7350#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7351 /********************************/
7352 /* VARIATION GLYPH */
7353 /* Selector Bit: 3 */
7354 /* Return Bit(s): 10 */
7355 /* */
7356 /* XXX: UNDOCUMENTED! */
7357 if ( (args[0] & 8 ) != 0 && exc->face->blend )
7358 K |= 1 << 10;
7359#endif
7360
7361 /********************************/
7362 /* BI-LEVEL HINTING AND */
7363 /* GRAYSCALE RENDERING */
7364 /* Selector Bit: 5 */
7365 /* Return Bit(s): 12 */
7366 /* */
7367 if ( ( args[0] & 32 ) != 0 && exc->grayscale )
7368 K |= 1 << 12;
7369
7370#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7371 /* Toggle the following flags only outside of monochrome mode. */
7372 /* Otherwise, instructions may behave weirdly and rendering results */
7373 /* may differ between v35 and v40 mode, e.g., in `Times New Roman */
7374 /* Bold Italic'. */
7375 if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
7376 {
7377 /********************************/
7378 /* HINTING FOR SUBPIXEL */
7379 /* Selector Bit: 6 */
7380 /* Return Bit(s): 13 */
7381 /* */
7382 /* v40 does subpixel hinting by default. */
7383 if ( ( args[0] & 64 ) != 0 )
7384 K |= 1 << 13;
7385
7386 /********************************/
7387 /* VERTICAL LCD SUBPIXELS? */
7388 /* Selector Bit: 8 */
7389 /* Return Bit(s): 15 */
7390 /* */
7391 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
7392 K |= 1 << 15;
7393
7394 /********************************/
7395 /* SUBPIXEL POSITIONED? */
7396 /* Selector Bit: 10 */
7397 /* Return Bit(s): 17 */
7398 /* */
7399 /* XXX: FreeType supports it, dependent on what client does? */
7400 if ( ( args[0] & 1024 ) != 0 )
7401 K |= 1 << 17;
7402
7403 /********************************/
7404 /* SYMMETRICAL SMOOTHING */
7405 /* Selector Bit: 11 */
7406 /* Return Bit(s): 18 */
7407 /* */
7408 /* The only smoothing method FreeType supports unless someone sets */
7409 /* FT_LOAD_TARGET_MONO. */
7410 if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
7411 K |= 1 << 18;
7412
7413 /********************************/
7414 /* CLEARTYPE HINTING AND */
7415 /* GRAYSCALE RENDERING */
7416 /* Selector Bit: 12 */
7417 /* Return Bit(s): 19 */
7418 /* */
7419 /* Grayscale rendering is what FreeType does anyway unless someone */
7420 /* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */
7421 if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
7422 K |= 1 << 19;
7423 }
7424#endif
7425
7426#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7427
7428 if ( SUBPIXEL_HINTING_INFINALITY &&
7429 exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7430 {
7431
7432 if ( exc->rasterizer_version >= 37 )
7433 {
7434 /********************************/
7435 /* HINTING FOR SUBPIXEL */
7436 /* Selector Bit: 6 */
7437 /* Return Bit(s): 13 */
7438 /* */
7439 if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
7440 K |= 1 << 13;
7441
7442 /********************************/
7443 /* COMPATIBLE WIDTHS ENABLED */
7444 /* Selector Bit: 7 */
7445 /* Return Bit(s): 14 */
7446 /* */
7447 /* Functionality still needs to be added */
7448 if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
7449 K |= 1 << 14;
7450
7451 /********************************/
7452 /* VERTICAL LCD SUBPIXELS? */
7453 /* Selector Bit: 8 */
7454 /* Return Bit(s): 15 */
7455 /* */
7456 /* Functionality still needs to be added */
7457 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
7458 K |= 1 << 15;
7459
7460 /********************************/
7461 /* HINTING FOR BGR? */
7462 /* Selector Bit: 9 */
7463 /* Return Bit(s): 16 */
7464 /* */
7465 /* Functionality still needs to be added */
7466 if ( ( args[0] & 512 ) != 0 && exc->bgr )
7467 K |= 1 << 16;
7468
7469 if ( exc->rasterizer_version >= 38 )
7470 {
7471 /********************************/
7472 /* SUBPIXEL POSITIONED? */
7473 /* Selector Bit: 10 */
7474 /* Return Bit(s): 17 */
7475 /* */
7476 /* Functionality still needs to be added */
7477 if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
7478 K |= 1 << 17;
7479
7480 /********************************/
7481 /* SYMMETRICAL SMOOTHING */
7482 /* Selector Bit: 11 */
7483 /* Return Bit(s): 18 */
7484 /* */
7485 /* Functionality still needs to be added */
7486 if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
7487 K |= 1 << 18;
7488
7489 /********************************/
7490 /* GRAY CLEARTYPE */
7491 /* Selector Bit: 12 */
7492 /* Return Bit(s): 19 */
7493 /* */
7494 /* Functionality still needs to be added */
7495 if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
7496 K |= 1 << 19;
7497 }
7498 }
7499 }
7500
7501#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7502
7503 args[0] = K;
7504 }
7505
7506
7507#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7508
7509 /*************************************************************************/
7510 /* */
7511 /* GETVARIATION[]: get normalized variation (blend) coordinates */
7512 /* Opcode range: 0x91 */
7513 /* Stack: --> f2.14... */
7514 /* */
7515 /* XXX: UNDOCUMENTED! There is no official documentation from Apple for */
7516 /* this bytecode instruction. Active only if a font has GX */
7517 /* variation axes. */
7518 /* */
7519 static void
7520 Ins_GETVARIATION( TT_ExecContext exc,
7521 FT_Long* args )
7522 {
7523 FT_UInt num_axes = exc->face->blend->num_axis;
7524 FT_Fixed* coords = exc->face->blend->normalizedcoords;
7525
7526 FT_UInt i;
7527
7528
7529 if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) )
7530 {
7531 exc->error = FT_THROW( Stack_Overflow );
7532 return;
7533 }
7534
7535 for ( i = 0; i < num_axes; i++ )
7536 args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
7537 }
7538
7539
7540 /*************************************************************************/
7541 /* */
7542 /* GETDATA[]: no idea what this is good for */
7543 /* Opcode range: 0x92 */
7544 /* Stack: --> 17 */
7545 /* */
7546 /* XXX: UNDOCUMENTED! There is no documentation from Apple for this */
7547 /* very weird bytecode instruction. */
7548 /* */
7549 static void
7550 Ins_GETDATA( FT_Long* args )
7551 {
7552 args[0] = 17;
7553 }
7554
7555#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
7556
7557
7558 static void
7559 Ins_UNKNOWN( TT_ExecContext exc )
7560 {
7561 TT_DefRecord* def = exc->IDefs;
7562 TT_DefRecord* limit = def + exc->numIDefs;
7563
7564
7565 for ( ; def < limit; def++ )
7566 {
7567 if ( (FT_Byte)def->opc == exc->opcode && def->active )
7568 {
7569 TT_CallRec* call;
7570
7571
7572 if ( exc->callTop >= exc->callSize )
7573 {
7574 exc->error = FT_THROW( Stack_Overflow );
7575 return;
7576 }
7577
7578 call = exc->callStack + exc->callTop++;
7579
7580 call->Caller_Range = exc->curRange;
7581 call->Caller_IP = exc->IP + 1;
7582 call->Cur_Count = 1;
7583 call->Def = def;
7584
7585 Ins_Goto_CodeRange( exc, def->range, def->start );
7586
7587 exc->step_ins = FALSE;
7588 return;
7589 }
7590 }
7591
7592 exc->error = FT_THROW( Invalid_Opcode );
7593 }
7594
7595
7596 /*************************************************************************/
7597 /* */
7598 /* RUN */
7599 /* */
7600 /* This function executes a run of opcodes. It will exit in the */
7601 /* following cases: */
7602 /* */
7603 /* - Errors (in which case it returns FALSE). */
7604 /* */
7605 /* - Reaching the end of the main code range (returns TRUE). */
7606 /* Reaching the end of a code range within a function call is an */
7607 /* error. */
7608 /* */
7609 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7610 /* is set to TRUE (returns TRUE). */
7611 /* */
7612 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7613 /* an instruction trap or a normal termination. */
7614 /* */
7615 /* */
7616 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7617 /* behaviour is unsupported; here a DEBUG opcode is always an */
7618 /* error. */
7619 /* */
7620 /* */
7621 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7622 /* */
7623 /*************************************************************************/
7624
7625
7626 /* documentation is in ttinterp.h */
7627
7630 {
7631 FT_ULong ins_counter = 0; /* executed instructions counter */
7632 FT_ULong num_twilight_points;
7633 FT_UShort i;
7634
7635#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7636 FT_Byte opcode_pattern[1][2] = {
7637 /* #8 TypeMan Talk Align */
7638 {
7639 0x06, /* SPVTL */
7640 0x7D, /* RDTG */
7641 },
7642 };
7643 FT_UShort opcode_patterns = 1;
7644 FT_UShort opcode_pointer[1] = { 0 };
7645 FT_UShort opcode_size[1] = { 1 };
7646#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7647
7648
7649#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7650 exc->iup_called = FALSE;
7651#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7652
7653#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7654 /*
7655 * Toggle backward compatibility according to what font wants, except
7656 * when
7657 *
7658 * 1) we have a `tricky' font that heavily relies on the interpreter to
7659 * render glyphs correctly, for example DFKai-SB, or
7660 * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested.
7661 *
7662 * In those cases, backward compatibility needs to be turned off to get
7663 * correct rendering. The rendering is then completely up to the
7664 * font's programming.
7665 *
7666 */
7667 if ( SUBPIXEL_HINTING_MINIMAL &&
7668 exc->subpixel_hinting_lean &&
7669 !FT_IS_TRICKY( &exc->face->root ) )
7670 exc->backward_compatibility = !( exc->GS.instruct_control & 4 );
7671 else
7672 exc->backward_compatibility = FALSE;
7673
7674 exc->iupx_called = FALSE;
7675 exc->iupy_called = FALSE;
7676#endif
7677
7678 /* We restrict the number of twilight points to a reasonable, */
7679 /* heuristic value to avoid slow execution of malformed bytecode. */
7680 num_twilight_points = FT_MAX( 30,
7681 2 * ( exc->pts.n_points + exc->cvtSize ) );
7682 if ( exc->twilight.n_points > num_twilight_points )
7683 {
7684 if ( num_twilight_points > 0xFFFFU )
7685 num_twilight_points = 0xFFFFU;
7686
7687 FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n"
7688 " from %d to the more reasonable value %d\n",
7689 exc->twilight.n_points,
7690 num_twilight_points ));
7691 exc->twilight.n_points = (FT_UShort)num_twilight_points;
7692 }
7693
7694 /* Set up loop detectors. We restrict the number of LOOPCALL loops */
7695 /* and the number of JMPR, JROT, and JROF calls with a negative */
7696 /* argument to values that depend on various parameters like the */
7697 /* size of the CVT table or the number of points in the current */
7698 /* glyph (if applicable). */
7699 /* */
7700 /* The idea is that in real-world bytecode you either iterate over */
7701 /* all CVT entries (in the `prep' table), or over all points (or */
7702 /* contours, in the `glyf' table) of a glyph, and such iterations */
7703 /* don't happen very often. */
7704 exc->loopcall_counter = 0;
7705 exc->neg_jump_counter = 0;
7706
7707 /* The maximum values are heuristic. */
7708 if ( exc->pts.n_points )
7709 exc->loopcall_counter_max = FT_MAX( 50,
7710 10 * exc->pts.n_points ) +
7711 FT_MAX( 50,
7712 exc->cvtSize / 10 );
7713 else
7714 exc->loopcall_counter_max = 300 + 8 * exc->cvtSize;
7715
7716 /* as a protection against an unreasonable number of CVT entries */
7717 /* we assume at most 100 control values per glyph for the counter */
7718 if ( exc->loopcall_counter_max >
7719 100 * (FT_ULong)exc->face->root.num_glyphs )
7720 exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs;
7721
7722 FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"
7723 " to %d\n", exc->loopcall_counter_max ));
7724
7726 FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"
7727 " to %d\n", exc->neg_jump_counter_max ));
7728
7729 /* set PPEM and CVT functions */
7730 exc->tt_metrics.ratio = 0;
7731 if ( exc->metrics.x_ppem != exc->metrics.y_ppem )
7732 {
7733 /* non-square pixels, use the stretched routines */
7734 exc->func_cur_ppem = Current_Ppem_Stretched;
7735 exc->func_read_cvt = Read_CVT_Stretched;
7736 exc->func_write_cvt = Write_CVT_Stretched;
7737 exc->func_move_cvt = Move_CVT_Stretched;
7738 }
7739 else
7740 {
7741 /* square pixels, use normal routines */
7742 exc->func_cur_ppem = Current_Ppem;
7743 exc->func_read_cvt = Read_CVT;
7744 exc->func_write_cvt = Write_CVT;
7745 exc->func_move_cvt = Move_CVT;
7746 }
7747
7748 Compute_Funcs( exc );
7749 Compute_Round( exc, (FT_Byte)exc->GS.round_state );
7750
7751 do
7752 {
7753 exc->opcode = exc->code[exc->IP];
7754
7755#ifdef FT_DEBUG_LEVEL_TRACE
7756 {
7757 FT_Long cnt = FT_MIN( 8, exc->top );
7758 FT_Long n;
7759
7760
7761 /* if tracing level is 7, show current code position */
7762 /* and the first few stack elements also */
7763 FT_TRACE6(( " " ));
7764 FT_TRACE7(( "%06d ", exc->IP ));
7765 FT_TRACE6(( opcode_name[exc->opcode] + 2 ));
7766 FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'
7767 ? 2
7768 : 12 - ( *opcode_name[exc->opcode] - '0' ),
7769 "#" ));
7770 for ( n = 1; n <= cnt; n++ )
7771 FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
7772 FT_TRACE6(( "\n" ));
7773 }
7774#endif /* FT_DEBUG_LEVEL_TRACE */
7775
7776 if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
7777 {
7778 if ( exc->IP + 1 >= exc->codeSize )
7779 goto LErrorCodeOverflow_;
7780
7781 exc->length = 2 - exc->length * exc->code[exc->IP + 1];
7782 }
7783
7784 if ( exc->IP + exc->length > exc->codeSize )
7785 goto LErrorCodeOverflow_;
7786
7787 /* First, let's check for empty stack and overflow */
7788 exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 );
7789
7790 /* `args' is the top of the stack once arguments have been popped. */
7791 /* One can also interpret it as the index of the last argument. */
7792 if ( exc->args < 0 )
7793 {
7794 if ( exc->pedantic_hinting )
7795 {
7796 exc->error = FT_THROW( Too_Few_Arguments );
7797 goto LErrorLabel_;
7798 }
7799
7800 /* push zeroes onto the stack */
7801 for ( i = 0; i < Pop_Push_Count[exc->opcode] >> 4; i++ )
7802 exc->stack[i] = 0;
7803 exc->args = 0;
7804 }
7805
7806#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7807 if ( exc->opcode == 0x91 )
7808 {
7809 /* this is very special: GETVARIATION returns */
7810 /* a variable number of arguments */
7811
7812 /* it is the job of the application to `activate' GX handling, */
7813 /* this is, calling any of the GX API functions on the current */
7814 /* font to select a variation instance */
7815 if ( exc->face->blend )
7816 exc->new_top = exc->args + exc->face->blend->num_axis;
7817 }
7818 else
7819#endif
7820 exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 );
7821
7822 /* `new_top' is the new top of the stack, after the instruction's */
7823 /* execution. `top' will be set to `new_top' after the `switch' */
7824 /* statement. */
7825 if ( exc->new_top > exc->stackSize )
7826 {
7827 exc->error = FT_THROW( Stack_Overflow );
7828 goto LErrorLabel_;
7829 }
7830
7831 exc->step_ins = TRUE;
7832 exc->error = FT_Err_Ok;
7833
7834#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7835
7836 if ( SUBPIXEL_HINTING_INFINALITY )
7837 {
7838 for ( i = 0; i < opcode_patterns; i++ )
7839 {
7840 if ( opcode_pointer[i] < opcode_size[i] &&
7841 exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
7842 {
7843 opcode_pointer[i] += 1;
7844
7845 if ( opcode_pointer[i] == opcode_size[i] )
7846 {
7847 FT_TRACE6(( "sph: opcode ptrn: %d, %s %s\n",
7848 i,
7849 exc->face->root.family_name,
7850 exc->face->root.style_name ));
7851
7852 switch ( i )
7853 {
7854 case 0:
7855 break;
7856 }
7857 opcode_pointer[i] = 0;
7858 }
7859 }
7860 else
7861 opcode_pointer[i] = 0;
7862 }
7863 }
7864
7865#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7866
7867 {
7868 FT_Long* args = exc->stack + exc->args;
7869 FT_Byte opcode = exc->opcode;
7870
7871
7872 switch ( opcode )
7873 {
7874 case 0x00: /* SVTCA y */
7875 case 0x01: /* SVTCA x */
7876 case 0x02: /* SPvTCA y */
7877 case 0x03: /* SPvTCA x */
7878 case 0x04: /* SFvTCA y */
7879 case 0x05: /* SFvTCA x */
7880 Ins_SxyTCA( exc );
7881 break;
7882
7883 case 0x06: /* SPvTL // */
7884 case 0x07: /* SPvTL + */
7885 Ins_SPVTL( exc, args );
7886 break;
7887
7888 case 0x08: /* SFvTL // */
7889 case 0x09: /* SFvTL + */
7890 Ins_SFVTL( exc, args );
7891 break;
7892
7893 case 0x0A: /* SPvFS */
7894 Ins_SPVFS( exc, args );
7895 break;
7896
7897 case 0x0B: /* SFvFS */
7898 Ins_SFVFS( exc, args );
7899 break;
7900
7901 case 0x0C: /* GPv */
7902 Ins_GPV( exc, args );
7903 break;
7904
7905 case 0x0D: /* GFv */
7906 Ins_GFV( exc, args );
7907 break;
7908
7909 case 0x0E: /* SFvTPv */
7910 Ins_SFVTPV( exc );
7911 break;
7912
7913 case 0x0F: /* ISECT */
7914 Ins_ISECT( exc, args );
7915 break;
7916
7917 case 0x10: /* SRP0 */
7918 Ins_SRP0( exc, args );
7919 break;
7920
7921 case 0x11: /* SRP1 */
7922 Ins_SRP1( exc, args );
7923 break;
7924
7925 case 0x12: /* SRP2 */
7926 Ins_SRP2( exc, args );
7927 break;
7928
7929 case 0x13: /* SZP0 */
7930 Ins_SZP0( exc, args );
7931 break;
7932
7933 case 0x14: /* SZP1 */
7934 Ins_SZP1( exc, args );
7935 break;
7936
7937 case 0x15: /* SZP2 */
7938 Ins_SZP2( exc, args );
7939 break;
7940
7941 case 0x16: /* SZPS */
7942 Ins_SZPS( exc, args );
7943 break;
7944
7945 case 0x17: /* SLOOP */
7946 Ins_SLOOP( exc, args );
7947 break;
7948
7949 case 0x18: /* RTG */
7950 Ins_RTG( exc );
7951 break;
7952
7953 case 0x19: /* RTHG */
7954 Ins_RTHG( exc );
7955 break;
7956
7957 case 0x1A: /* SMD */
7958 Ins_SMD( exc, args );
7959 break;
7960
7961 case 0x1B: /* ELSE */
7962 Ins_ELSE( exc );
7963 break;
7964
7965 case 0x1C: /* JMPR */
7966 Ins_JMPR( exc, args );
7967 break;
7968
7969 case 0x1D: /* SCVTCI */
7970 Ins_SCVTCI( exc, args );
7971 break;
7972
7973 case 0x1E: /* SSWCI */
7974 Ins_SSWCI( exc, args );
7975 break;
7976
7977 case 0x1F: /* SSW */
7978 Ins_SSW( exc, args );
7979 break;
7980
7981 case 0x20: /* DUP */
7982 Ins_DUP( args );
7983 break;
7984
7985 case 0x21: /* POP */
7986 Ins_POP();
7987 break;
7988
7989 case 0x22: /* CLEAR */
7990 Ins_CLEAR( exc );
7991 break;
7992
7993 case 0x23: /* SWAP */
7994 Ins_SWAP( args );
7995 break;
7996
7997 case 0x24: /* DEPTH */
7998 Ins_DEPTH( exc, args );
7999 break;
8000
8001 case 0x25: /* CINDEX */
8002 Ins_CINDEX( exc, args );
8003 break;
8004
8005 case 0x26: /* MINDEX */
8006 Ins_MINDEX( exc, args );
8007 break;
8008
8009 case 0x27: /* ALIGNPTS */
8010 Ins_ALIGNPTS( exc, args );
8011 break;
8012
8013 case 0x28: /* RAW */
8014 Ins_UNKNOWN( exc );
8015 break;
8016
8017 case 0x29: /* UTP */
8018 Ins_UTP( exc, args );
8019 break;
8020
8021 case 0x2A: /* LOOPCALL */
8022 Ins_LOOPCALL( exc, args );
8023 break;
8024
8025 case 0x2B: /* CALL */
8026 Ins_CALL( exc, args );
8027 break;
8028
8029 case 0x2C: /* FDEF */
8030 Ins_FDEF( exc, args );
8031 break;
8032
8033 case 0x2D: /* ENDF */
8034 Ins_ENDF( exc );
8035 break;
8036
8037 case 0x2E: /* MDAP */
8038 case 0x2F: /* MDAP */
8039 Ins_MDAP( exc, args );
8040 break;
8041
8042 case 0x30: /* IUP */
8043 case 0x31: /* IUP */
8044 Ins_IUP( exc );
8045 break;
8046
8047 case 0x32: /* SHP */
8048 case 0x33: /* SHP */
8049 Ins_SHP( exc );
8050 break;
8051
8052 case 0x34: /* SHC */
8053 case 0x35: /* SHC */
8054 Ins_SHC( exc, args );
8055 break;
8056
8057 case 0x36: /* SHZ */
8058 case 0x37: /* SHZ */
8059 Ins_SHZ( exc, args );
8060 break;
8061
8062 case 0x38: /* SHPIX */
8063 Ins_SHPIX( exc, args );
8064 break;
8065
8066 case 0x39: /* IP */
8067 Ins_IP( exc );
8068 break;
8069
8070 case 0x3A: /* MSIRP */
8071 case 0x3B: /* MSIRP */
8072 Ins_MSIRP( exc, args );
8073 break;
8074
8075 case 0x3C: /* AlignRP */
8076 Ins_ALIGNRP( exc );
8077 break;
8078
8079 case 0x3D: /* RTDG */
8080 Ins_RTDG( exc );
8081 break;
8082
8083 case 0x3E: /* MIAP */
8084 case 0x3F: /* MIAP */
8085 Ins_MIAP( exc, args );
8086 break;
8087
8088 case 0x40: /* NPUSHB */
8089 Ins_NPUSHB( exc, args );
8090 break;
8091
8092 case 0x41: /* NPUSHW */
8093 Ins_NPUSHW( exc, args );
8094 break;
8095
8096 case 0x42: /* WS */
8097 Ins_WS( exc, args );
8098 break;
8099
8100 case 0x43: /* RS */
8101 Ins_RS( exc, args );
8102 break;
8103
8104 case 0x44: /* WCVTP */
8105 Ins_WCVTP( exc, args );
8106 break;
8107
8108 case 0x45: /* RCVT */
8109 Ins_RCVT( exc, args );
8110 break;
8111
8112 case 0x46: /* GC */
8113 case 0x47: /* GC */
8114 Ins_GC( exc, args );
8115 break;
8116
8117 case 0x48: /* SCFS */
8118 Ins_SCFS( exc, args );
8119 break;
8120
8121 case 0x49: /* MD */
8122 case 0x4A: /* MD */
8123 Ins_MD( exc, args );
8124 break;
8125
8126 case 0x4B: /* MPPEM */
8127 Ins_MPPEM( exc, args );
8128 break;
8129
8130 case 0x4C: /* MPS */
8131 Ins_MPS( exc, args );
8132 break;
8133
8134 case 0x4D: /* FLIPON */
8135 Ins_FLIPON( exc );
8136 break;
8137
8138 case 0x4E: /* FLIPOFF */
8139 Ins_FLIPOFF( exc );
8140 break;
8141
8142 case 0x4F: /* DEBUG */
8143 Ins_DEBUG( exc );
8144 break;
8145
8146 case 0x50: /* LT */
8147 Ins_LT( args );
8148 break;
8149
8150 case 0x51: /* LTEQ */
8151 Ins_LTEQ( args );
8152 break;
8153
8154 case 0x52: /* GT */
8155 Ins_GT( args );
8156 break;
8157
8158 case 0x53: /* GTEQ */
8159 Ins_GTEQ( args );
8160 break;
8161
8162 case 0x54: /* EQ */
8163 Ins_EQ( args );
8164 break;
8165
8166 case 0x55: /* NEQ */
8167 Ins_NEQ( args );
8168 break;
8169
8170 case 0x56: /* ODD */
8171 Ins_ODD( exc, args );
8172 break;
8173
8174 case 0x57: /* EVEN */
8175 Ins_EVEN( exc, args );
8176 break;
8177
8178 case 0x58: /* IF */
8179 Ins_IF( exc, args );
8180 break;
8181
8182 case 0x59: /* EIF */
8183 Ins_EIF();
8184 break;
8185
8186 case 0x5A: /* AND */
8187 Ins_AND( args );
8188 break;
8189
8190 case 0x5B: /* OR */
8191 Ins_OR( args );
8192 break;
8193
8194 case 0x5C: /* NOT */
8195 Ins_NOT( args );
8196 break;
8197
8198 case 0x5D: /* DELTAP1 */
8199 Ins_DELTAP( exc, args );
8200 break;
8201
8202 case 0x5E: /* SDB */
8203 Ins_SDB( exc, args );
8204 break;
8205
8206 case 0x5F: /* SDS */
8207 Ins_SDS( exc, args );
8208 break;
8209
8210 case 0x60: /* ADD */
8211 Ins_ADD( args );
8212 break;
8213
8214 case 0x61: /* SUB */
8215 Ins_SUB( args );
8216 break;
8217
8218 case 0x62: /* DIV */
8219 Ins_DIV( exc, args );
8220 break;
8221
8222 case 0x63: /* MUL */
8223 Ins_MUL( args );
8224 break;
8225
8226 case 0x64: /* ABS */
8227 Ins_ABS( args );
8228 break;
8229
8230 case 0x65: /* NEG */
8231 Ins_NEG( args );
8232 break;
8233
8234 case 0x66: /* FLOOR */
8235 Ins_FLOOR( args );
8236 break;
8237
8238 case 0x67: /* CEILING */
8239 Ins_CEILING( args );
8240 break;
8241
8242 case 0x68: /* ROUND */
8243 case 0x69: /* ROUND */
8244 case 0x6A: /* ROUND */
8245 case 0x6B: /* ROUND */
8246 Ins_ROUND( exc, args );
8247 break;
8248
8249 case 0x6C: /* NROUND */
8250 case 0x6D: /* NROUND */
8251 case 0x6E: /* NRRUND */
8252 case 0x6F: /* NROUND */
8253 Ins_NROUND( exc, args );
8254 break;
8255
8256 case 0x70: /* WCVTF */
8257 Ins_WCVTF( exc, args );
8258 break;
8259
8260 case 0x71: /* DELTAP2 */
8261 case 0x72: /* DELTAP3 */
8262 Ins_DELTAP( exc, args );
8263 break;
8264
8265 case 0x73: /* DELTAC0 */
8266 case 0x74: /* DELTAC1 */
8267 case 0x75: /* DELTAC2 */
8268 Ins_DELTAC( exc, args );
8269 break;
8270
8271 case 0x76: /* SROUND */
8272 Ins_SROUND( exc, args );
8273 break;
8274
8275 case 0x77: /* S45Round */
8276 Ins_S45ROUND( exc, args );
8277 break;
8278
8279 case 0x78: /* JROT */
8280 Ins_JROT( exc, args );
8281 break;
8282
8283 case 0x79: /* JROF */
8284 Ins_JROF( exc, args );
8285 break;
8286
8287 case 0x7A: /* ROFF */
8288 Ins_ROFF( exc );
8289 break;
8290
8291 case 0x7B: /* ???? */
8292 Ins_UNKNOWN( exc );
8293 break;
8294
8295 case 0x7C: /* RUTG */
8296 Ins_RUTG( exc );
8297 break;
8298
8299 case 0x7D: /* RDTG */
8300 Ins_RDTG( exc );
8301 break;
8302
8303 case 0x7E: /* SANGW */
8304 Ins_SANGW();
8305 break;
8306
8307 case 0x7F: /* AA */
8308 Ins_AA();
8309 break;
8310
8311 case 0x80: /* FLIPPT */
8312 Ins_FLIPPT( exc );
8313 break;
8314
8315 case 0x81: /* FLIPRGON */
8316 Ins_FLIPRGON( exc, args );
8317 break;
8318
8319 case 0x82: /* FLIPRGOFF */
8320 Ins_FLIPRGOFF( exc, args );
8321 break;
8322
8323 case 0x83: /* UNKNOWN */
8324 case 0x84: /* UNKNOWN */
8325 Ins_UNKNOWN( exc );
8326 break;
8327
8328 case 0x85: /* SCANCTRL */
8329 Ins_SCANCTRL( exc, args );
8330 break;
8331
8332 case 0x86: /* SDPvTL */
8333 case 0x87: /* SDPvTL */
8334 Ins_SDPVTL( exc, args );
8335 break;
8336
8337 case 0x88: /* GETINFO */
8338 Ins_GETINFO( exc, args );
8339 break;
8340
8341 case 0x89: /* IDEF */
8342 Ins_IDEF( exc, args );
8343 break;
8344
8345 case 0x8A: /* ROLL */
8346 Ins_ROLL( args );
8347 break;
8348
8349 case 0x8B: /* MAX */
8350 Ins_MAX( args );
8351 break;
8352
8353 case 0x8C: /* MIN */
8354 Ins_MIN( args );
8355 break;
8356
8357 case 0x8D: /* SCANTYPE */
8358 Ins_SCANTYPE( exc, args );
8359 break;
8360
8361 case 0x8E: /* INSTCTRL */
8362 Ins_INSTCTRL( exc, args );
8363 break;
8364
8365 case 0x8F: /* ADJUST */
8366 case 0x90: /* ADJUST */
8367 Ins_UNKNOWN( exc );
8368 break;
8369
8370#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
8371 case 0x91:
8372 /* it is the job of the application to `activate' GX handling, */
8373 /* this is, calling any of the GX API functions on the current */
8374 /* font to select a variation instance */
8375 if ( exc->face->blend )
8376 Ins_GETVARIATION( exc, args );
8377 else
8378 Ins_UNKNOWN( exc );
8379 break;
8380
8381 case 0x92:
8382 /* there is at least one MS font (LaoUI.ttf version 5.01) that */
8383 /* uses IDEFs for 0x91 and 0x92; for this reason we activate */
8384 /* GETDATA for GX fonts only, similar to GETVARIATION */
8385 if ( exc->face->blend )
8386 Ins_GETDATA( args );
8387 else
8388 Ins_UNKNOWN( exc );
8389 break;
8390#endif
8391
8392 default:
8393 if ( opcode >= 0xE0 )
8394 Ins_MIRP( exc, args );
8395 else if ( opcode >= 0xC0 )
8396 Ins_MDRP( exc, args );
8397 else if ( opcode >= 0xB8 )
8398 Ins_PUSHW( exc, args );
8399 else if ( opcode >= 0xB0 )
8400 Ins_PUSHB( exc, args );
8401 else
8402 Ins_UNKNOWN( exc );
8403 }
8404 }
8405
8406 if ( exc->error )
8407 {
8408 switch ( exc->error )
8409 {
8410 /* looking for redefined instructions */
8411 case FT_ERR( Invalid_Opcode ):
8412 {
8413 TT_DefRecord* def = exc->IDefs;
8414 TT_DefRecord* limit = def + exc->numIDefs;
8415
8416
8417 for ( ; def < limit; def++ )
8418 {
8419 if ( def->active && exc->opcode == (FT_Byte)def->opc )
8420 {
8421 TT_CallRec* callrec;
8422
8423
8424 if ( exc->callTop >= exc->callSize )
8425 {
8426 exc->error = FT_THROW( Invalid_Reference );
8427 goto LErrorLabel_;
8428 }
8429
8430 callrec = &exc->callStack[exc->callTop];
8431
8432 callrec->Caller_Range = exc->curRange;
8433 callrec->Caller_IP = exc->IP + 1;
8434 callrec->Cur_Count = 1;
8435 callrec->Def = def;
8436
8437 if ( Ins_Goto_CodeRange( exc,
8438 def->range,
8439 def->start ) == FAILURE )
8440 goto LErrorLabel_;
8441
8442 goto LSuiteLabel_;
8443 }
8444 }
8445 }
8446
8447 exc->error = FT_THROW( Invalid_Opcode );
8448 goto LErrorLabel_;
8449
8450#if 0
8451 break; /* Unreachable code warning suppression. */
8452 /* Leave to remind in case a later change the editor */
8453 /* to consider break; */
8454#endif
8455
8456 default:
8457 goto LErrorLabel_;
8458
8459#if 0
8460 break;
8461#endif
8462 }
8463 }
8464
8465 exc->top = exc->new_top;
8466
8467 if ( exc->step_ins )
8468 exc->IP += exc->length;
8469
8470 /* increment instruction counter and check if we didn't */
8471 /* run this program for too long (e.g. infinite loops). */
8472 if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
8473 return FT_THROW( Execution_Too_Long );
8474
8475 LSuiteLabel_:
8476 if ( exc->IP >= exc->codeSize )
8477 {
8478 if ( exc->callTop > 0 )
8479 {
8480 exc->error = FT_THROW( Code_Overflow );
8481 goto LErrorLabel_;
8482 }
8483 else
8484 goto LNo_Error_;
8485 }
8486 } while ( !exc->instruction_trap );
8487
8488 LNo_Error_:
8489 FT_TRACE4(( " %d instruction%s executed\n",
8490 ins_counter == 1 ? "" : "s",
8491 ins_counter ));
8492 return FT_Err_Ok;
8493
8494 LErrorCodeOverflow_:
8495 exc->error = FT_THROW( Code_Overflow );
8496
8497 LErrorLabel_:
8498 if ( exc->error && !exc->instruction_trap )
8499 FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error ));
8500
8501 return exc->error;
8502 }
8503
8504#else /* !TT_USE_BYTECODE_INTERPRETER */
8505
8506 /* ANSI C doesn't like empty source files */
8507 typedef int _tt_interp_dummy;
8508
8509#endif /* !TT_USE_BYTECODE_INTERPRETER */
8510
8511
8512/* END */
@ GS
Definition: amd64_sup.c:16
struct _BOUNDS BOUNDS
#define D(d)
Definition: builtin.c:4557
#define C(c)
Definition: builtin.c:4556
r l[0]
Definition: byte_order.h:168
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
Definition: ehthrow.cxx:93
Definition: ehthrow.cxx:54
Definition: terminate.cpp:24
#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES
Definition: ftoption.h:688
@ Out
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define __attribute__(x)
Definition: wpp_private.h:207
WORD face[3]
Definition: mesh.c:4747
unsigned int idx
Definition: utils.c:41
#define Y(I)
#define P(row, col)
#define A(row, col)
#define B(row, col)
static DOUBLE day(DOUBLE time)
Definition: date.c:117
#define noinline
Definition: types.h:64
POINTL point
Definition: edittest.c:50
int Fail
Definition: ehthrow.cxx:24
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
#define FT_IS_TRICKY(face)
Definition: freetype.h:1474
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:416
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
FT_Vector * vec
Definition: ftbbox.c:448
return FT_Err_Ok
Definition: ftbbox.c:511
FT_BEGIN_HEADER FT_MulDiv_No_Round(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:464
FT_Vector_NormLen(FT_Vector *vector)
Definition: ftcalc.c:776
#define NEG_LONG(a)
Definition: ftcalc.h:426
#define MUL_LONG(a, b)
Definition: ftcalc.h:424
#define SUB_LONG(a, b)
Definition: ftcalc.h:422
#define ADD_LONG(a, b)
Definition: ftcalc.h:420
FT_Hypot(FT_Fixed x, FT_Fixed y)
Definition: ftcalc.c:155
#define FT_CALLBACK_DEF(x)
Definition: ftconfig.h:533
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:388
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
#define FT_EXPORT_DEF(x)
Definition: ftconfig.h:483
unsigned short FT_UInt16
Definition: ftconfig.h:181
#define FT_ASSERT(condition)
Definition: ftdebug.h:211
#define FT_ERROR(varformat)
Definition: ftdebug.h:181
#define FT_TRACE5(varformat)
Definition: ftdebug.h:162
#define FT_TRACE7(varformat)
Definition: ftdebug.h:164
#define FT_TRACE6(varformat)
Definition: ftdebug.h:163
#define FT_THROW(e)
Definition: ftdebug.h:213
#define FT_TRACE1(varformat)
Definition: ftdebug.h:158
#define FT_TRACE4(varformat)
Definition: ftdebug.h:161
#define TT_INTERPRETER_VERSION_38
Definition: ftdriver.h:748
#define TT_INTERPRETER_VERSION_35
Definition: ftdriver.h:747
#define FT_CURVE_TAG_TOUCH_X
Definition: ftimage.h:459
#define FT_CURVE_TAG_TOUCH_BOTH
Definition: ftimage.h:462
#define FT_CURVE_TAG_TOUCH_Y
Definition: ftimage.h:460
#define FT_CURVE_TAG_ON
Definition: ftimage.h:453
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:58
#define FT_REALLOC(ptr, cursz, newsz)
Definition: ftmemory.h:306
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:333
#define FT_NEW(ptr)
Definition: ftmemory.h:331
#define FT_FREE(ptr)
Definition: ftmemory.h:329
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_ARRAY_MOVE(dest, source, count)
Definition: ftmemory.h:249
#define FT_PIX_CEIL(x)
Definition: ftobjs.h:94
#define FT_PAD_ROUND_LONG(x, n)
Definition: ftobjs.h:98
#define FT_ABS(a)
Definition: ftobjs.h:74
#define FT_PIX_FLOOR(x)
Definition: ftobjs.h:92
#define FT_MIN(a, b)
Definition: ftobjs.h:71
#define FT_FACE_DRIVER(x)
Definition: ftobjs.h:634
#define FT_PIX_ROUND_LONG(x)
Definition: ftobjs.h:102
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:93
#define FT_MAX(a, b)
Definition: ftobjs.h:72
#define FT_PIX_CEIL_LONG(x)
Definition: ftobjs.h:103
#define IP
Definition: ftp_var.h:24
#define FAILURE
Definition: ftraster.c:290
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
signed char FT_Char
Definition: fttypes.h:143
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
signed long FT_F26Dot6
Definition: fttypes.h:276
signed short FT_F2Dot14
Definition: fttypes.h:264
unsigned long FT_ULong
Definition: fttypes.h:253
unsigned char FT_Byte
Definition: fttypes.h:154
signed long FT_Fixed
Definition: fttypes.h:288
int FT_Error
Definition: fttypes.h:300
signed long FT_Long
Definition: fttypes.h:242
#define FT_ERR(e)
Definition: fttypes.h:586
unsigned short FT_UShort
Definition: fttypes.h:209
signed short FT_Short
Definition: fttypes.h:198
unsigned int FT_UInt
Definition: fttypes.h:231
#define FT_BOOL(x)
Definition: fttypes.h:578
signed int FT_Int
Definition: fttypes.h:220
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLdouble s
Definition: gl.h:2039
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLdouble GLdouble t
Definition: gl.h:2047
GLsizeiptr size
Definition: glext.h:5919
GLdouble n
Definition: glext.h:7729
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GLuint coords
Definition: glext.h:7368
GLenum GLint GLuint mask
Definition: glext.h:6028
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLint limit
Definition: glext.h:10326
GLenum GLint * range
Definition: glext.h:7539
GLsizei GLsizei GLfloat distance
Definition: glext.h:11755
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLfloat * val
Definition: glext.h:7180
GLfloat GLfloat p
Definition: glext.h:8902
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLfloat GLfloat v1
Definition: glext.h:6062
GLfloat GLfloat GLfloat v2
Definition: glext.h:6063
GLbyte by
Definition: glext.h:8766
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define X(b, s)
#define I(s)
#define V(i, a, b, c, d)
Definition: jaricom.c:29
#define d
Definition: ke_i.h:81
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
GLint dy
Definition: linetemp.h:97
if(dx< 0)
Definition: linetemp.h:194
GLint dx
Definition: linetemp.h:97
#define AA(_h, _w, _x, _y, _z)
#define sign(x)
Definition: mapdesc.cc:613
#define error(str)
Definition: mkdosfs.c:1605
static const struct update_accum a1
Definition: msg.c:578
static CRYPT_DATA_BLOB b1[]
Definition: msg.c:573
static char memory[1024 *256]
Definition: process.c:116
DWORD zone
Definition: sec_mgr.c:1754
int k
Definition: mpi.c:3369
struct @1669::@1670 driver
#define L(x)
Definition: ntvdm.h:50
__asm__(".p2align 4, 0x90\n" ".seh_proc __seh2_global_filter_func\n" "__seh2_global_filter_func:\n" "\tpush %rbp\n" "\t.seh_pushreg %rbp\n" "\tsub $32, %rsp\n" "\t.seh_stackalloc 32\n" "\t.seh_endprologue\n" "\tmov %rdx, %rbp\n" "\tjmp *%rax\n" "__seh2_global_filter_func_exit:\n" "\t.p2align 4\n" "\tadd $32, %rsp\n" "\tpop %rbp\n" "\tret\n" "\t.seh_endproc")
#define long
Definition: qsort.c:33
#define SUCCESS
Definition: regproc.h:26
#define S(x)
Definition: test.h:217
#define F(x, y, z)
Definition: md5.c:51
#define R(b, x)
Definition: sha2.c:134
FT_Long num_glyphs
Definition: freetype.h:1076
FT_String * style_name
Definition: freetype.h:1079
FT_String * family_name
Definition: freetype.h:1078
FT_Fixed y_scale
Definition: freetype.h:1644
FT_Fixed x_scale
Definition: freetype.h:1643
FT_UShort x_ppem
Definition: freetype.h:1640
FT_UShort y_ppem
Definition: freetype.h:1641
FT_F2Dot14 x
Definition: fttypes.h:356
FT_F2Dot14 y
Definition: fttypes.h:357
FT_Pos x
Definition: ftimage.h:76
FT_Pos y
Definition: ftimage.h:77
Definition: movable.cpp:9
FT_Int Caller_Range
Definition: ttinterp.h:93
FT_Long Cur_Count
Definition: ttinterp.h:95
FT_Long Caller_IP
Definition: ttinterp.h:94
TT_DefRecord * Def
Definition: ttinterp.h:97
FT_Byte * base
Definition: ttobjs.h:147
FT_Long size
Definition: ttobjs.h:148
FT_ULong sph_fdef_flags
Definition: ttobjs.h:167
FT_Long start
Definition: ttobjs.h:162
FT_UInt opc
Definition: ttobjs.h:164
FT_Long end
Definition: ttobjs.h:163
FT_Bool active
Definition: ttobjs.h:165
FT_Int range
Definition: ttobjs.h:161
FT_Bool inline_delta
Definition: ttobjs.h:166
FT_Memory memory
Definition: ttinterp.h:153
FT_Bool instruction_trap
Definition: ttinterp.h:224
TT_Get_CVT_Func func_read_cvt
Definition: ttinterp.h:247
TT_Round_Func func_round
Definition: ttinterp.h:236
FT_Long * storage
Definition: ttinterp.h:218
TT_GlyphZoneRec pts
Definition: ttinterp.h:170
TT_GlyphZoneRec zp1
Definition: ttinterp.h:168
FT_Bool is_composite
Definition: ttinterp.h:229
FT_ULong loopcall_counter
Definition: ttinterp.h:430
TT_CallStack callStack
Definition: ttinterp.h:208
TT_Project_Func func_dualproj
Definition: ttinterp.h:239
FT_Bool pedantic_hinting
Definition: ttinterp.h:230
FT_Long stackSize
Definition: ttinterp.h:161
FT_UInt numIDefs
Definition: ttinterp.h:199
FT_UInt maxFDefs
Definition: ttinterp.h:196
FT_Long * cvt
Definition: ttinterp.h:190
TT_GraphicsState GS
Definition: ttinterp.h:177
FT_ULong neg_jump_counter_max
Definition: ttinterp.h:433
TT_DefArray FDefs
Definition: ttinterp.h:197
TT_GlyphZoneRec twilight
Definition: ttinterp.h:171
TT_Size_Metrics tt_metrics
Definition: ttinterp.h:175
TT_Move_Func func_move
Definition: ttinterp.h:242
FT_UInt maxIDefs
Definition: ttinterp.h:200
TT_DefArray IDefs
Definition: ttinterp.h:201
FT_UInt numFDefs
Definition: ttinterp.h:195
FT_Long codeSize
Definition: ttinterp.h:182
TT_GlyphZoneRec zp0
Definition: ttinterp.h:167
FT_UInt glyphSize
Definition: ttinterp.h:192
FT_UShort storeSize
Definition: ttinterp.h:217
FT_ULong cvtSize
Definition: ttinterp.h:189
FT_F26Dot6 phase
Definition: ttinterp.h:221
TT_Move_Func func_move_orig
Definition: ttinterp.h:243
TT_Project_Func func_project
Definition: ttinterp.h:238
TT_Set_CVT_Func func_move_cvt
Definition: ttinterp.h:249
TT_Cur_Ppem_Func func_cur_ppem
Definition: ttinterp.h:245
TT_GlyphZoneRec zp2
Definition: ttinterp.h:169
FT_Bool grayscale
Definition: ttinterp.h:251
FT_Short maxContours
Definition: ttinterp.h:211
FT_ULong loopcall_counter_max
Definition: ttinterp.h:431
FT_ULong neg_jump_counter
Definition: ttinterp.h:432
FT_Byte * code
Definition: ttinterp.h:180
FT_Long pointSize
Definition: ttinterp.h:173
FT_Error error
Definition: ttinterp.h:157
FT_F26Dot6 period
Definition: ttinterp.h:220
TT_CodeRangeTable codeRangeTable
Definition: ttinterp.h:214
FT_Size_Metrics metrics
Definition: ttinterp.h:174
FT_UShort maxPoints
Definition: ttinterp.h:210
FT_Long * stack
Definition: ttinterp.h:162
FT_Bool step_ins
Definition: ttinterp.h:187
FT_Byte * glyphIns
Definition: ttinterp.h:193
TT_Set_CVT_Func func_write_cvt
Definition: ttinterp.h:248
FT_F26Dot6 threshold
Definition: ttinterp.h:222
TT_Interpreter interpreter
Definition: tttypes.h:1488
FT_FaceRec root
Definition: tttypes.h:1393
FT_Short n_contours
Definition: tttypes.h:1605
FT_Vector * org
Definition: tttypes.h:1607
FT_UShort n_points
Definition: tttypes.h:1604
FT_Vector * orus
Definition: tttypes.h:1609
FT_Vector * cur
Definition: tttypes.h:1608
FT_UShort first_point
Definition: tttypes.h:1614
FT_UShort * contours
Definition: tttypes.h:1612
FT_Byte * tags
Definition: tttypes.h:1611
FT_F26Dot6 single_width_value
Definition: ttobjs.h:82
FT_Byte instruct_control
Definition: ttobjs.h:86
FT_UShort delta_shift
Definition: ttobjs.h:84
FT_UShort rp0
Definition: ttobjs.h:67
FT_Bool scan_control
Definition: ttobjs.h:91
FT_UShort gep1
Definition: ttobjs.h:95
FT_UnitVector dualVector
Definition: ttobjs.h:71
FT_UShort delta_base
Definition: ttobjs.h:83
FT_UnitVector freeVector
Definition: ttobjs.h:73
FT_Int round_state
Definition: ttobjs.h:77
FT_UShort gep0
Definition: ttobjs.h:94
FT_UnitVector projVector
Definition: ttobjs.h:72
FT_F26Dot6 control_value_cutin
Definition: ttobjs.h:80
FT_UShort gep2
Definition: ttobjs.h:96
FT_UShort rp2
Definition: ttobjs.h:69
FT_Long loop
Definition: ttobjs.h:75
FT_Int scan_type
Definition: ttobjs.h:92
FT_F26Dot6 minimum_distance
Definition: ttobjs.h:76
FT_Bool auto_flip
Definition: ttobjs.h:79
FT_UShort rp1
Definition: ttobjs.h:68
FT_F26Dot6 single_width_cutin
Definition: ttobjs.h:81
FT_UShort maxStackElements
Definition: tttables.h:580
FT_UShort maxSizeOfInstructions
Definition: tttables.h:581
FT_Bool rotated
Definition: ttobjs.h:265
FT_F26Dot6 compensations[4]
Definition: ttobjs.h:261
FT_Bool stretched
Definition: ttobjs.h:266
FT_Long y_ratio
Definition: ttobjs.h:255
FT_Long ratio
Definition: ttobjs.h:258
FT_Fixed scale
Definition: ttobjs.h:259
FT_UShort ppem
Definition: ttobjs.h:257
FT_Long x_ratio
Definition: ttobjs.h:254
Definition: types.h:73
Definition: match.c:390
ecx edi movl ebx edx edi decl ecx esi eax jecxz decl eax andl eax esi movl edx movl TEMP incl eax andl eax ecx incl ebx testl eax jnz xchgl ecx incl TEMP esp ecx subl ebx pushl ecx ecx edx ecx shrl ecx mm0 mm4 mm0 mm4 mm1 mm5 mm1 mm5 mm2 mm6 mm2 mm6 mm3 mm7 mm3 mm7 paddd mm0 paddd mm4 paddd mm0 paddd mm4 paddd mm0 paddd mm4 movq mm1 movq mm5 psrlq mm1 psrlq mm5 paddd mm0 paddd mm4 psrad mm0 psrad mm4 packssdw mm0 packssdw mm4 mm1 punpckldq mm0 pand mm1 pand mm0 por mm1 movq edi esi edx edi decl ecx jnz popl ecx andl ecx jecxz mm0 mm0 mm1 mm1 mm2 mm2 mm3 mm3 paddd mm0 paddd mm0 paddd mm0 movq mm1 psrlq mm1 paddd mm0 psrad mm0 packssdw mm0 movd eax movw ax
Definition: synth_sse3d.h:180
#define PACK(r, g, b)
int _tt_interp_dummy
Definition: ttinterp.c:8507
FT_F26Dot6(* TT_Round_Func)(TT_ExecContext exc, FT_F26Dot6 distance, FT_F26Dot6 compensation)
Definition: ttinterp.h:53
#define TT_Round_Super_45
Definition: ttinterp.h:40
#define TT_Round_To_Double_Grid
Definition: ttinterp.h:36
#define TT_Round_Up_To_Grid
Definition: ttinterp.h:37
#define TT_Round_Off
Definition: ttinterp.h:33
TT_RunIns(TT_ExecContext exec)
#define TT_Round_To_Half_Grid
Definition: ttinterp.h:34
const TT_GraphicsState tt_default_graphics_state
void(* TT_Move_Func)(TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance)
Definition: ttinterp.h:59
FT_F26Dot6(* TT_Project_Func)(TT_ExecContext exc, FT_Pos dx, FT_Pos dy)
Definition: ttinterp.h:66
TT_New_Context(TT_Driver driver)
#define TT_Round_To_Grid
Definition: ttinterp.h:35
#define TT_Round_Super
Definition: ttinterp.h:39
#define TT_Round_Down_To_Grid
Definition: ttinterp.h:38
typedefFT_BEGIN_HEADER struct TT_DriverRec_ * TT_Driver
Definition: ttobjs.h:39
#define TT_MAX_CODE_RANGES
Definition: ttobjs.h:125
@ tt_coderange_glyph
Definition: ttobjs.h:140
Definition: pdh_main.c:94
int ret
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList