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