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