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