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