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