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