1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2018 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17
18
19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
20 /* issues; many thanks! */
21
22
23 #include <ft2build.h>
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_CALC_H
26 #include FT_TRIGONOMETRY_H
27 #include FT_SYSTEM_H
28 #include FT_DRIVER_H
29 #include FT_MULTIPLE_MASTERS_H
30
31 #include "ttinterp.h"
32 #include "tterrors.h"
33 #include "ttsubpix.h"
34 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
35 #include "ttgxvar.h"
36 #endif
37
38
39 #ifdef TT_USE_BYTECODE_INTERPRETER
40
41
42 /*************************************************************************/
43 /* */
44 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
45 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
46 /* messages during execution. */
47 /* */
48 #undef FT_COMPONENT
49 #define FT_COMPONENT trace_ttinterp
50
51
52 #define NO_SUBPIXEL_HINTING \
53 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
54 TT_INTERPRETER_VERSION_35 )
55
56 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
57 #define SUBPIXEL_HINTING_INFINALITY \
58 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
59 TT_INTERPRETER_VERSION_38 )
60 #endif
61
62 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
63 #define SUBPIXEL_HINTING_MINIMAL \
64 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
65 TT_INTERPRETER_VERSION_40 )
66 #endif
67
68 #define PROJECT( v1, v2 ) \
69 exc->func_project( exc, \
70 SUB_LONG( (v1)->x, (v2)->x ), \
71 SUB_LONG( (v1)->y, (v2)->y ) )
72
73 #define DUALPROJ( v1, v2 ) \
74 exc->func_dualproj( exc, \
75 SUB_LONG( (v1)->x, (v2)->x ), \
76 SUB_LONG( (v1)->y, (v2)->y ) )
77
78 #define FAST_PROJECT( v ) \
79 exc->func_project( exc, (v)->x, (v)->y )
80
81 #define FAST_DUALPROJ( v ) \
82 exc->func_dualproj( exc, (v)->x, (v)->y )
83
84
85 /*************************************************************************/
86 /* */
87 /* Two simple bounds-checking macros. */
88 /* */
89 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
90 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
91
92
93 #undef SUCCESS
94 #define SUCCESS 0
95
96 #undef FAILURE
97 #define FAILURE 1
98
99
100 /*************************************************************************/
101 /* */
102 /* CODERANGE FUNCTIONS */
103 /* */
104 /*************************************************************************/
105
106
107 /*************************************************************************/
108 /* */
109 /* <Function> */
110 /* TT_Goto_CodeRange */
111 /* */
112 /* <Description> */
113 /* Switches to a new code range (updates the code related elements in */
114 /* `exec', and `IP'). */
115 /* */
116 /* <Input> */
117 /* range :: The new execution code range. */
118 /* */
119 /* IP :: The new IP in the new code range. */
120 /* */
121 /* <InOut> */
122 /* exec :: The target execution context. */
123 /* */
124 FT_LOCAL_DEF( void )
125 TT_Goto_CodeRange( TT_ExecContext exec,
126 FT_Int range,
127 FT_Long IP )
128 {
129 TT_CodeRange* coderange;
130
131
132 FT_ASSERT( range >= 1 && range <= 3 );
133
134 coderange = &exec->codeRangeTable[range - 1];
135
136 FT_ASSERT( coderange->base );
137
138 /* NOTE: Because the last instruction of a program may be a CALL */
139 /* which will return to the first byte *after* the code */
140 /* range, we test for IP <= Size instead of IP < Size. */
141 /* */
142 FT_ASSERT( IP <= coderange->size );
143
144 exec->code = coderange->base;
145 exec->codeSize = coderange->size;
146 exec->IP = IP;
147 exec->curRange = range;
148 }
149
150
151 /*************************************************************************/
152 /* */
153 /* <Function> */
154 /* TT_Set_CodeRange */
155 /* */
156 /* <Description> */
157 /* Sets a code range. */
158 /* */
159 /* <Input> */
160 /* range :: The code range index. */
161 /* */
162 /* base :: The new code base. */
163 /* */
164 /* length :: The range size in bytes. */
165 /* */
166 /* <InOut> */
167 /* exec :: The target execution context. */
168 /* */
169 FT_LOCAL_DEF( void )
170 TT_Set_CodeRange( TT_ExecContext exec,
171 FT_Int range,
172 void* base,
173 FT_Long length )
174 {
175 FT_ASSERT( range >= 1 && range <= 3 );
176
177 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
178 exec->codeRangeTable[range - 1].size = length;
179 }
180
181
182 /*************************************************************************/
183 /* */
184 /* <Function> */
185 /* TT_Clear_CodeRange */
186 /* */
187 /* <Description> */
188 /* Clears a code range. */
189 /* */
190 /* <Input> */
191 /* range :: The code range index. */
192 /* */
193 /* <InOut> */
194 /* exec :: The target execution context. */
195 /* */
196 FT_LOCAL_DEF( void )
197 TT_Clear_CodeRange( TT_ExecContext exec,
198 FT_Int range )
199 {
200 FT_ASSERT( range >= 1 && range <= 3 );
201
202 exec->codeRangeTable[range - 1].base = NULL;
203 exec->codeRangeTable[range - 1].size = 0;
204 }
205
206
207 /*************************************************************************/
208 /* */
209 /* EXECUTION CONTEXT ROUTINES */
210 /* */
211 /*************************************************************************/
212
213
214 /*************************************************************************/
215 /* */
216 /* <Function> */
217 /* TT_Done_Context */
218 /* */
219 /* <Description> */
220 /* Destroys a given context. */
221 /* */
222 /* <Input> */
223 /* exec :: A handle to the target execution context. */
224 /* */
225 /* memory :: A handle to the parent memory object. */
226 /* */
227 /* <Note> */
228 /* Only the glyph loader and debugger should call this function. */
229 /* */
230 FT_LOCAL_DEF( void )
231 TT_Done_Context( TT_ExecContext exec )
232 {
233 FT_Memory memory = exec->memory;
234
235
236 /* points zone */
237 exec->maxPoints = 0;
238 exec->maxContours = 0;
239
240 /* free stack */
241 FT_FREE( exec->stack );
242 exec->stackSize = 0;
243
244 /* free call stack */
245 FT_FREE( exec->callStack );
246 exec->callSize = 0;
247 exec->callTop = 0;
248
249 /* free glyph code range */
250 FT_FREE( exec->glyphIns );
251 exec->glyphSize = 0;
252
253 exec->size = NULL;
254 exec->face = NULL;
255
256 FT_FREE( exec );
257 }
258
259
260 /*************************************************************************/
261 /* */
262 /* <Function> */
263 /* Init_Context */
264 /* */
265 /* <Description> */
266 /* Initializes a context object. */
267 /* */
268 /* <Input> */
269 /* memory :: A handle to the parent memory object. */
270 /* */
271 /* <InOut> */
272 /* exec :: A handle to the target execution context. */
273 /* */
274 /* <Return> */
275 /* FreeType error code. 0 means success. */
276 /* */
277 static FT_Error
278 Init_Context( TT_ExecContext exec,
279 FT_Memory memory )
280 {
281 FT_Error error;
282
283
284 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
285
286 exec->memory = memory;
287 exec->callSize = 32;
288
289 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
290 goto Fail_Memory;
291
292 /* all values in the context are set to 0 already, but this is */
293 /* here as a remainder */
294 exec->maxPoints = 0;
295 exec->maxContours = 0;
296
297 exec->stackSize = 0;
298 exec->glyphSize = 0;
299
300 exec->stack = NULL;
301 exec->glyphIns = NULL;
302
303 exec->face = NULL;
304 exec->size = NULL;
305
306 return FT_Err_Ok;
307
308 Fail_Memory:
309 FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
310 TT_Done_Context( exec );
311
312 return error;
313 }
314
315
316 /*************************************************************************/
317 /* */
318 /* <Function> */
319 /* Update_Max */
320 /* */
321 /* <Description> */
322 /* Checks the size of a buffer and reallocates it if necessary. */
323 /* */
324 /* <Input> */
325 /* memory :: A handle to the parent memory object. */
326 /* */
327 /* multiplier :: The size in bytes of each element in the buffer. */
328 /* */
329 /* new_max :: The new capacity (size) of the buffer. */
330 /* */
331 /* <InOut> */
332 /* size :: The address of the buffer's current size expressed */
333 /* in elements. */
334 /* */
335 /* buff :: The address of the buffer base pointer. */
336 /* */
337 /* <Return> */
338 /* FreeType error code. 0 means success. */
339 /* */
340 FT_LOCAL_DEF( FT_Error )
341 Update_Max( FT_Memory memory,
342 FT_ULong* size,
343 FT_ULong multiplier,
344 void* _pbuff,
345 FT_ULong new_max )
346 {
347 FT_Error error;
348 void** pbuff = (void**)_pbuff;
349
350
351 if ( *size < new_max )
352 {
353 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
354 return error;
355 *size = new_max;
356 }
357
358 return FT_Err_Ok;
359 }
360
361
362 /*************************************************************************/
363 /* */
364 /* <Function> */
365 /* TT_Load_Context */
366 /* */
367 /* <Description> */
368 /* Prepare an execution context for glyph hinting. */
369 /* */
370 /* <Input> */
371 /* face :: A handle to the source face object. */
372 /* */
373 /* size :: A handle to the source size object. */
374 /* */
375 /* <InOut> */
376 /* exec :: A handle to the target execution context. */
377 /* */
378 /* <Return> */
379 /* FreeType error code. 0 means success. */
380 /* */
381 /* <Note> */
382 /* Only the glyph loader and debugger should call this function. */
383 /* */
384 FT_LOCAL_DEF( FT_Error )
385 TT_Load_Context( TT_ExecContext exec,
386 TT_Face face,
387 TT_Size size )
388 {
389 FT_Int i;
390 FT_ULong tmp;
391 TT_MaxProfile* maxp;
392 FT_Error error;
393
394
395 exec->face = face;
396 maxp = &face->max_profile;
397 exec->size = size;
398
399 if ( size )
400 {
401 exec->numFDefs = size->num_function_defs;
402 exec->maxFDefs = size->max_function_defs;
403 exec->numIDefs = size->num_instruction_defs;
450 sizeof ( FT_Byte ),
451 (void*)&exec->glyphIns,
452 maxp->maxSizeOfInstructions );
453 exec->glyphSize = (FT_UShort)tmp;
454 if ( error )
455 return error;
456
457 exec->pts.n_points = 0;
458 exec->pts.n_contours = 0;
459
460 exec->zp1 = exec->pts;
461 exec->zp2 = exec->pts;
462 exec->zp0 = exec->pts;
463
464 exec->instruction_trap = FALSE;
465
466 return FT_Err_Ok;
467 }
468
469
470 /*************************************************************************/
471 /* */
472 /* <Function> */
473 /* TT_Save_Context */
474 /* */
475 /* <Description> */
476 /* Saves the code ranges in a `size' object. */
477 /* */
478 /* <Input> */
479 /* exec :: A handle to the source execution context. */
480 /* */
481 /* <InOut> */
482 /* size :: A handle to the target size object. */
483 /* */
484 /* <Note> */
485 /* Only the glyph loader and debugger should call this function. */
486 /* */
487 FT_LOCAL_DEF( void )
488 TT_Save_Context( TT_ExecContext exec,
489 TT_Size size )
490 {
491 FT_Int i;
492
493
494 /* XXX: Will probably disappear soon with all the code range */
495 /* management, which is now rather obsolete. */
496 /* */
497 size->num_function_defs = exec->numFDefs;
498 size->num_instruction_defs = exec->numIDefs;
499
500 size->max_func = exec->maxFunc;
501 size->max_ins = exec->maxIns;
502
503 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
504 size->codeRangeTable[i] = exec->codeRangeTable[i];
505 }
506
507
508 /*************************************************************************/
509 /* */
510 /* <Function> */
511 /* TT_Run_Context */
512 /* */
513 /* <Description> */
514 /* Executes one or more instructions in the execution context. */
515 /* */
516 /* <Input> */
517 /* debug :: A Boolean flag. If set, the function sets some internal */
518 /* variables and returns immediately, otherwise TT_RunIns() */
519 /* is called. */
520 /* */
521 /* This is commented out currently. */
522 /* */
523 /* <Input> */
524 /* exec :: A handle to the target execution context. */
525 /* */
526 /* <Return> */
527 /* TrueType error code. 0 means success. */
528 /* */
529 FT_LOCAL_DEF( FT_Error )
530 TT_Run_Context( TT_ExecContext exec )
531 {
532 TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
533
534 exec->zp0 = exec->pts;
535 exec->zp1 = exec->pts;
536 exec->zp2 = exec->pts;
537
538 exec->GS.gep0 = 1;
539 exec->GS.gep1 = 1;
540 exec->GS.gep2 = 1;
541
542 exec->GS.projVector.x = 0x4000;
543 exec->GS.projVector.y = 0x0000;
544
545 exec->GS.freeVector = exec->GS.projVector;
546 exec->GS.dualVector = exec->GS.projVector;
547
548 exec->GS.round_state = 1;
592 goto Fail;
593
594 memory = driver->root.root.memory;
595
596 /* allocate object */
597 if ( FT_NEW( exec ) )
598 goto Fail;
599
600 /* initialize it; in case of error this deallocates `exec' too */
601 error = Init_Context( exec, memory );
602 if ( error )
603 goto Fail;
604
605 return exec;
606
607 Fail:
608 return NULL;
609 }
610
611
612 /*************************************************************************/
613 /* */
614 /* Before an opcode is executed, the interpreter verifies that there are */
615 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
616 /* table. */
617 /* */
618 /* For each opcode, the first column gives the number of arguments that */
619 /* are popped from the stack; the second one gives the number of those */
620 /* that are pushed in result. */
621 /* */
622 /* Opcodes which have a varying number of parameters in the data stream */
623 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
624 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
625 /* to zero. */
626 /* */
627 /*************************************************************************/
628
629
630 #undef PACK
631 #define PACK( x, y ) ( ( x << 4 ) | y )
632
633
634 static
635 const FT_Byte Pop_Push_Count[256] =
636 {
637 /* opcodes are gathered in groups of 16 */
638 /* please keep the spaces as they are */
639
640 /* SVTCA y */ PACK( 0, 0 ),
641 /* SVTCA x */ PACK( 0, 0 ),
642 /* SPvTCA y */ PACK( 0, 0 ),
643 /* SPvTCA x */ PACK( 0, 0 ),
644 /* SFvTCA y */ PACK( 0, 0 ),
645 /* SFvTCA x */ PACK( 0, 0 ),
646 /* SPvTL // */ PACK( 2, 0 ),
647 /* SPvTL + */ PACK( 2, 0 ),
1112 "7 INS_$AE",
1113 "7 INS_$AF",
1114
1115 "8 PushB[0]",
1116 "8 PushB[1]",
1117 "8 PushB[2]",
1118 "8 PushB[3]",
1119 "8 PushB[4]",
1120 "8 PushB[5]",
1121 "8 PushB[6]",
1122 "8 PushB[7]",
1123 "8 PushW[0]",
1124 "8 PushW[1]",
1125 "8 PushW[2]",
1126 "8 PushW[3]",
1127 "8 PushW[4]",
1128 "8 PushW[5]",
1129 "8 PushW[6]",
1130 "8 PushW[7]",
1131
1132 "8 MDRP[00]",
1133 "8 MDRP[01]",
1134 "8 MDRP[02]",
1135 "8 MDRP[03]",
1136 "8 MDRP[04]",
1137 "8 MDRP[05]",
1138 "8 MDRP[06]",
1139 "8 MDRP[07]",
1140 "8 MDRP[08]",
1141 "8 MDRP[09]",
1142 "8 MDRP[10]",
1143 "8 MDRP[11]",
1144 "8 MDRP[12]",
1145 "8 MDRP[13]",
1146 "8 MDRP[14]",
1147 "8 MDRP[15]",
1148
1149 "8 MDRP[16]",
1150 "8 MDRP[17]",
1151 "8 MDRP[18]",
1152 "8 MDRP[19]",
1153 "8 MDRP[20]",
1154 "8 MDRP[21]",
1155 "8 MDRP[22]",
1156 "8 MDRP[23]",
1157 "8 MDRP[24]",
1158 "8 MDRP[25]",
1159 "8 MDRP[26]",
1160 "8 MDRP[27]",
1161 "8 MDRP[28]",
1162 "8 MDRP[29]",
1163 "8 MDRP[30]",
1164 "8 MDRP[31]",
1165
1166 "8 MIRP[00]",
1167 "8 MIRP[01]",
1168 "8 MIRP[02]",
1169 "8 MIRP[03]",
1170 "8 MIRP[04]",
1171 "8 MIRP[05]",
1172 "8 MIRP[06]",
1173 "8 MIRP[07]",
1174 "8 MIRP[08]",
1175 "8 MIRP[09]",
1176 "8 MIRP[10]",
1177 "8 MIRP[11]",
1178 "8 MIRP[12]",
1179 "8 MIRP[13]",
1180 "8 MIRP[14]",
1181 "8 MIRP[15]",
1182
1183 "8 MIRP[16]",
1184 "8 MIRP[17]",
1185 "8 MIRP[18]",
1186 "8 MIRP[19]",
1187 "8 MIRP[20]",
1188 "8 MIRP[21]",
1189 "8 MIRP[22]",
1190 "8 MIRP[23]",
1191 "8 MIRP[24]",
1192 "8 MIRP[25]",
1193 "8 MIRP[26]",
1194 "8 MIRP[27]",
1195 "8 MIRP[28]",
1196 "8 MIRP[29]",
1197 "8 MIRP[30]",
1198 "8 MIRP[31]"
1199 };
1200
1201 #endif /* FT_DEBUG_LEVEL_TRACE */
1202
1203
1204 static
1205 const FT_Char opcode_length[256] =
1206 {
1207 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1208 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1209 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1210 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1211
1212 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1213 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1214 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1215 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1216
1217 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1218 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1431
1432 /* add them */
1433 lo = lo1 + lo2;
1434 hi = hi1 + hi2 + ( lo < lo1 );
1435
1436 /* divide the result by 2^14 with rounding */
1437 s = hi >> 31;
1438 l = lo + (FT_UInt32)s;
1439 hi += s + ( l < lo );
1440 lo = l;
1441
1442 l = lo + 0x2000U;
1443 hi += ( l < lo );
1444
1445 return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
1446 }
1447
1448 #endif /* TT_DotFix14 */
1449
1450
1451 /*************************************************************************/
1452 /* */
1453 /* <Function> */
1454 /* Current_Ratio */
1455 /* */
1456 /* <Description> */
1457 /* Returns the current aspect ratio scaling factor depending on the */
1458 /* projection vector's state and device resolutions. */
1459 /* */
1460 /* <Return> */
1461 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1462 /* */
1463 static FT_Long
1464 Current_Ratio( TT_ExecContext exc )
1465 {
1466 if ( !exc->tt_metrics.ratio )
1467 {
1468 if ( exc->GS.projVector.y == 0 )
1469 exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;
1470
1471 else if ( exc->GS.projVector.x == 0 )
1472 exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;
1473
1474 else
1475 {
1476 FT_F26Dot6 x, y;
1477
1478
1479 x = TT_MulFix14( exc->tt_metrics.x_ratio,
1480 exc->GS.projVector.x );
1481 y = TT_MulFix14( exc->tt_metrics.y_ratio,
1482 exc->GS.projVector.y );
1484 }
1485 }
1486 return exc->tt_metrics.ratio;
1487 }
1488
1489
1490 FT_CALLBACK_DEF( FT_Long )
1491 Current_Ppem( TT_ExecContext exc )
1492 {
1493 return exc->tt_metrics.ppem;
1494 }
1495
1496
1497 FT_CALLBACK_DEF( FT_Long )
1498 Current_Ppem_Stretched( TT_ExecContext exc )
1499 {
1500 return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );
1501 }
1502
1503
1504 /*************************************************************************/
1505 /* */
1506 /* Functions related to the control value table (CVT). */
1507 /* */
1508 /*************************************************************************/
1509
1510
1511 FT_CALLBACK_DEF( FT_F26Dot6 )
1512 Read_CVT( TT_ExecContext exc,
1513 FT_ULong idx )
1514 {
1515 return exc->cvt[idx];
1516 }
1517
1518
1519 FT_CALLBACK_DEF( FT_F26Dot6 )
1520 Read_CVT_Stretched( TT_ExecContext exc,
1521 FT_ULong idx )
1522 {
1523 return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
1524 }
1525
1526
1527 FT_CALLBACK_DEF( void )
1528 Write_CVT( TT_ExecContext exc,
1530 FT_F26Dot6 value )
1531 {
1532 exc->cvt[idx] = value;
1533 }
1534
1535
1536 FT_CALLBACK_DEF( void )
1537 Write_CVT_Stretched( TT_ExecContext exc,
1538 FT_ULong idx,
1539 FT_F26Dot6 value )
1540 {
1541 exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
1542 }
1543
1544
1545 FT_CALLBACK_DEF( void )
1546 Move_CVT( TT_ExecContext exc,
1547 FT_ULong idx,
1548 FT_F26Dot6 value )
1549 {
1550 exc->cvt[idx] += value;
1551 }
1552
1553
1554 FT_CALLBACK_DEF( void )
1555 Move_CVT_Stretched( TT_ExecContext exc,
1556 FT_ULong idx,
1557 FT_F26Dot6 value )
1558 {
1559 exc->cvt[idx] += FT_DivFix( value, Current_Ratio( exc ) );
1560 }
1561
1562
1563 /*************************************************************************/
1564 /* */
1565 /* <Function> */
1566 /* GetShortIns */
1567 /* */
1568 /* <Description> */
1569 /* Returns a short integer taken from the instruction stream at */
1570 /* address IP. */
1571 /* */
1572 /* <Return> */
1573 /* Short read at code[IP]. */
1574 /* */
1575 /* <Note> */
1576 /* This one could become a macro. */
1577 /* */
1578 static FT_Short
1579 GetShortIns( TT_ExecContext exc )
1580 {
1581 /* Reading a byte stream so there is no endianness (DaveP) */
1582 exc->IP += 2;
1583 return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
1584 exc->code[exc->IP - 1] );
1585 }
1586
1587
1588 /*************************************************************************/
1589 /* */
1590 /* <Function> */
1591 /* Ins_Goto_CodeRange */
1592 /* */
1593 /* <Description> */
1594 /* Goes to a certain code range in the instruction stream. */
1595 /* */
1596 /* <Input> */
1597 /* aRange :: The index of the code range. */
1598 /* */
1599 /* aIP :: The new IP address in the code range. */
1600 /* */
1601 /* <Return> */
1602 /* SUCCESS or FAILURE. */
1603 /* */
1604 static FT_Bool
1605 Ins_Goto_CodeRange( TT_ExecContext exc,
1606 FT_Int aRange,
1607 FT_Long aIP )
1608 {
1609 TT_CodeRange* range;
1610
1611
1612 if ( aRange < 1 || aRange > 3 )
1613 {
1614 exc->error = FT_THROW( Bad_Argument );
1615 return FAILURE;
1616 }
1617
1618 range = &exc->codeRangeTable[aRange - 1];
1619
1620 if ( !range->base ) /* invalid coderange */
1621 {
1622 exc->error = FT_THROW( Invalid_CodeRange );
1623 return FAILURE;
1625
1626 /* NOTE: Because the last instruction of a program may be a CALL */
1627 /* which will return to the first byte *after* the code */
1628 /* range, we test for aIP <= Size, instead of aIP < Size. */
1629
1630 if ( aIP > range->size )
1631 {
1632 exc->error = FT_THROW( Code_Overflow );
1633 return FAILURE;
1634 }
1635
1636 exc->code = range->base;
1637 exc->codeSize = range->size;
1638 exc->IP = aIP;
1639 exc->curRange = aRange;
1640
1641 return SUCCESS;
1642 }
1643
1644
1645 /*************************************************************************/
1646 /* */
1647 /* <Function> */
1648 /* Direct_Move */
1649 /* */
1650 /* <Description> */
1651 /* Moves a point by a given distance along the freedom vector. The */
1652 /* point will be `touched'. */
1653 /* */
1654 /* <Input> */
1655 /* point :: The index of the point to move. */
1656 /* */
1657 /* distance :: The distance to apply. */
1658 /* */
1659 /* <InOut> */
1660 /* zone :: The affected glyph zone. */
1661 /* */
1662 /* <Note> */
1663 /* See `ttinterp.h' for details on backward compatibility mode. */
1664 /* `Touches' the point. */
1665 /* */
1666 static void
1667 Direct_Move( TT_ExecContext exc,
1668 TT_GlyphZone zone,
1669 FT_UShort point,
1670 FT_F26Dot6 distance )
1671 {
1672 FT_F26Dot6 v;
1673
1674
1675 v = exc->GS.freeVector.x;
1676
1677 if ( v != 0 )
1678 {
1679 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1680 if ( SUBPIXEL_HINTING_INFINALITY &&
1681 ( !exc->ignore_x_mode ||
1682 ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
1683 zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1684 FT_MulDiv( distance,
1685 v,
1711 v = exc->GS.freeVector.y;
1712
1713 if ( v != 0 )
1714 {
1715 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1716 if ( !( SUBPIXEL_HINTING_MINIMAL &&
1717 exc->backward_compatibility &&
1718 exc->iupx_called &&
1719 exc->iupy_called ) )
1720 #endif
1721 zone->cur[point].y = ADD_LONG( zone->cur[point].y,
1722 FT_MulDiv( distance,
1723 v,
1724 exc->F_dot_P ) );
1725
1726 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1727 }
1728 }
1729
1730
1731 /*************************************************************************/
1732 /* */
1733 /* <Function> */
1734 /* Direct_Move_Orig */
1735 /* */
1736 /* <Description> */
1737 /* Moves the *original* position of a point by a given distance along */
1738 /* the freedom vector. Obviously, the point will not be `touched'. */
1739 /* */
1740 /* <Input> */
1741 /* point :: The index of the point to move. */
1742 /* */
1743 /* distance :: The distance to apply. */
1744 /* */
1745 /* <InOut> */
1746 /* zone :: The affected glyph zone. */
1747 /* */
1748 static void
1749 Direct_Move_Orig( TT_ExecContext exc,
1750 TT_GlyphZone zone,
1751 FT_UShort point,
1752 FT_F26Dot6 distance )
1753 {
1754 FT_F26Dot6 v;
1755
1756
1757 v = exc->GS.freeVector.x;
1758
1759 if ( v != 0 )
1760 zone->org[point].x = ADD_LONG( zone->org[point].x,
1761 FT_MulDiv( distance,
1762 v,
1763 exc->F_dot_P ) );
1764
1765 v = exc->GS.freeVector.y;
1766
1767 if ( v != 0 )
1768 zone->org[point].y = ADD_LONG( zone->org[point].y,
1769 FT_MulDiv( distance,
1770 v,
1771 exc->F_dot_P ) );
1772 }
1773
1774
1775 /*************************************************************************/
1776 /* */
1777 /* Special versions of Direct_Move() */
1778 /* */
1779 /* The following versions are used whenever both vectors are both */
1780 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1781 /* See `ttinterp.h' for details on backward compatibility mode. */
1782 /* */
1783 /*************************************************************************/
1784
1785
1786 static void
1787 Direct_Move_X( TT_ExecContext exc,
1788 TT_GlyphZone zone,
1789 FT_UShort point,
1790 FT_F26Dot6 distance )
1791 {
1792 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1793 if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
1794 zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1795 else
1796 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1797
1798 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1799 if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
1800 zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1801 else
1802 #endif
1803
1810
1811 static void
1812 Direct_Move_Y( TT_ExecContext exc,
1813 TT_GlyphZone zone,
1814 FT_UShort point,
1815 FT_F26Dot6 distance )
1816 {
1817 FT_UNUSED( exc );
1818
1819 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1820 if ( !( SUBPIXEL_HINTING_MINIMAL &&
1821 exc->backward_compatibility &&
1822 exc->iupx_called && exc->iupy_called ) )
1823 #endif
1824 zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );
1825
1826 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1827 }
1828
1829
1830 /*************************************************************************/
1831 /* */
1832 /* Special versions of Direct_Move_Orig() */
1833 /* */
1834 /* The following versions are used whenever both vectors are both */
1835 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1836 /* */
1837 /*************************************************************************/
1838
1839
1840 static void
1841 Direct_Move_Orig_X( TT_ExecContext exc,
1842 TT_GlyphZone zone,
1843 FT_UShort point,
1844 FT_F26Dot6 distance )
1845 {
1846 FT_UNUSED( exc );
1847
1848 zone->org[point].x = ADD_LONG( zone->org[point].x, distance );
1849 }
1850
1851
1852 static void
1853 Direct_Move_Orig_Y( TT_ExecContext exc,
1854 TT_GlyphZone zone,
1855 FT_UShort point,
1856 FT_F26Dot6 distance )
1857 {
1858 FT_UNUSED( exc );
1859
1860 zone->org[point].y = ADD_LONG( zone->org[point].y, distance );
1861 }
1862
1863
1864 /*************************************************************************/
1865 /* */
1866 /* <Function> */
1867 /* Round_None */
1868 /* */
1869 /* <Description> */
1870 /* Does not round, but adds engine compensation. */
1871 /* */
1872 /* <Input> */
1873 /* distance :: The distance (not) to round. */
1874 /* */
1875 /* compensation :: The engine compensation. */
1876 /* */
1877 /* <Return> */
1878 /* The compensated distance. */
1879 /* */
1880 /* <Note> */
1881 /* The TrueType specification says very few about the relationship */
1882 /* between rounding and engine compensation. However, it seems from */
1883 /* the description of super round that we should add the compensation */
1884 /* before rounding. */
1885 /* */
1886 static FT_F26Dot6
1887 Round_None( TT_ExecContext exc,
1888 FT_F26Dot6 distance,
1889 FT_F26Dot6 compensation )
1890 {
1891 FT_F26Dot6 val;
1892
1893 FT_UNUSED( exc );
1894
1895
1896 if ( distance >= 0 )
1897 {
1898 val = ADD_LONG( distance, compensation );
1899 if ( val < 0 )
1900 val = 0;
1901 }
1902 else
1903 {
1904 val = SUB_LONG( distance, compensation );
1905 if ( val > 0 )
1906 val = 0;
1907 }
1908 return val;
1909 }
1910
1911
1912 /*************************************************************************/
1913 /* */
1914 /* <Function> */
1915 /* Round_To_Grid */
1916 /* */
1917 /* <Description> */
1918 /* Rounds value to grid after adding engine compensation. */
1919 /* */
1920 /* <Input> */
1921 /* distance :: The distance to round. */
1922 /* */
1923 /* compensation :: The engine compensation. */
1924 /* */
1925 /* <Return> */
1926 /* Rounded distance. */
1927 /* */
1928 static FT_F26Dot6
1929 Round_To_Grid( TT_ExecContext exc,
1930 FT_F26Dot6 distance,
1931 FT_F26Dot6 compensation )
1932 {
1933 FT_F26Dot6 val;
1934
1935 FT_UNUSED( exc );
1936
1937
1938 if ( distance >= 0 )
1939 {
1940 val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );
1941 if ( val < 0 )
1942 val = 0;
1943 }
1944 else
1945 {
1946 val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,
1947 distance ) ) );
1948 if ( val > 0 )
1949 val = 0;
1950 }
1951
1952 return val;
1953 }
1954
1955
1956 /*************************************************************************/
1957 /* */
1958 /* <Function> */
1959 /* Round_To_Half_Grid */
1960 /* */
1961 /* <Description> */
1962 /* Rounds value to half grid after adding engine compensation. */
1963 /* */
1964 /* <Input> */
1965 /* distance :: The distance to round. */
1966 /* */
1967 /* compensation :: The engine compensation. */
1968 /* */
1969 /* <Return> */
1970 /* Rounded distance. */
1971 /* */
1972 static FT_F26Dot6
1973 Round_To_Half_Grid( TT_ExecContext exc,
1974 FT_F26Dot6 distance,
1975 FT_F26Dot6 compensation )
1976 {
1977 FT_F26Dot6 val;
1978
1979 FT_UNUSED( exc );
1980
1981
1982 if ( distance >= 0 )
1983 {
1984 val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),
1985 32 );
1986 if ( val < 0 )
1987 val = 32;
1988 }
1989 else
1990 {
1991 val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,
1992 distance ) ),
1993 32 ) );
1994 if ( val > 0 )
1995 val = -32;
1996 }
1997
1998 return val;
1999 }
2000
2001
2002 /*************************************************************************/
2003 /* */
2004 /* <Function> */
2005 /* Round_Down_To_Grid */
2006 /* */
2007 /* <Description> */
2008 /* Rounds value down to grid after adding engine compensation. */
2009 /* */
2010 /* <Input> */
2011 /* distance :: The distance to round. */
2012 /* */
2013 /* compensation :: The engine compensation. */
2014 /* */
2015 /* <Return> */
2016 /* Rounded distance. */
2017 /* */
2018 static FT_F26Dot6
2019 Round_Down_To_Grid( TT_ExecContext exc,
2020 FT_F26Dot6 distance,
2021 FT_F26Dot6 compensation )
2022 {
2023 FT_F26Dot6 val;
2024
2025 FT_UNUSED( exc );
2026
2027
2028 if ( distance >= 0 )
2029 {
2030 val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );
2031 if ( val < 0 )
2032 val = 0;
2033 }
2034 else
2035 {
2036 val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );
2037 if ( val > 0 )
2038 val = 0;
2039 }
2040
2041 return val;
2042 }
2043
2044
2045 /*************************************************************************/
2046 /* */
2047 /* <Function> */
2048 /* Round_Up_To_Grid */
2049 /* */
2050 /* <Description> */
2051 /* Rounds value up to grid after adding engine compensation. */
2052 /* */
2053 /* <Input> */
2054 /* distance :: The distance to round. */
2055 /* */
2056 /* compensation :: The engine compensation. */
2057 /* */
2058 /* <Return> */
2059 /* Rounded distance. */
2060 /* */
2061 static FT_F26Dot6
2062 Round_Up_To_Grid( TT_ExecContext exc,
2063 FT_F26Dot6 distance,
2064 FT_F26Dot6 compensation )
2065 {
2066 FT_F26Dot6 val;
2067
2068 FT_UNUSED( exc );
2069
2070
2071 if ( distance >= 0 )
2072 {
2073 val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );
2074 if ( val < 0 )
2075 val = 0;
2076 }
2077 else
2078 {
2079 val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,
2080 distance ) ) );
2081 if ( val > 0 )
2082 val = 0;
2083 }
2084
2085 return val;
2086 }
2087
2088
2089 /*************************************************************************/
2090 /* */
2091 /* <Function> */
2092 /* Round_To_Double_Grid */
2093 /* */
2094 /* <Description> */
2095 /* Rounds value to double grid after adding engine compensation. */
2096 /* */
2097 /* <Input> */
2098 /* distance :: The distance to round. */
2099 /* */
2100 /* compensation :: The engine compensation. */
2101 /* */
2102 /* <Return> */
2103 /* Rounded distance. */
2104 /* */
2105 static FT_F26Dot6
2106 Round_To_Double_Grid( TT_ExecContext exc,
2107 FT_F26Dot6 distance,
2108 FT_F26Dot6 compensation )
2109 {
2110 FT_F26Dot6 val;
2111
2112 FT_UNUSED( exc );
2113
2114
2115 if ( distance >= 0 )
2116 {
2117 val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );
2118 if ( val < 0 )
2119 val = 0;
2120 }
2121 else
2122 {
2123 val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),
2124 32 ) );
2125 if ( val > 0 )
2126 val = 0;
2127 }
2128
2129 return val;
2130 }
2131
2132
2133 /*************************************************************************/
2134 /* */
2135 /* <Function> */
2136 /* Round_Super */
2137 /* */
2138 /* <Description> */
2139 /* Super-rounds value to grid after adding engine compensation. */
2140 /* */
2141 /* <Input> */
2142 /* distance :: The distance to round. */
2143 /* */
2144 /* compensation :: The engine compensation. */
2145 /* */
2146 /* <Return> */
2147 /* Rounded distance. */
2148 /* */
2149 /* <Note> */
2150 /* The TrueType specification says very little about the relationship */
2151 /* between rounding and engine compensation. However, it seems from */
2152 /* the description of super round that we should add the compensation */
2153 /* before rounding. */
2154 /* */
2155 static FT_F26Dot6
2156 Round_Super( TT_ExecContext exc,
2157 FT_F26Dot6 distance,
2158 FT_F26Dot6 compensation )
2159 {
2160 FT_F26Dot6 val;
2161
2162
2163 if ( distance >= 0 )
2164 {
2165 val = ADD_LONG( distance,
2166 exc->threshold - exc->phase + compensation ) &
2167 -exc->period;
2168 val = ADD_LONG( val, exc->phase );
2169 if ( val < 0 )
2170 val = exc->phase;
2171 }
2172 else
2173 {
2174 val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,
2175 distance ) &
2176 -exc->period );
2177 val = SUB_LONG( val, exc->phase );
2178 if ( val > 0 )
2179 val = -exc->phase;
2180 }
2181
2182 return val;
2183 }
2184
2185
2186 /*************************************************************************/
2187 /* */
2188 /* <Function> */
2189 /* Round_Super_45 */
2190 /* */
2191 /* <Description> */
2192 /* Super-rounds value to grid after adding engine compensation. */
2193 /* */
2194 /* <Input> */
2195 /* distance :: The distance to round. */
2196 /* */
2197 /* compensation :: The engine compensation. */
2198 /* */
2199 /* <Return> */
2200 /* Rounded distance. */
2201 /* */
2202 /* <Note> */
2203 /* There is a separate function for Round_Super_45() as we may need */
2204 /* greater precision. */
2205 /* */
2206 static FT_F26Dot6
2207 Round_Super_45( TT_ExecContext exc,
2208 FT_F26Dot6 distance,
2209 FT_F26Dot6 compensation )
2210 {
2211 FT_F26Dot6 val;
2212
2213
2214 if ( distance >= 0 )
2215 {
2216 val = ( ADD_LONG( distance,
2217 exc->threshold - exc->phase + compensation ) /
2218 exc->period ) * exc->period;
2219 val = ADD_LONG( val, exc->phase );
2220 if ( val < 0 )
2221 val = exc->phase;
2222 }
2223 else
2224 {
2225 val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,
2226 distance ) /
2227 exc->period ) * exc->period );
2228 val = SUB_LONG( val, exc->phase );
2229 if ( val > 0 )
2230 val = -exc->phase;
2231 }
2232
2233 return val;
2234 }
2235
2236
2237 /*************************************************************************/
2238 /* */
2239 /* <Function> */
2240 /* Compute_Round */
2241 /* */
2242 /* <Description> */
2243 /* Sets the rounding mode. */
2244 /* */
2245 /* <Input> */
2246 /* round_mode :: The rounding mode to be used. */
2247 /* */
2248 static void
2249 Compute_Round( TT_ExecContext exc,
2250 FT_Byte round_mode )
2251 {
2252 switch ( round_mode )
2253 {
2254 case TT_Round_Off:
2255 exc->func_round = (TT_Round_Func)Round_None;
2256 break;
2257
2258 case TT_Round_To_Grid:
2259 exc->func_round = (TT_Round_Func)Round_To_Grid;
2260 break;
2261
2262 case TT_Round_Up_To_Grid:
2263 exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
2264 break;
2265
2266 case TT_Round_Down_To_Grid:
2267 exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
2269
2270 case TT_Round_To_Half_Grid:
2271 exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
2272 break;
2273
2274 case TT_Round_To_Double_Grid:
2275 exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
2276 break;
2277
2278 case TT_Round_Super:
2279 exc->func_round = (TT_Round_Func)Round_Super;
2280 break;
2281
2282 case TT_Round_Super_45:
2283 exc->func_round = (TT_Round_Func)Round_Super_45;
2284 break;
2285 }
2286 }
2287
2288
2289 /*************************************************************************/
2290 /* */
2291 /* <Function> */
2292 /* SetSuperRound */
2293 /* */
2294 /* <Description> */
2295 /* Sets Super Round parameters. */
2296 /* */
2297 /* <Input> */
2298 /* GridPeriod :: The grid period. */
2299 /* */
2300 /* selector :: The SROUND opcode. */
2301 /* */
2302 static void
2303 SetSuperRound( TT_ExecContext exc,
2304 FT_F2Dot14 GridPeriod,
2305 FT_Long selector )
2306 {
2307 switch ( (FT_Int)( selector & 0xC0 ) )
2308 {
2309 case 0:
2310 exc->period = GridPeriod / 2;
2311 break;
2312
2313 case 0x40:
2314 exc->period = GridPeriod;
2315 break;
2316
2317 case 0x80:
2318 exc->period = GridPeriod * 2;
2319 break;
2320
2321 /* This opcode is reserved, but... */
2338 exc->phase = exc->period / 2;
2339 break;
2340
2341 case 0x30:
2342 exc->phase = exc->period * 3 / 4;
2343 break;
2344 }
2345
2346 if ( ( selector & 0x0F ) == 0 )
2347 exc->threshold = exc->period - 1;
2348 else
2349 exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;
2350
2351 /* convert to F26Dot6 format */
2352 exc->period >>= 8;
2353 exc->phase >>= 8;
2354 exc->threshold >>= 8;
2355 }
2356
2357
2358 /*************************************************************************/
2359 /* */
2360 /* <Function> */
2361 /* Project */
2362 /* */
2363 /* <Description> */
2364 /* Computes the projection of vector given by (v2-v1) along the */
2365 /* current projection vector. */
2366 /* */
2367 /* <Input> */
2368 /* v1 :: First input vector. */
2369 /* v2 :: Second input vector. */
2370 /* */
2371 /* <Return> */
2372 /* The distance in F26dot6 format. */
2373 /* */
2374 static FT_F26Dot6
2375 Project( TT_ExecContext exc,
2376 FT_Pos dx,
2377 FT_Pos dy )
2378 {
2379 return TT_DotFix14( dx, dy,
2380 exc->GS.projVector.x,
2381 exc->GS.projVector.y );
2382 }
2383
2384
2385 /*************************************************************************/
2386 /* */
2387 /* <Function> */
2388 /* Dual_Project */
2389 /* */
2390 /* <Description> */
2391 /* Computes the projection of the vector given by (v2-v1) along the */
2392 /* current dual vector. */
2393 /* */
2394 /* <Input> */
2395 /* v1 :: First input vector. */
2396 /* v2 :: Second input vector. */
2397 /* */
2398 /* <Return> */
2399 /* The distance in F26dot6 format. */
2400 /* */
2401 static FT_F26Dot6
2402 Dual_Project( TT_ExecContext exc,
2403 FT_Pos dx,
2404 FT_Pos dy )
2405 {
2406 return TT_DotFix14( dx, dy,
2407 exc->GS.dualVector.x,
2408 exc->GS.dualVector.y );
2409 }
2410
2411
2412 /*************************************************************************/
2413 /* */
2414 /* <Function> */
2415 /* Project_x */
2416 /* */
2417 /* <Description> */
2418 /* Computes the projection of the vector given by (v2-v1) along the */
2419 /* horizontal axis. */
2420 /* */
2421 /* <Input> */
2422 /* v1 :: First input vector. */
2423 /* v2 :: Second input vector. */
2424 /* */
2425 /* <Return> */
2426 /* The distance in F26dot6 format. */
2427 /* */
2428 static FT_F26Dot6
2429 Project_x( TT_ExecContext exc,
2430 FT_Pos dx,
2431 FT_Pos dy )
2432 {
2433 FT_UNUSED( exc );
2434 FT_UNUSED( dy );
2435
2436 return dx;
2437 }
2438
2439
2440 /*************************************************************************/
2441 /* */
2442 /* <Function> */
2443 /* Project_y */
2444 /* */
2445 /* <Description> */
2446 /* Computes the projection of the vector given by (v2-v1) along the */
2447 /* vertical axis. */
2448 /* */
2449 /* <Input> */
2450 /* v1 :: First input vector. */
2451 /* v2 :: Second input vector. */
2452 /* */
2453 /* <Return> */
2454 /* The distance in F26dot6 format. */
2455 /* */
2456 static FT_F26Dot6
2457 Project_y( TT_ExecContext exc,
2458 FT_Pos dx,
2459 FT_Pos dy )
2460 {
2461 FT_UNUSED( exc );
2462 FT_UNUSED( dx );
2463
2464 return dy;
2465 }
2466
2467
2468 /*************************************************************************/
2469 /* */
2470 /* <Function> */
2471 /* Compute_Funcs */
2472 /* */
2473 /* <Description> */
2474 /* Computes the projection and movement function pointers according */
2475 /* to the current graphics state. */
2476 /* */
2477 static void
2478 Compute_Funcs( TT_ExecContext exc )
2479 {
2480 if ( exc->GS.freeVector.x == 0x4000 )
2481 exc->F_dot_P = exc->GS.projVector.x;
2482 else if ( exc->GS.freeVector.y == 0x4000 )
2483 exc->F_dot_P = exc->GS.projVector.y;
2484 else
2485 exc->F_dot_P =
2486 ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
2487 (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
2488
2489 if ( exc->GS.projVector.x == 0x4000 )
2490 exc->func_project = (TT_Project_Func)Project_x;
2491 else if ( exc->GS.projVector.y == 0x4000 )
2492 exc->func_project = (TT_Project_Func)Project_y;
2493 else
2494 exc->func_project = (TT_Project_Func)Project;
2495
2496 if ( exc->GS.dualVector.x == 0x4000 )
2511 exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2512 }
2513 else if ( exc->GS.freeVector.y == 0x4000 )
2514 {
2515 exc->func_move = (TT_Move_Func)Direct_Move_Y;
2516 exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2517 }
2518 }
2519
2520 /* at small sizes, F_dot_P can become too small, resulting */
2521 /* in overflows and `spikes' in a number of glyphs like `w'. */
2522
2523 if ( FT_ABS( exc->F_dot_P ) < 0x400L )
2524 exc->F_dot_P = 0x4000L;
2525
2526 /* Disable cached aspect ratio */
2527 exc->tt_metrics.ratio = 0;
2528 }
2529
2530
2531 /*************************************************************************/
2532 /* */
2533 /* <Function> */
2534 /* Normalize */
2535 /* */
2536 /* <Description> */
2537 /* Norms a vector. */
2538 /* */
2539 /* <Input> */
2540 /* Vx :: The horizontal input vector coordinate. */
2541 /* Vy :: The vertical input vector coordinate. */
2542 /* */
2543 /* <Output> */
2544 /* R :: The normed unit vector. */
2545 /* */
2546 /* <Return> */
2547 /* Returns FAILURE if a vector parameter is zero. */
2548 /* */
2549 /* <Note> */
2550 /* In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and */
2551 /* R is undefined. */
2552 /* */
2553 static FT_Bool
2554 Normalize( FT_F26Dot6 Vx,
2555 FT_F26Dot6 Vy,
2556 FT_UnitVector* R )
2557 {
2558 FT_Vector V;
2559
2560
2561 if ( Vx == 0 && Vy == 0 )
2562 {
2563 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2564 /* to normalize the vector (0,0). Return immediately. */
2565 return SUCCESS;
2566 }
2567
2568 V.x = Vx;
2569 V.y = Vy;
2570
2571 FT_Vector_NormLen( &V );
2572
2573 R->x = (FT_F2Dot14)( V.x / 4 );
2574 R->y = (FT_F2Dot14)( V.y / 4 );
2575
2576 return SUCCESS;
2577 }
2578
2579
2580 /*************************************************************************/
2581 /* */
2582 /* Here we start with the implementation of the various opcodes. */
2583 /* */
2584 /*************************************************************************/
2585
2586
2587 #define ARRAY_BOUND_ERROR \
2588 do \
2589 { \
2590 exc->error = FT_THROW( Invalid_Reference ); \
2591 return; \
2592 } while (0)
2593
2594
2595 /*************************************************************************/
2596 /* */
2597 /* MPPEM[]: Measure Pixel Per EM */
2598 /* Opcode range: 0x4B */
2599 /* Stack: --> Euint16 */
2600 /* */
2601 static void
2602 Ins_MPPEM( TT_ExecContext exc,
2603 FT_Long* args )
2604 {
2605 args[0] = exc->func_cur_ppem( exc );
2606 }
2607
2608
2609 /*************************************************************************/
2610 /* */
2611 /* MPS[]: Measure Point Size */
2612 /* Opcode range: 0x4C */
2613 /* Stack: --> Euint16 */
2614 /* */
2615 static void
2616 Ins_MPS( TT_ExecContext exc,
2617 FT_Long* args )
2618 {
2619 if ( NO_SUBPIXEL_HINTING )
2620 {
2621 /* Microsoft's GDI bytecode interpreter always returns value 12; */
2622 /* we return the current PPEM value instead. */
2623 args[0] = exc->func_cur_ppem( exc );
2624 }
2625 else
2626 {
2627 /* A possible practical application of the MPS instruction is to */
2628 /* implement optical scaling and similar features, which should be */
2629 /* based on perceptual attributes, thus independent of the */
2630 /* resolution. */
2631 args[0] = exc->pointSize;
2632 }
2633 }
2634
2635
2636 /*************************************************************************/
2637 /* */
2638 /* DUP[]: DUPlicate the stack's top element */
2639 /* Opcode range: 0x20 */
2640 /* Stack: StkElt --> StkElt StkElt */
2641 /* */
2642 static void
2643 Ins_DUP( FT_Long* args )
2644 {
2645 args[1] = args[0];
2646 }
2647
2648
2649 /*************************************************************************/
2650 /* */
2651 /* POP[]: POP the stack's top element */
2652 /* Opcode range: 0x21 */
2653 /* Stack: StkElt --> */
2654 /* */
2655 static void
2656 Ins_POP( void )
2657 {
2658 /* nothing to do */
2659 }
2660
2661
2662 /*************************************************************************/
2663 /* */
2664 /* CLEAR[]: CLEAR the entire stack */
2665 /* Opcode range: 0x22 */
2666 /* Stack: StkElt... --> */
2667 /* */
2668 static void
2669 Ins_CLEAR( TT_ExecContext exc )
2670 {
2671 exc->new_top = 0;
2672 }
2673
2674
2675 /*************************************************************************/
2676 /* */
2677 /* SWAP[]: SWAP the stack's top two elements */
2678 /* Opcode range: 0x23 */
2679 /* Stack: 2 * StkElt --> 2 * StkElt */
2680 /* */
2681 static void
2682 Ins_SWAP( FT_Long* args )
2683 {
2684 FT_Long L;
2685
2686
2687 L = args[0];
2688 args[0] = args[1];
2689 args[1] = L;
2690 }
2691
2692
2693 /*************************************************************************/
2694 /* */
2695 /* DEPTH[]: return the stack DEPTH */
2696 /* Opcode range: 0x24 */
2697 /* Stack: --> uint32 */
2698 /* */
2699 static void
2700 Ins_DEPTH( TT_ExecContext exc,
2701 FT_Long* args )
2702 {
2703 args[0] = exc->top;
2704 }
2705
2706
2707 /*************************************************************************/
2708 /* */
2709 /* LT[]: Less Than */
2710 /* Opcode range: 0x50 */
2711 /* Stack: int32? int32? --> bool */
2712 /* */
2713 static void
2714 Ins_LT( FT_Long* args )
2715 {
2716 args[0] = ( args[0] < args[1] );
2717 }
2718
2719
2720 /*************************************************************************/
2721 /* */
2722 /* LTEQ[]: Less Than or EQual */
2723 /* Opcode range: 0x51 */
2724 /* Stack: int32? int32? --> bool */
2725 /* */
2726 static void
2727 Ins_LTEQ( FT_Long* args )
2728 {
2729 args[0] = ( args[0] <= args[1] );
2730 }
2731
2732
2733 /*************************************************************************/
2734 /* */
2735 /* GT[]: Greater Than */
2736 /* Opcode range: 0x52 */
2737 /* Stack: int32? int32? --> bool */
2738 /* */
2739 static void
2740 Ins_GT( FT_Long* args )
2741 {
2742 args[0] = ( args[0] > args[1] );
2743 }
2744
2745
2746 /*************************************************************************/
2747 /* */
2748 /* GTEQ[]: Greater Than or EQual */
2749 /* Opcode range: 0x53 */
2750 /* Stack: int32? int32? --> bool */
2751 /* */
2752 static void
2753 Ins_GTEQ( FT_Long* args )
2754 {
2755 args[0] = ( args[0] >= args[1] );
2756 }
2757
2758
2759 /*************************************************************************/
2760 /* */
2761 /* EQ[]: EQual */
2762 /* Opcode range: 0x54 */
2763 /* Stack: StkElt StkElt --> bool */
2764 /* */
2765 static void
2766 Ins_EQ( FT_Long* args )
2767 {
2768 args[0] = ( args[0] == args[1] );
2769 }
2770
2771
2772 /*************************************************************************/
2773 /* */
2774 /* NEQ[]: Not EQual */
2775 /* Opcode range: 0x55 */
2776 /* Stack: StkElt StkElt --> bool */
2777 /* */
2778 static void
2779 Ins_NEQ( FT_Long* args )
2780 {
2781 args[0] = ( args[0] != args[1] );
2782 }
2783
2784
2785 /*************************************************************************/
2786 /* */
2787 /* ODD[]: Is ODD */
2788 /* Opcode range: 0x56 */
2789 /* Stack: f26.6 --> bool */
2790 /* */
2791 static void
2792 Ins_ODD( TT_ExecContext exc,
2793 FT_Long* args )
2794 {
2795 args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 );
2796 }
2797
2798
2799 /*************************************************************************/
2800 /* */
2801 /* EVEN[]: Is EVEN */
2802 /* Opcode range: 0x57 */
2803 /* Stack: f26.6 --> bool */
2804 /* */
2805 static void
2806 Ins_EVEN( TT_ExecContext exc,
2807 FT_Long* args )
2808 {
2809 args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 );
2810 }
2811
2812
2813 /*************************************************************************/
2814 /* */
2815 /* AND[]: logical AND */
2816 /* Opcode range: 0x5A */
2817 /* Stack: uint32 uint32 --> uint32 */
2818 /* */
2819 static void
2820 Ins_AND( FT_Long* args )
2821 {
2822 args[0] = ( args[0] && args[1] );
2823 }
2824
2825
2826 /*************************************************************************/
2827 /* */
2828 /* OR[]: logical OR */
2829 /* Opcode range: 0x5B */
2830 /* Stack: uint32 uint32 --> uint32 */
2831 /* */
2832 static void
2833 Ins_OR( FT_Long* args )
2834 {
2835 args[0] = ( args[0] || args[1] );
2836 }
2837
2838
2839 /*************************************************************************/
2840 /* */
2841 /* NOT[]: logical NOT */
2842 /* Opcode range: 0x5C */
2843 /* Stack: StkElt --> uint32 */
2844 /* */
2845 static void
2846 Ins_NOT( FT_Long* args )
2847 {
2848 args[0] = !args[0];
2849 }
2850
2851
2852 /*************************************************************************/
2853 /* */
2854 /* ADD[]: ADD */
2855 /* Opcode range: 0x60 */
2856 /* Stack: f26.6 f26.6 --> f26.6 */
2857 /* */
2858 static void
2859 Ins_ADD( FT_Long* args )
2860 {
2861 args[0] = ADD_LONG( args[0], args[1] );
2862 }
2863
2864
2865 /*************************************************************************/
2866 /* */
2867 /* SUB[]: SUBtract */
2868 /* Opcode range: 0x61 */
2869 /* Stack: f26.6 f26.6 --> f26.6 */
2870 /* */
2871 static void
2872 Ins_SUB( FT_Long* args )
2873 {
2874 args[0] = SUB_LONG( args[0], args[1] );
2875 }
2876
2877
2878 /*************************************************************************/
2879 /* */
2880 /* DIV[]: DIVide */
2881 /* Opcode range: 0x62 */
2882 /* Stack: f26.6 f26.6 --> f26.6 */
2883 /* */
2884 static void
2885 Ins_DIV( TT_ExecContext exc,
2886 FT_Long* args )
2887 {
2888 if ( args[1] == 0 )
2889 exc->error = FT_THROW( Divide_By_Zero );
2890 else
2891 args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
2892 }
2893
2894
2895 /*************************************************************************/
2896 /* */
2897 /* MUL[]: MULtiply */
2898 /* Opcode range: 0x63 */
2899 /* Stack: f26.6 f26.6 --> f26.6 */
2900 /* */
2901 static void
2902 Ins_MUL( FT_Long* args )
2903 {
2904 args[0] = FT_MulDiv( args[0], args[1], 64L );
2905 }
2906
2907
2908 /*************************************************************************/
2909 /* */
2910 /* ABS[]: ABSolute value */
2911 /* Opcode range: 0x64 */
2912 /* Stack: f26.6 --> f26.6 */
2913 /* */
2914 static void
2915 Ins_ABS( FT_Long* args )
2916 {
2917 if ( args[0] < 0 )
2918 args[0] = NEG_LONG( args[0] );
2919 }
2920
2921
2922 /*************************************************************************/
2923 /* */
2924 /* NEG[]: NEGate */
2925 /* Opcode range: 0x65 */
2926 /* Stack: f26.6 --> f26.6 */
2927 /* */
2928 static void
2929 Ins_NEG( FT_Long* args )
2930 {
2931 args[0] = NEG_LONG( args[0] );
2932 }
2933
2934
2935 /*************************************************************************/
2936 /* */
2937 /* FLOOR[]: FLOOR */
2938 /* Opcode range: 0x66 */
2939 /* Stack: f26.6 --> f26.6 */
2940 /* */
2941 static void
2942 Ins_FLOOR( FT_Long* args )
2943 {
2944 args[0] = FT_PIX_FLOOR( args[0] );
2945 }
2946
2947
2948 /*************************************************************************/
2949 /* */
2950 /* CEILING[]: CEILING */
2951 /* Opcode range: 0x67 */
2952 /* Stack: f26.6 --> f26.6 */
2953 /* */
2954 static void
2955 Ins_CEILING( FT_Long* args )
2956 {
2957 args[0] = FT_PIX_CEIL_LONG( args[0] );
2958 }
2959
2960
2961 /*************************************************************************/
2962 /* */
2963 /* RS[]: Read Store */
2964 /* Opcode range: 0x43 */
2965 /* Stack: uint32 --> uint32 */
2966 /* */
2967 static void
2968 Ins_RS( TT_ExecContext exc,
2969 FT_Long* args )
2970 {
2971 FT_ULong I = (FT_ULong)args[0];
2972
2973
2974 if ( BOUNDSL( I, exc->storeSize ) )
2975 {
2976 if ( exc->pedantic_hinting )
2977 ARRAY_BOUND_ERROR;
2978 else
2979 args[0] = 0;
2980 }
2981 else
2982 {
2983 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2984 /* subpixel hinting - avoid Typeman Dstroke and */
2985 /* IStroke and Vacuform rounds */
2986 if ( SUBPIXEL_HINTING_INFINALITY &&
2987 exc->ignore_x_mode &&
2988 ( ( I == 24 &&
2989 ( exc->face->sph_found_func_flags &
2990 ( SPH_FDEF_SPACING_1 |
2991 SPH_FDEF_SPACING_2 ) ) ) ||
2992 ( I == 22 &&
2993 ( exc->sph_in_func_flags &
2994 SPH_FDEF_TYPEMAN_STROKES ) ) ||
2995 ( I == 8 &&
2996 ( exc->face->sph_found_func_flags &
2997 SPH_FDEF_VACUFORM_ROUND_1 ) &&
2998 exc->iup_called ) ) )
2999 args[0] = 0;
3000 else
3001 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3002 args[0] = exc->storage[I];
3003 }
3004 }
3005
3006
3007 /*************************************************************************/
3008 /* */
3009 /* WS[]: Write Store */
3010 /* Opcode range: 0x42 */
3011 /* Stack: uint32 uint32 --> */
3012 /* */
3013 static void
3014 Ins_WS( TT_ExecContext exc,
3015 FT_Long* args )
3016 {
3017 FT_ULong I = (FT_ULong)args[0];
3018
3019
3020 if ( BOUNDSL( I, exc->storeSize ) )
3021 {
3022 if ( exc->pedantic_hinting )
3023 ARRAY_BOUND_ERROR;
3024 }
3025 else
3026 exc->storage[I] = args[1];
3027 }
3028
3029
3030 /*************************************************************************/
3031 /* */
3032 /* WCVTP[]: Write CVT in Pixel units */
3033 /* Opcode range: 0x44 */
3034 /* Stack: f26.6 uint32 --> */
3035 /* */
3036 static void
3037 Ins_WCVTP( TT_ExecContext exc,
3038 FT_Long* args )
3039 {
3040 FT_ULong I = (FT_ULong)args[0];
3041
3042
3043 if ( BOUNDSL( I, exc->cvtSize ) )
3044 {
3045 if ( exc->pedantic_hinting )
3046 ARRAY_BOUND_ERROR;
3047 }
3048 else
3049 exc->func_write_cvt( exc, I, args[1] );
3050 }
3051
3052
3053 /*************************************************************************/
3054 /* */
3055 /* WCVTF[]: Write CVT in Funits */
3056 /* Opcode range: 0x70 */
3057 /* Stack: uint32 uint32 --> */
3058 /* */
3059 static void
3060 Ins_WCVTF( TT_ExecContext exc,
3061 FT_Long* args )
3062 {
3063 FT_ULong I = (FT_ULong)args[0];
3064
3065
3066 if ( BOUNDSL( I, exc->cvtSize ) )
3067 {
3068 if ( exc->pedantic_hinting )
3069 ARRAY_BOUND_ERROR;
3070 }
3071 else
3072 exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );
3073 }
3074
3075
3076 /*************************************************************************/
3077 /* */
3078 /* RCVT[]: Read CVT */
3079 /* Opcode range: 0x45 */
3080 /* Stack: uint32 --> f26.6 */
3081 /* */
3082 static void
3083 Ins_RCVT( TT_ExecContext exc,
3084 FT_Long* args )
3085 {
3086 FT_ULong I = (FT_ULong)args[0];
3087
3088
3089 if ( BOUNDSL( I, exc->cvtSize ) )
3090 {
3091 if ( exc->pedantic_hinting )
3092 ARRAY_BOUND_ERROR;
3093 else
3094 args[0] = 0;
3095 }
3096 else
3097 args[0] = exc->func_read_cvt( exc, I );
3098 }
3099
3100
3101 /*************************************************************************/
3102 /* */
3103 /* AA[]: Adjust Angle */
3104 /* Opcode range: 0x7F */
3105 /* Stack: uint32 --> */
3106 /* */
3107 static void
3108 Ins_AA( void )
3109 {
3110 /* intentionally no longer supported */
3111 }
3112
3113
3114 /*************************************************************************/
3115 /* */
3116 /* DEBUG[]: DEBUG. Unsupported. */
3117 /* Opcode range: 0x4F */
3118 /* Stack: uint32 --> */
3119 /* */
3120 /* Note: The original instruction pops a value from the stack. */
3121 /* */
3122 static void
3123 Ins_DEBUG( TT_ExecContext exc )
3124 {
3125 exc->error = FT_THROW( Debug_OpCode );
3126 }
3127
3128
3129 /*************************************************************************/
3130 /* */
3131 /* ROUND[ab]: ROUND value */
3132 /* Opcode range: 0x68-0x6B */
3133 /* Stack: f26.6 --> f26.6 */
3134 /* */
3135 static void
3136 Ins_ROUND( TT_ExecContext exc,
3137 FT_Long* args )
3138 {
3139 args[0] = exc->func_round(
3140 exc,
3141 args[0],
3142 exc->tt_metrics.compensations[exc->opcode - 0x68] );
3143 }
3144
3145
3146 /*************************************************************************/
3147 /* */
3148 /* NROUND[ab]: No ROUNDing of value */
3149 /* Opcode range: 0x6C-0x6F */
3150 /* Stack: f26.6 --> f26.6 */
3151 /* */
3152 static void
3153 Ins_NROUND( TT_ExecContext exc,
3154 FT_Long* args )
3155 {
3156 args[0] = Round_None(
3157 exc,
3158 args[0],
3159 exc->tt_metrics.compensations[exc->opcode - 0x6C] );
3160 }
3161
3162
3163 /*************************************************************************/
3164 /* */
3165 /* MAX[]: MAXimum */
3166 /* Opcode range: 0x8B */
3167 /* Stack: int32? int32? --> int32 */
3168 /* */
3169 static void
3170 Ins_MAX( FT_Long* args )
3171 {
3172 if ( args[1] > args[0] )
3173 args[0] = args[1];
3174 }
3175
3176
3177 /*************************************************************************/
3178 /* */
3179 /* MIN[]: MINimum */
3180 /* Opcode range: 0x8C */
3181 /* Stack: int32? int32? --> int32 */
3182 /* */
3183 static void
3184 Ins_MIN( FT_Long* args )
3185 {
3186 if ( args[1] < args[0] )
3187 args[0] = args[1];
3188 }
3189
3190
3191 /*************************************************************************/
3192 /* */
3193 /* MINDEX[]: Move INDEXed element */
3194 /* Opcode range: 0x26 */
3195 /* Stack: int32? --> StkElt */
3196 /* */
3197 static void
3198 Ins_MINDEX( TT_ExecContext exc,
3199 FT_Long* args )
3200 {
3201 FT_Long L, K;
3202
3203
3204 L = args[0];
3205
3206 if ( L <= 0 || L > exc->args )
3207 {
3208 if ( exc->pedantic_hinting )
3209 exc->error = FT_THROW( Invalid_Reference );
3210 }
3211 else
3212 {
3213 K = exc->stack[exc->args - L];
3214
3215 FT_ARRAY_MOVE( &exc->stack[exc->args - L ],
3216 &exc->stack[exc->args - L + 1],
3217 ( L - 1 ) );
3218
3219 exc->stack[exc->args - 1] = K;
3220 }
3221 }
3222
3223
3224 /*************************************************************************/
3225 /* */
3226 /* CINDEX[]: Copy INDEXed element */
3227 /* Opcode range: 0x25 */
3228 /* Stack: int32 --> StkElt */
3229 /* */
3230 static void
3231 Ins_CINDEX( TT_ExecContext exc,
3232 FT_Long* args )
3233 {
3234 FT_Long L;
3235
3236
3237 L = args[0];
3238
3239 if ( L <= 0 || L > exc->args )
3240 {
3241 if ( exc->pedantic_hinting )
3242 exc->error = FT_THROW( Invalid_Reference );
3243 args[0] = 0;
3244 }
3245 else
3246 args[0] = exc->stack[exc->args - L];
3247 }
3248
3249
3250 /*************************************************************************/
3251 /* */
3252 /* ROLL[]: ROLL top three elements */
3253 /* Opcode range: 0x8A */
3254 /* Stack: 3 * StkElt --> 3 * StkElt */
3255 /* */
3256 static void
3257 Ins_ROLL( FT_Long* args )
3258 {
3259 FT_Long A, B, C;
3260
3261
3262 A = args[2];
3263 B = args[1];
3264 C = args[0];
3265
3266 args[2] = C;
3267 args[1] = A;
3268 args[0] = B;
3269 }
3270
3271
3272 /*************************************************************************/
3273 /* */
3274 /* MANAGING THE FLOW OF CONTROL */
3275 /* */
3276 /*************************************************************************/
3277
3278
3279 /*************************************************************************/
3280 /* */
3281 /* SLOOP[]: Set LOOP variable */
3282 /* Opcode range: 0x17 */
3283 /* Stack: int32? --> */
3284 /* */
3285 static void
3286 Ins_SLOOP( TT_ExecContext exc,
3287 FT_Long* args )
3288 {
3289 if ( args[0] < 0 )
3290 exc->error = FT_THROW( Bad_Argument );
3291 else
3292 {
3293 /* we heuristically limit the number of loops to 16 bits */
3294 exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0];
3295 }
3296 }
3297
3298
3299 static FT_Bool
3300 SkipCode( TT_ExecContext exc )
3301 {
3302 exc->IP += exc->length;
3303
3304 if ( exc->IP < exc->codeSize )
3306 exc->opcode = exc->code[exc->IP];
3307
3308 exc->length = opcode_length[exc->opcode];
3309 if ( exc->length < 0 )
3310 {
3311 if ( exc->IP + 1 >= exc->codeSize )
3312 goto Fail_Overflow;
3313 exc->length = 2 - exc->length * exc->code[exc->IP + 1];
3314 }
3315
3316 if ( exc->IP + exc->length <= exc->codeSize )
3317 return SUCCESS;
3318 }
3319
3320 Fail_Overflow:
3321 exc->error = FT_THROW( Code_Overflow );
3322 return FAILURE;
3323 }
3324
3325
3326 /*************************************************************************/
3327 /* */
3328 /* IF[]: IF test */
3329 /* Opcode range: 0x58 */
3330 /* Stack: StkElt --> */
3331 /* */
3332 static void
3333 Ins_IF( TT_ExecContext exc,
3334 FT_Long* args )
3335 {
3336 FT_Int nIfs;
3337 FT_Bool Out;
3338
3339
3340 if ( args[0] != 0 )
3341 return;
3342
3343 nIfs = 1;
3344 Out = 0;
3345
3346 do
3347 {
3348 if ( SkipCode( exc ) == FAILURE )
3349 return;
3350
3351 switch ( exc->opcode )
3352 {
3353 case 0x58: /* IF */
3354 nIfs++;
3355 break;
3356
3357 case 0x1B: /* ELSE */
3358 Out = FT_BOOL( nIfs == 1 );
3359 break;
3360
3361 case 0x59: /* EIF */
3362 nIfs--;
3363 Out = FT_BOOL( nIfs == 0 );
3364 break;
3365 }
3366 } while ( Out == 0 );
3367 }
3368
3369
3370 /*************************************************************************/
3371 /* */
3372 /* ELSE[]: ELSE */
3373 /* Opcode range: 0x1B */
3374 /* Stack: --> */
3375 /* */
3376 static void
3377 Ins_ELSE( TT_ExecContext exc )
3378 {
3379 FT_Int nIfs;
3380
3381
3382 nIfs = 1;
3383
3384 do
3385 {
3386 if ( SkipCode( exc ) == FAILURE )
3387 return;
3388
3389 switch ( exc->opcode )
3390 {
3391 case 0x58: /* IF */
3392 nIfs++;
3393 break;
3394
3395 case 0x59: /* EIF */
3396 nIfs--;
3397 break;
3398 }
3399 } while ( nIfs != 0 );
3400 }
3401
3402
3403 /*************************************************************************/
3404 /* */
3405 /* EIF[]: End IF */
3406 /* Opcode range: 0x59 */
3407 /* Stack: --> */
3408 /* */
3409 static void
3410 Ins_EIF( void )
3411 {
3412 /* nothing to do */
3413 }
3414
3415
3416 /*************************************************************************/
3417 /* */
3418 /* JMPR[]: JuMP Relative */
3419 /* Opcode range: 0x1C */
3420 /* Stack: int32 --> */
3421 /* */
3422 static void
3423 Ins_JMPR( TT_ExecContext exc,
3424 FT_Long* args )
3425 {
3426 if ( args[0] == 0 && exc->args == 0 )
3427 {
3428 exc->error = FT_THROW( Bad_Argument );
3429 return;
3430 }
3431
3432 exc->IP += args[0];
3433 if ( exc->IP < 0 ||
3434 ( exc->callTop > 0 &&
3435 exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
3436 {
3437 exc->error = FT_THROW( Bad_Argument );
3438 return;
3439 }
3440
3441 exc->step_ins = FALSE;
3442
3443 if ( args[0] < 0 )
3444 {
3445 if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
3446 exc->error = FT_THROW( Execution_Too_Long );
3447 }
3448 }
3449
3450
3451 /*************************************************************************/
3452 /* */
3453 /* JROT[]: Jump Relative On True */
3454 /* Opcode range: 0x78 */
3455 /* Stack: StkElt int32 --> */
3456 /* */
3457 static void
3458 Ins_JROT( TT_ExecContext exc,
3459 FT_Long* args )
3460 {
3461 if ( args[1] != 0 )
3462 Ins_JMPR( exc, args );
3463 }
3464
3465
3466 /*************************************************************************/
3467 /* */
3468 /* JROF[]: Jump Relative On False */
3469 /* Opcode range: 0x79 */
3470 /* Stack: StkElt int32 --> */
3471 /* */
3472 static void
3473 Ins_JROF( TT_ExecContext exc,
3474 FT_Long* args )
3475 {
3476 if ( args[1] == 0 )
3477 Ins_JMPR( exc, args );
3478 }
3479
3480
3481 /*************************************************************************/
3482 /* */
3483 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
3484 /* */
3485 /*************************************************************************/
3486
3487
3488 /*************************************************************************/
3489 /* */
3490 /* FDEF[]: Function DEFinition */
3491 /* Opcode range: 0x2C */
3492 /* Stack: uint32 --> */
3493 /* */
3494 static void
3495 Ins_FDEF( TT_ExecContext exc,
3496 FT_Long* args )
3497 {
3498 FT_ULong n;
3499 TT_DefRecord* rec;
3500 TT_DefRecord* limit;
3501
3502 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3503 /* arguments to opcodes are skipped by `SKIP_Code' */
3504 FT_Byte opcode_pattern[9][12] = {
3505 /* #0 inline delta function 1 */
3506 {
3507 0x4B, /* PPEM */
3508 0x53, /* GTEQ */
3509 0x23, /* SWAP */
3510 0x4B, /* PPEM */
3511 0x51, /* LTEQ */
3512 0x5A, /* AND */
3513 0x58, /* IF */
3771 ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
3772 }
3773
3774 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3775
3776 switch ( exc->opcode )
3777 {
3778 case 0x89: /* IDEF */
3779 case 0x2C: /* FDEF */
3780 exc->error = FT_THROW( Nested_DEFS );
3781 return;
3782
3783 case 0x2D: /* ENDF */
3784 rec->end = exc->IP;
3785 return;
3786 }
3787 }
3788 }
3789
3790
3791 /*************************************************************************/
3792 /* */
3793 /* ENDF[]: END Function definition */
3794 /* Opcode range: 0x2D */
3795 /* Stack: --> */
3796 /* */
3797 static void
3798 Ins_ENDF( TT_ExecContext exc )
3799 {
3800 TT_CallRec* pRec;
3801
3802
3803 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3804 exc->sph_in_func_flags = 0x0000;
3805 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3806
3807 if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */
3808 {
3809 exc->error = FT_THROW( ENDF_In_Exec_Stream );
3810 return;
3811 }
3812
3813 exc->callTop--;
3814
3815 pRec = &exc->callStack[exc->callTop];
3816
3820
3821 if ( pRec->Cur_Count > 0 )
3822 {
3823 exc->callTop++;
3824 exc->IP = pRec->Def->start;
3825 }
3826 else
3827 /* Loop through the current function */
3828 Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );
3829
3830 /* Exit the current call frame. */
3831
3832 /* NOTE: If the last instruction of a program is a */
3833 /* CALL or LOOPCALL, the return address is */
3834 /* always out of the code range. This is a */
3835 /* valid address, and it is why we do not test */
3836 /* the result of Ins_Goto_CodeRange() here! */
3837 }
3838
3839
3840 /*************************************************************************/
3841 /* */
3842 /* CALL[]: CALL function */
3843 /* Opcode range: 0x2B */
3844 /* Stack: uint32? --> */
3845 /* */
3846 static void
3847 Ins_CALL( TT_ExecContext exc,
3848 FT_Long* args )
3849 {
3850 FT_ULong F;
3851 TT_CallRec* pCrec;
3852 TT_DefRecord* def;
3853
3854
3855 /* first of all, check the index */
3856
3857 F = (FT_ULong)args[0];
3858 if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3859 goto Fail;
3860
3861 /* Except for some old Apple fonts, all functions in a TrueType */
3862 /* font are defined in increasing order, starting from 0. This */
3863 /* means that we normally have */
3864 /* */
3865 /* exc->maxFunc+1 == exc->numFDefs */
3909 pCrec = exc->callStack + exc->callTop;
3910
3911 pCrec->Caller_Range = exc->curRange;
3912 pCrec->Caller_IP = exc->IP + 1;
3913 pCrec->Cur_Count = 1;
3914 pCrec->Def = def;
3915
3916 exc->callTop++;
3917
3918 Ins_Goto_CodeRange( exc, def->range, def->start );
3919
3920 exc->step_ins = FALSE;
3921
3922 return;
3923
3924 Fail:
3925 exc->error = FT_THROW( Invalid_Reference );
3926 }
3927
3928
3929 /*************************************************************************/
3930 /* */
3931 /* LOOPCALL[]: LOOP and CALL function */
3932 /* Opcode range: 0x2A */
3933 /* Stack: uint32? Eint16? --> */
3934 /* */
3935 static void
3936 Ins_LOOPCALL( TT_ExecContext exc,
3937 FT_Long* args )
3938 {
3939 FT_ULong F;
3940 TT_CallRec* pCrec;
3941 TT_DefRecord* def;
3942
3943
3944 /* first of all, check the index */
3945 F = (FT_ULong)args[1];
3946 if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3947 goto Fail;
3948
3949 /* Except for some old Apple fonts, all functions in a TrueType */
3950 /* font are defined in increasing order, starting from 0. This */
3951 /* means that we normally have */
3952 /* */
3953 /* exc->maxFunc+1 == exc->numFDefs */
3954 /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */
4002 pCrec->Def = def;
4003
4004 exc->callTop++;
4005
4006 Ins_Goto_CodeRange( exc, def->range, def->start );
4007
4008 exc->step_ins = FALSE;
4009
4010 exc->loopcall_counter += (FT_ULong)args[0];
4011 if ( exc->loopcall_counter > exc->loopcall_counter_max )
4012 exc->error = FT_THROW( Execution_Too_Long );
4013 }
4014
4015 return;
4016
4017 Fail:
4018 exc->error = FT_THROW( Invalid_Reference );
4019 }
4020
4021
4022 /*************************************************************************/
4023 /* */
4024 /* IDEF[]: Instruction DEFinition */
4025 /* Opcode range: 0x89 */
4026 /* Stack: Eint8 --> */
4027 /* */
4028 static void
4029 Ins_IDEF( TT_ExecContext exc,
4030 FT_Long* args )
4031 {
4032 TT_DefRecord* def;
4033 TT_DefRecord* limit;
4034
4035
4036 /* we enable IDEF only in `prep' or `fpgm' */
4037 if ( exc->curRange == tt_coderange_glyph )
4038 {
4039 exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
4040 return;
4041 }
4042
4043 /* First of all, look for the same function in our table */
4044
4045 def = exc->IDefs;
4046 limit = def + exc->numIDefs;
4047
4077
4078 /* Now skip the whole function definition. */
4079 /* We don't allow nested IDEFs & FDEFs. */
4080
4081 while ( SkipCode( exc ) == SUCCESS )
4082 {
4083 switch ( exc->opcode )
4084 {
4085 case 0x89: /* IDEF */
4086 case 0x2C: /* FDEF */
4087 exc->error = FT_THROW( Nested_DEFS );
4088 return;
4089 case 0x2D: /* ENDF */
4090 def->end = exc->IP;
4091 return;
4092 }
4093 }
4094 }
4095
4096
4097 /*************************************************************************/
4098 /* */
4099 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4100 /* */
4101 /*************************************************************************/
4102
4103
4104 /*************************************************************************/
4105 /* */
4106 /* NPUSHB[]: PUSH N Bytes */
4107 /* Opcode range: 0x40 */
4108 /* Stack: --> uint32... */
4109 /* */
4110 static void
4111 Ins_NPUSHB( TT_ExecContext exc,
4112 FT_Long* args )
4113 {
4114 FT_UShort L, K;
4115
4116
4117 L = (FT_UShort)exc->code[exc->IP + 1];
4118
4119 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4120 {
4121 exc->error = FT_THROW( Stack_Overflow );
4122 return;
4123 }
4124
4125 for ( K = 1; K <= L; K++ )
4126 args[K - 1] = exc->code[exc->IP + K + 1];
4127
4128 exc->new_top += L;
4129 }
4130
4131
4132 /*************************************************************************/
4133 /* */
4134 /* NPUSHW[]: PUSH N Words */
4135 /* Opcode range: 0x41 */
4136 /* Stack: --> int32... */
4137 /* */
4138 static void
4139 Ins_NPUSHW( TT_ExecContext exc,
4140 FT_Long* args )
4141 {
4142 FT_UShort L, K;
4143
4144
4145 L = (FT_UShort)exc->code[exc->IP + 1];
4146
4147 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4148 {
4149 exc->error = FT_THROW( Stack_Overflow );
4150 return;
4151 }
4152
4153 exc->IP += 2;
4154
4155 for ( K = 0; K < L; K++ )
4156 args[K] = GetShortIns( exc );
4157
4158 exc->step_ins = FALSE;
4159 exc->new_top += L;
4160 }
4161
4162
4163 /*************************************************************************/
4164 /* */
4165 /* PUSHB[abc]: PUSH Bytes */
4166 /* Opcode range: 0xB0-0xB7 */
4167 /* Stack: --> uint32... */
4168 /* */
4169 static void
4170 Ins_PUSHB( TT_ExecContext exc,
4171 FT_Long* args )
4172 {
4173 FT_UShort L, K;
4174
4175
4176 L = (FT_UShort)( exc->opcode - 0xB0 + 1 );
4177
4178 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4179 {
4180 exc->error = FT_THROW( Stack_Overflow );
4181 return;
4182 }
4183
4184 for ( K = 1; K <= L; K++ )
4185 args[K - 1] = exc->code[exc->IP + K];
4186 }
4187
4188
4189 /*************************************************************************/
4190 /* */
4191 /* PUSHW[abc]: PUSH Words */
4192 /* Opcode range: 0xB8-0xBF */
4193 /* Stack: --> int32... */
4194 /* */
4195 static void
4196 Ins_PUSHW( TT_ExecContext exc,
4197 FT_Long* args )
4198 {
4199 FT_UShort L, K;
4200
4201
4202 L = (FT_UShort)( exc->opcode - 0xB8 + 1 );
4203
4204 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4205 {
4206 exc->error = FT_THROW( Stack_Overflow );
4207 return;
4208 }
4209
4210 exc->IP++;
4211
4212 for ( K = 0; K < L; K++ )
4213 args[K] = GetShortIns( exc );
4214
4215 exc->step_ins = FALSE;
4216 }
4217
4218
4219 /*************************************************************************/
4220 /* */
4221 /* MANAGING THE GRAPHICS STATE */
4222 /* */
4223 /*************************************************************************/
4224
4225
4226 static FT_Bool
4227 Ins_SxVTL( TT_ExecContext exc,
4228 FT_UShort aIdx1,
4229 FT_UShort aIdx2,
4230 FT_UnitVector* Vec )
4231 {
4232 FT_Long A, B, C;
4233 FT_Vector* p1;
4234 FT_Vector* p2;
4235
4236 FT_Byte opcode = exc->opcode;
4237
4238
4239 if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
4240 BOUNDS( aIdx2, exc->zp1.n_points ) )
4241 {
4242 if ( exc->pedantic_hinting )
4243 exc->error = FT_THROW( Invalid_Reference );
4257
4258 if ( A == 0 && B == 0 )
4259 {
4260 A = 0x4000;
4261 opcode = 0;
4262 }
4263
4264 if ( ( opcode & 1 ) != 0 )
4265 {
4266 C = B; /* counter clockwise rotation */
4267 B = A;
4268 A = NEG_LONG( C );
4269 }
4270
4271 Normalize( A, B, Vec );
4272
4273 return SUCCESS;
4274 }
4275
4276
4277 /*************************************************************************/
4278 /* */
4279 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
4280 /* Opcode range: 0x00-0x01 */
4281 /* Stack: --> */
4282 /* */
4283 /* SPvTCA[a]: Set PVector to Coordinate Axis */
4284 /* Opcode range: 0x02-0x03 */
4285 /* Stack: --> */
4286 /* */
4287 /* SFvTCA[a]: Set FVector to Coordinate Axis */
4288 /* Opcode range: 0x04-0x05 */
4289 /* Stack: --> */
4290 /* */
4291 static void
4292 Ins_SxyTCA( TT_ExecContext exc )
4293 {
4294 FT_Short AA, BB;
4295
4296 FT_Byte opcode = exc->opcode;
4297
4298
4299 AA = (FT_Short)( ( opcode & 1 ) << 14 );
4300 BB = (FT_Short)( AA ^ 0x4000 );
4301
4302 if ( opcode < 4 )
4303 {
4304 exc->GS.projVector.x = AA;
4305 exc->GS.projVector.y = BB;
4306
4307 exc->GS.dualVector.x = AA;
4308 exc->GS.dualVector.y = BB;
4309 }
4310
4311 if ( ( opcode & 2 ) == 0 )
4312 {
4313 exc->GS.freeVector.x = AA;
4314 exc->GS.freeVector.y = BB;
4315 }
4316
4317 Compute_Funcs( exc );
4318 }
4319
4320
4321 /*************************************************************************/
4322 /* */
4323 /* SPvTL[a]: Set PVector To Line */
4324 /* Opcode range: 0x06-0x07 */
4325 /* Stack: uint32 uint32 --> */
4326 /* */
4327 static void
4328 Ins_SPVTL( TT_ExecContext exc,
4329 FT_Long* args )
4330 {
4331 if ( Ins_SxVTL( exc,
4332 (FT_UShort)args[1],
4333 (FT_UShort)args[0],
4334 &exc->GS.projVector ) == SUCCESS )
4335 {
4336 exc->GS.dualVector = exc->GS.projVector;
4337 Compute_Funcs( exc );
4338 }
4339 }
4340
4341
4342 /*************************************************************************/
4343 /* */
4344 /* SFvTL[a]: Set FVector To Line */
4345 /* Opcode range: 0x08-0x09 */
4346 /* Stack: uint32 uint32 --> */
4347 /* */
4348 static void
4349 Ins_SFVTL( TT_ExecContext exc,
4350 FT_Long* args )
4351 {
4352 if ( Ins_SxVTL( exc,
4353 (FT_UShort)args[1],
4354 (FT_UShort)args[0],
4355 &exc->GS.freeVector ) == SUCCESS )
4356 {
4357 Compute_Funcs( exc );
4358 }
4359 }
4360
4361
4362 /*************************************************************************/
4363 /* */
4364 /* SFvTPv[]: Set FVector To PVector */
4365 /* Opcode range: 0x0E */
4366 /* Stack: --> */
4367 /* */
4368 static void
4369 Ins_SFVTPV( TT_ExecContext exc )
4370 {
4371 exc->GS.freeVector = exc->GS.projVector;
4372 Compute_Funcs( exc );
4373 }
4374
4375
4376 /*************************************************************************/
4377 /* */
4378 /* SPvFS[]: Set PVector From Stack */
4379 /* Opcode range: 0x0A */
4380 /* Stack: f2.14 f2.14 --> */
4381 /* */
4382 static void
4383 Ins_SPVFS( TT_ExecContext exc,
4384 FT_Long* args )
4385 {
4386 FT_Short S;
4387 FT_Long X, Y;
4388
4389
4390 /* Only use low 16bits, then sign extend */
4391 S = (FT_Short)args[1];
4392 Y = (FT_Long)S;
4393 S = (FT_Short)args[0];
4394 X = (FT_Long)S;
4395
4396 Normalize( X, Y, &exc->GS.projVector );
4397
4398 exc->GS.dualVector = exc->GS.projVector;
4399 Compute_Funcs( exc );
4400 }
4401
4402
4403 /*************************************************************************/
4404 /* */
4405 /* SFvFS[]: Set FVector From Stack */
4406 /* Opcode range: 0x0B */
4407 /* Stack: f2.14 f2.14 --> */
4408 /* */
4409 static void
4410 Ins_SFVFS( TT_ExecContext exc,
4411 FT_Long* args )
4412 {
4413 FT_Short S;
4414 FT_Long X, Y;
4415
4416
4417 /* Only use low 16bits, then sign extend */
4418 S = (FT_Short)args[1];
4419 Y = (FT_Long)S;
4420 S = (FT_Short)args[0];
4421 X = S;
4422
4423 Normalize( X, Y, &exc->GS.freeVector );
4424 Compute_Funcs( exc );
4425 }
4426
4427
4428 /*************************************************************************/
4429 /* */
4430 /* GPv[]: Get Projection Vector */
4431 /* Opcode range: 0x0C */
4432 /* Stack: ef2.14 --> ef2.14 */
4433 /* */
4434 static void
4435 Ins_GPV( TT_ExecContext exc,
4436 FT_Long* args )
4437 {
4438 args[0] = exc->GS.projVector.x;
4439 args[1] = exc->GS.projVector.y;
4440 }
4441
4442
4443 /*************************************************************************/
4444 /* */
4445 /* GFv[]: Get Freedom Vector */
4446 /* Opcode range: 0x0D */
4447 /* Stack: ef2.14 --> ef2.14 */
4448 /* */
4449 static void
4450 Ins_GFV( TT_ExecContext exc,
4451 FT_Long* args )
4452 {
4453 args[0] = exc->GS.freeVector.x;
4454 args[1] = exc->GS.freeVector.y;
4455 }
4456
4457
4458 /*************************************************************************/
4459 /* */
4460 /* SRP0[]: Set Reference Point 0 */
4461 /* Opcode range: 0x10 */
4462 /* Stack: uint32 --> */
4463 /* */
4464 static void
4465 Ins_SRP0( TT_ExecContext exc,
4466 FT_Long* args )
4467 {
4468 exc->GS.rp0 = (FT_UShort)args[0];
4469 }
4470
4471
4472 /*************************************************************************/
4473 /* */
4474 /* SRP1[]: Set Reference Point 1 */
4475 /* Opcode range: 0x11 */
4476 /* Stack: uint32 --> */
4477 /* */
4478 static void
4479 Ins_SRP1( TT_ExecContext exc,
4480 FT_Long* args )
4481 {
4482 exc->GS.rp1 = (FT_UShort)args[0];
4483 }
4484
4485
4486 /*************************************************************************/
4487 /* */
4488 /* SRP2[]: Set Reference Point 2 */
4489 /* Opcode range: 0x12 */
4490 /* Stack: uint32 --> */
4491 /* */
4492 static void
4493 Ins_SRP2( TT_ExecContext exc,
4494 FT_Long* args )
4495 {
4496 exc->GS.rp2 = (FT_UShort)args[0];
4497 }
4498
4499
4500 /*************************************************************************/
4501 /* */
4502 /* SMD[]: Set Minimum Distance */
4503 /* Opcode range: 0x1A */
4504 /* Stack: f26.6 --> */
4505 /* */
4506 static void
4507 Ins_SMD( TT_ExecContext exc,
4508 FT_Long* args )
4509 {
4510 exc->GS.minimum_distance = args[0];
4511 }
4512
4513
4514 /*************************************************************************/
4515 /* */
4516 /* SCVTCI[]: Set Control Value Table Cut In */
4517 /* Opcode range: 0x1D */
4518 /* Stack: f26.6 --> */
4519 /* */
4520 static void
4521 Ins_SCVTCI( TT_ExecContext exc,
4522 FT_Long* args )
4523 {
4524 exc->GS.control_value_cutin = (FT_F26Dot6)args[0];
4525 }
4526
4527
4528 /*************************************************************************/
4529 /* */
4530 /* SSWCI[]: Set Single Width Cut In */
4531 /* Opcode range: 0x1E */
4532 /* Stack: f26.6 --> */
4533 /* */
4534 static void
4535 Ins_SSWCI( TT_ExecContext exc,
4536 FT_Long* args )
4537 {
4538 exc->GS.single_width_cutin = (FT_F26Dot6)args[0];
4539 }
4540
4541
4542 /*************************************************************************/
4543 /* */
4544 /* SSW[]: Set Single Width */
4545 /* Opcode range: 0x1F */
4546 /* Stack: int32? --> */
4547 /* */
4548 static void
4549 Ins_SSW( TT_ExecContext exc,
4550 FT_Long* args )
4551 {
4552 exc->GS.single_width_value = FT_MulFix( args[0],
4553 exc->tt_metrics.scale );
4554 }
4555
4556
4557 /*************************************************************************/
4558 /* */
4559 /* FLIPON[]: Set auto-FLIP to ON */
4560 /* Opcode range: 0x4D */
4561 /* Stack: --> */
4562 /* */
4563 static void
4564 Ins_FLIPON( TT_ExecContext exc )
4565 {
4566 exc->GS.auto_flip = TRUE;
4567 }
4568
4569
4570 /*************************************************************************/
4571 /* */
4572 /* FLIPOFF[]: Set auto-FLIP to OFF */
4573 /* Opcode range: 0x4E */
4574 /* Stack: --> */
4575 /* */
4576 static void
4577 Ins_FLIPOFF( TT_ExecContext exc )
4578 {
4579 exc->GS.auto_flip = FALSE;
4580 }
4581
4582
4583 /*************************************************************************/
4584 /* */
4585 /* SANGW[]: Set ANGle Weight */
4586 /* Opcode range: 0x7E */
4587 /* Stack: uint32 --> */
4588 /* */
4589 static void
4590 Ins_SANGW( void )
4591 {
4592 /* instruction not supported anymore */
4593 }
4594
4595
4596 /*************************************************************************/
4597 /* */
4598 /* SDB[]: Set Delta Base */
4599 /* Opcode range: 0x5E */
4600 /* Stack: uint32 --> */
4601 /* */
4602 static void
4603 Ins_SDB( TT_ExecContext exc,
4604 FT_Long* args )
4605 {
4606 exc->GS.delta_base = (FT_UShort)args[0];
4607 }
4608
4609
4610 /*************************************************************************/
4611 /* */
4612 /* SDS[]: Set Delta Shift */
4613 /* Opcode range: 0x5F */
4614 /* Stack: uint32 --> */
4615 /* */
4616 static void
4617 Ins_SDS( TT_ExecContext exc,
4618 FT_Long* args )
4619 {
4620 if ( (FT_ULong)args[0] > 6UL )
4621 exc->error = FT_THROW( Bad_Argument );
4622 else
4623 exc->GS.delta_shift = (FT_UShort)args[0];
4624 }
4625
4626
4627 /*************************************************************************/
4628 /* */
4629 /* RTHG[]: Round To Half Grid */
4630 /* Opcode range: 0x19 */
4631 /* Stack: --> */
4632 /* */
4633 static void
4634 Ins_RTHG( TT_ExecContext exc )
4635 {
4636 exc->GS.round_state = TT_Round_To_Half_Grid;
4637 exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
4638 }
4639
4640
4641 /*************************************************************************/
4642 /* */
4643 /* RTG[]: Round To Grid */
4644 /* Opcode range: 0x18 */
4645 /* Stack: --> */
4646 /* */
4647 static void
4648 Ins_RTG( TT_ExecContext exc )
4649 {
4650 exc->GS.round_state = TT_Round_To_Grid;
4651 exc->func_round = (TT_Round_Func)Round_To_Grid;
4652 }
4653
4654
4655 /*************************************************************************/
4656 /* RTDG[]: Round To Double Grid */
4657 /* Opcode range: 0x3D */
4658 /* Stack: --> */
4659 /* */
4660 static void
4661 Ins_RTDG( TT_ExecContext exc )
4662 {
4663 exc->GS.round_state = TT_Round_To_Double_Grid;
4664 exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
4665 }
4666
4667
4668 /*************************************************************************/
4669 /* RUTG[]: Round Up To Grid */
4670 /* Opcode range: 0x7C */
4671 /* Stack: --> */
4672 /* */
4673 static void
4674 Ins_RUTG( TT_ExecContext exc )
4675 {
4676 exc->GS.round_state = TT_Round_Up_To_Grid;
4677 exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
4678 }
4679
4680
4681 /*************************************************************************/
4682 /* */
4683 /* RDTG[]: Round Down To Grid */
4684 /* Opcode range: 0x7D */
4685 /* Stack: --> */
4686 /* */
4687 static void
4688 Ins_RDTG( TT_ExecContext exc )
4689 {
4690 exc->GS.round_state = TT_Round_Down_To_Grid;
4691 exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
4692 }
4693
4694
4695 /*************************************************************************/
4696 /* */
4697 /* ROFF[]: Round OFF */
4698 /* Opcode range: 0x7A */
4699 /* Stack: --> */
4700 /* */
4701 static void
4702 Ins_ROFF( TT_ExecContext exc )
4703 {
4704 exc->GS.round_state = TT_Round_Off;
4705 exc->func_round = (TT_Round_Func)Round_None;
4706 }
4707
4708
4709 /*************************************************************************/
4710 /* */
4711 /* SROUND[]: Super ROUND */
4712 /* Opcode range: 0x76 */
4713 /* Stack: Eint8 --> */
4714 /* */
4715 static void
4716 Ins_SROUND( TT_ExecContext exc,
4717 FT_Long* args )
4718 {
4719 SetSuperRound( exc, 0x4000, args[0] );
4720
4721 exc->GS.round_state = TT_Round_Super;
4722 exc->func_round = (TT_Round_Func)Round_Super;
4723 }
4724
4725
4726 /*************************************************************************/
4727 /* */
4728 /* S45ROUND[]: Super ROUND 45 degrees */
4729 /* Opcode range: 0x77 */
4730 /* Stack: uint32 --> */
4731 /* */
4732 static void
4733 Ins_S45ROUND( TT_ExecContext exc,
4734 FT_Long* args )
4735 {
4736 SetSuperRound( exc, 0x2D41, args[0] );
4737
4738 exc->GS.round_state = TT_Round_Super_45;
4739 exc->func_round = (TT_Round_Func)Round_Super_45;
4740 }
4741
4742
4743 /*************************************************************************/
4744 /* */
4745 /* GC[a]: Get Coordinate projected onto */
4746 /* Opcode range: 0x46-0x47 */
4747 /* Stack: uint32 --> f26.6 */
4748 /* */
4749 /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
4750 /* along the dual projection vector! */
4751 /* */
4752 static void
4753 Ins_GC( TT_ExecContext exc,
4754 FT_Long* args )
4755 {
4756 FT_ULong L;
4757 FT_F26Dot6 R;
4758
4759
4760 L = (FT_ULong)args[0];
4761
4762 if ( BOUNDSL( L, exc->zp2.n_points ) )
4763 {
4764 if ( exc->pedantic_hinting )
4765 exc->error = FT_THROW( Invalid_Reference );
4766 R = 0;
4767 }
4768 else
4769 {
4770 if ( exc->opcode & 1 )
4771 R = FAST_DUALPROJ( &exc->zp2.org[L] );
4772 else
4773 R = FAST_PROJECT( &exc->zp2.cur[L] );
4774 }
4775
4776 args[0] = R;
4777 }
4778
4779
4780 /*************************************************************************/
4781 /* */
4782 /* SCFS[]: Set Coordinate From Stack */
4783 /* Opcode range: 0x48 */
4784 /* Stack: f26.6 uint32 --> */
4785 /* */
4786 /* Formula: */
4787 /* */
4788 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4789 /* */
4790 static void
4791 Ins_SCFS( TT_ExecContext exc,
4792 FT_Long* args )
4793 {
4794 FT_Long K;
4795 FT_UShort L;
4796
4797
4798 L = (FT_UShort)args[0];
4799
4800 if ( BOUNDS( L, exc->zp2.n_points ) )
4801 {
4802 if ( exc->pedantic_hinting )
4803 exc->error = FT_THROW( Invalid_Reference );
4804 return;
4805 }
4806
4807 K = FAST_PROJECT( &exc->zp2.cur[L] );
4808
4809 exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );
4810
4811 /* UNDOCUMENTED! The MS rasterizer does that with */
4812 /* twilight points (confirmed by Greg Hitchcock) */
4813 if ( exc->GS.gep2 == 0 )
4814 exc->zp2.org[L] = exc->zp2.cur[L];
4815 }
4816
4817
4818 /*************************************************************************/
4819 /* */
4820 /* MD[a]: Measure Distance */
4821 /* Opcode range: 0x49-0x4A */
4822 /* Stack: uint32 uint32 --> f26.6 */
4823 /* */
4824 /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
4825 /* the dual projection vector. */
4826 /* */
4827 /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
4828 /* 0 => measure distance in original outline */
4829 /* 1 => measure distance in grid-fitted outline */
4830 /* */
4831 /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
4832 /* */
4833 static void
4834 Ins_MD( TT_ExecContext exc,
4835 FT_Long* args )
4836 {
4837 FT_UShort K, L;
4838 FT_F26Dot6 D;
4839
4840
4841 K = (FT_UShort)args[1];
4842 L = (FT_UShort)args[0];
4843
4844 if ( BOUNDS( L, exc->zp0.n_points ) ||
4845 BOUNDS( K, exc->zp1.n_points ) )
4846 {
4847 if ( exc->pedantic_hinting )
4848 exc->error = FT_THROW( Invalid_Reference );
4849 D = 0;
4850 }
4851 else
4852 {
4885 vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );
4886
4887 D = FAST_DUALPROJ( &vec );
4888 }
4889 }
4890 }
4891 }
4892
4893 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
4894 /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
4895 if ( SUBPIXEL_HINTING_INFINALITY &&
4896 exc->ignore_x_mode &&
4897 FT_ABS( D ) == 64 )
4898 D += 1;
4899 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
4900
4901 args[0] = D;
4902 }
4903
4904
4905 /*************************************************************************/
4906 /* */
4907 /* SDPvTL[a]: Set Dual PVector to Line */
4908 /* Opcode range: 0x86-0x87 */
4909 /* Stack: uint32 uint32 --> */
4910 /* */
4911 static void
4912 Ins_SDPVTL( TT_ExecContext exc,
4913 FT_Long* args )
4914 {
4915 FT_Long A, B, C;
4916 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4917
4918 FT_Byte opcode = exc->opcode;
4919
4920
4921 p1 = (FT_UShort)args[1];
4922 p2 = (FT_UShort)args[0];
4923
4924 if ( BOUNDS( p2, exc->zp1.n_points ) ||
4925 BOUNDS( p1, exc->zp2.n_points ) )
4926 {
4927 if ( exc->pedantic_hinting )
4928 exc->error = FT_THROW( Invalid_Reference );
4929 return;
4930 }
4968
4969 if ( A == 0 && B == 0 )
4970 {
4971 A = 0x4000;
4972 opcode = 0;
4973 }
4974 }
4975
4976 if ( ( opcode & 1 ) != 0 )
4977 {
4978 C = B; /* counter clockwise rotation */
4979 B = A;
4980 A = NEG_LONG( C );
4981 }
4982
4983 Normalize( A, B, &exc->GS.projVector );
4984 Compute_Funcs( exc );
4985 }
4986
4987
4988 /*************************************************************************/
4989 /* */
4990 /* SZP0[]: Set Zone Pointer 0 */
4991 /* Opcode range: 0x13 */
4992 /* Stack: uint32 --> */
4993 /* */
4994 static void
4995 Ins_SZP0( TT_ExecContext exc,
4996 FT_Long* args )
4997 {
4998 switch ( (FT_Int)args[0] )
4999 {
5000 case 0:
5001 exc->zp0 = exc->twilight;
5002 break;
5003
5004 case 1:
5005 exc->zp0 = exc->pts;
5006 break;
5007
5008 default:
5009 if ( exc->pedantic_hinting )
5010 exc->error = FT_THROW( Invalid_Reference );
5011 return;
5012 }
5013
5014 exc->GS.gep0 = (FT_UShort)args[0];
5015 }
5016
5017
5018 /*************************************************************************/
5019 /* */
5020 /* SZP1[]: Set Zone Pointer 1 */
5021 /* Opcode range: 0x14 */
5022 /* Stack: uint32 --> */
5023 /* */
5024 static void
5025 Ins_SZP1( TT_ExecContext exc,
5026 FT_Long* args )
5027 {
5028 switch ( (FT_Int)args[0] )
5029 {
5030 case 0:
5031 exc->zp1 = exc->twilight;
5032 break;
5033
5034 case 1:
5035 exc->zp1 = exc->pts;
5036 break;
5037
5038 default:
5039 if ( exc->pedantic_hinting )
5040 exc->error = FT_THROW( Invalid_Reference );
5041 return;
5042 }
5043
5044 exc->GS.gep1 = (FT_UShort)args[0];
5045 }
5046
5047
5048 /*************************************************************************/
5049 /* */
5050 /* SZP2[]: Set Zone Pointer 2 */
5051 /* Opcode range: 0x15 */
5052 /* Stack: uint32 --> */
5053 /* */
5054 static void
5055 Ins_SZP2( TT_ExecContext exc,
5056 FT_Long* args )
5057 {
5058 switch ( (FT_Int)args[0] )
5059 {
5060 case 0:
5061 exc->zp2 = exc->twilight;
5062 break;
5063
5064 case 1:
5065 exc->zp2 = exc->pts;
5066 break;
5067
5068 default:
5069 if ( exc->pedantic_hinting )
5070 exc->error = FT_THROW( Invalid_Reference );
5071 return;
5072 }
5073
5074 exc->GS.gep2 = (FT_UShort)args[0];
5075 }
5076
5077
5078 /*************************************************************************/
5079 /* */
5080 /* SZPS[]: Set Zone PointerS */
5081 /* Opcode range: 0x16 */
5082 /* Stack: uint32 --> */
5083 /* */
5084 static void
5085 Ins_SZPS( TT_ExecContext exc,
5086 FT_Long* args )
5087 {
5088 switch ( (FT_Int)args[0] )
5089 {
5090 case 0:
5091 exc->zp0 = exc->twilight;
5092 break;
5093
5094 case 1:
5095 exc->zp0 = exc->pts;
5096 break;
5097
5098 default:
5099 if ( exc->pedantic_hinting )
5100 exc->error = FT_THROW( Invalid_Reference );
5101 return;
5102 }
5103
5104 exc->zp1 = exc->zp0;
5105 exc->zp2 = exc->zp0;
5106
5107 exc->GS.gep0 = (FT_UShort)args[0];
5108 exc->GS.gep1 = (FT_UShort)args[0];
5109 exc->GS.gep2 = (FT_UShort)args[0];
5110 }
5111
5112
5113 /*************************************************************************/
5114 /* */
5115 /* INSTCTRL[]: INSTruction ConTRoL */
5116 /* Opcode range: 0x8E */
5117 /* Stack: int32 int32 --> */
5118 /* */
5119 static void
5120 Ins_INSTCTRL( TT_ExecContext exc,
5121 FT_Long* args )
5122 {
5123 FT_ULong K, L, Kf;
5124
5125
5126 K = (FT_ULong)args[1];
5127 L = (FT_ULong)args[0];
5128
5129 /* selector values cannot be `OR'ed; */
5130 /* they are indices starting with index 1, not flags */
5131 if ( K < 1 || K > 3 )
5132 {
5133 if ( exc->pedantic_hinting )
5134 exc->error = FT_THROW( Invalid_Reference );
5135 return;
5136 }
5137
5138 /* convert index to flag value */
5155 if ( K == 3 )
5156 {
5157 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5158 /* INSTCTRL modifying flag 3 also has an effect */
5159 /* outside of the CVT program */
5160 if ( SUBPIXEL_HINTING_INFINALITY )
5161 exc->ignore_x_mode = FT_BOOL( L == 4 );
5162 #endif
5163
5164 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5165 /* Native ClearType fonts sign a waiver that turns off all backward */
5166 /* compatibility hacks and lets them program points to the grid like */
5167 /* it's 1996. They might sign a waiver for just one glyph, though. */
5168 if ( SUBPIXEL_HINTING_MINIMAL )
5169 exc->backward_compatibility = !FT_BOOL( L == 4 );
5170 #endif
5171 }
5172 }
5173
5174
5175 /*************************************************************************/
5176 /* */
5177 /* SCANCTRL[]: SCAN ConTRoL */
5178 /* Opcode range: 0x85 */
5179 /* Stack: uint32? --> */
5180 /* */
5181 static void
5182 Ins_SCANCTRL( TT_ExecContext exc,
5183 FT_Long* args )
5184 {
5185 FT_Int A;
5186
5187
5188 /* Get Threshold */
5189 A = (FT_Int)( args[0] & 0xFF );
5190
5191 if ( A == 0xFF )
5192 {
5193 exc->GS.scan_control = TRUE;
5194 return;
5195 }
5196 else if ( A == 0 )
5197 {
5198 exc->GS.scan_control = FALSE;
5199 return;
5200 }
5202 if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )
5203 exc->GS.scan_control = TRUE;
5204
5205 if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )
5206 exc->GS.scan_control = TRUE;
5207
5208 if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )
5209 exc->GS.scan_control = TRUE;
5210
5211 if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )
5212 exc->GS.scan_control = FALSE;
5213
5214 if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )
5215 exc->GS.scan_control = FALSE;
5216
5217 if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )
5218 exc->GS.scan_control = FALSE;
5219 }
5220
5221
5222 /*************************************************************************/
5223 /* */
5224 /* SCANTYPE[]: SCAN TYPE */
5225 /* Opcode range: 0x8D */
5226 /* Stack: uint16 --> */
5227 /* */
5228 static void
5229 Ins_SCANTYPE( TT_ExecContext exc,
5230 FT_Long* args )
5231 {
5232 if ( args[0] >= 0 )
5233 exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;
5234 }
5235
5236
5237 /*************************************************************************/
5238 /* */
5239 /* MANAGING OUTLINES */
5240 /* */
5241 /*************************************************************************/
5242
5243
5244 /*************************************************************************/
5245 /* */
5246 /* FLIPPT[]: FLIP PoinT */
5247 /* Opcode range: 0x80 */
5248 /* Stack: uint32... --> */
5249 /* */
5250 static void
5251 Ins_FLIPPT( TT_ExecContext exc )
5252 {
5253 FT_UShort point;
5254
5255
5256 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5257 /* See `ttinterp.h' for details on backward compatibility mode. */
5258 if ( SUBPIXEL_HINTING_MINIMAL &&
5259 exc->backward_compatibility &&
5260 exc->iupx_called &&
5261 exc->iupy_called )
5262 goto Fail;
5263 #endif
5264
5265 if ( exc->top < exc->GS.loop )
5266 {
5267 if ( exc->pedantic_hinting )
5268 exc->error = FT_THROW( Too_Few_Arguments );
5269 goto Fail;
5278 if ( BOUNDS( point, exc->pts.n_points ) )
5279 {
5280 if ( exc->pedantic_hinting )
5281 {
5282 exc->error = FT_THROW( Invalid_Reference );
5283 return;
5284 }
5285 }
5286 else
5287 exc->pts.tags[point] ^= FT_CURVE_TAG_ON;
5288
5289 exc->GS.loop--;
5290 }
5291
5292 Fail:
5293 exc->GS.loop = 1;
5294 exc->new_top = exc->args;
5295 }
5296
5297
5298 /*************************************************************************/
5299 /* */
5300 /* FLIPRGON[]: FLIP RanGe ON */
5301 /* Opcode range: 0x81 */
5302 /* Stack: uint32 uint32 --> */
5303 /* */
5304 static void
5305 Ins_FLIPRGON( TT_ExecContext exc,
5306 FT_Long* args )
5307 {
5308 FT_UShort I, K, L;
5309
5310
5311 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5312 /* See `ttinterp.h' for details on backward compatibility mode. */
5313 if ( SUBPIXEL_HINTING_MINIMAL &&
5314 exc->backward_compatibility &&
5315 exc->iupx_called &&
5316 exc->iupy_called )
5317 return;
5318 #endif
5319
5320 K = (FT_UShort)args[1];
5321 L = (FT_UShort)args[0];
5322
5323 if ( BOUNDS( K, exc->pts.n_points ) ||
5324 BOUNDS( L, exc->pts.n_points ) )
5325 {
5326 if ( exc->pedantic_hinting )
5327 exc->error = FT_THROW( Invalid_Reference );
5328 return;
5329 }
5330
5331 for ( I = L; I <= K; I++ )
5332 exc->pts.tags[I] |= FT_CURVE_TAG_ON;
5333 }
5334
5335
5336 /*************************************************************************/
5337 /* */
5338 /* FLIPRGOFF: FLIP RanGe OFF */
5339 /* Opcode range: 0x82 */
5340 /* Stack: uint32 uint32 --> */
5341 /* */
5342 static void
5343 Ins_FLIPRGOFF( TT_ExecContext exc,
5344 FT_Long* args )
5345 {
5346 FT_UShort I, K, L;
5347
5348
5349 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5350 /* See `ttinterp.h' for details on backward compatibility mode. */
5351 if ( SUBPIXEL_HINTING_MINIMAL &&
5352 exc->backward_compatibility &&
5353 exc->iupx_called &&
5354 exc->iupy_called )
5355 return;
5356 #endif
5357
5358 K = (FT_UShort)args[1];
5359 L = (FT_UShort)args[0];
5360
5361 if ( BOUNDS( K, exc->pts.n_points ) ||
5433 if ( touch )
5434 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5435 }
5436
5437 if ( exc->GS.freeVector.y != 0 )
5438 {
5439 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5440 if ( !( SUBPIXEL_HINTING_MINIMAL &&
5441 exc->backward_compatibility &&
5442 exc->iupx_called &&
5443 exc->iupy_called ) )
5444 #endif
5445 exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );
5446
5447 if ( touch )
5448 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5449 }
5450 }
5451
5452
5453 /*************************************************************************/
5454 /* */
5455 /* SHP[a]: SHift Point by the last point */
5456 /* Opcode range: 0x32-0x33 */
5457 /* Stack: uint32... --> */
5458 /* */
5459 static void
5460 Ins_SHP( TT_ExecContext exc )
5461 {
5462 TT_GlyphZoneRec zp;
5463 FT_UShort refp;
5464
5465 FT_F26Dot6 dx, dy;
5466 FT_UShort point;
5467
5468
5469 if ( exc->top < exc->GS.loop )
5470 {
5471 if ( exc->pedantic_hinting )
5472 exc->error = FT_THROW( Invalid_Reference );
5473 goto Fail;
5474 }
5475
5476 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5477 return;
5478
5490 }
5491 }
5492 else
5493 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5494 /* doesn't follow Cleartype spec but produces better result */
5495 if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
5496 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5497 else
5498 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5499 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5500
5501 exc->GS.loop--;
5502 }
5503
5504 Fail:
5505 exc->GS.loop = 1;
5506 exc->new_top = exc->args;
5507 }
5508
5509
5510 /*************************************************************************/
5511 /* */
5512 /* SHC[a]: SHift Contour */
5513 /* Opcode range: 0x34-35 */
5514 /* Stack: uint32 --> */
5515 /* */
5516 /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
5517 /* contour in the twilight zone, namely contour number */
5518 /* zero which includes all points of it. */
5519 /* */
5520 static void
5521 Ins_SHC( TT_ExecContext exc,
5522 FT_Long* args )
5523 {
5524 TT_GlyphZoneRec zp;
5525 FT_UShort refp;
5526 FT_F26Dot6 dx, dy;
5527
5528 FT_Short contour, bounds;
5529 FT_UShort start, limit, i;
5530
5531
5532 contour = (FT_Short)args[0];
5533 bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
5534
5535 if ( BOUNDS( contour, bounds ) )
5536 {
5537 if ( exc->pedantic_hinting )
5538 exc->error = FT_THROW( Invalid_Reference );
5539 return;
5546 start = 0;
5547 else
5548 start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
5549 exc->zp2.first_point );
5550
5551 /* we use the number of points if in the twilight zone */
5552 if ( exc->GS.gep2 == 0 )
5553 limit = exc->zp2.n_points;
5554 else
5555 limit = (FT_UShort)( exc->zp2.contours[contour] -
5556 exc->zp2.first_point + 1 );
5557
5558 for ( i = start; i < limit; i++ )
5559 {
5560 if ( zp.cur != exc->zp2.cur || refp != i )
5561 Move_Zp2_Point( exc, i, dx, dy, TRUE );
5562 }
5563 }
5564
5565
5566 /*************************************************************************/
5567 /* */
5568 /* SHZ[a]: SHift Zone */
5569 /* Opcode range: 0x36-37 */
5570 /* Stack: uint32 --> */
5571 /* */
5572 static void
5573 Ins_SHZ( TT_ExecContext exc,
5574 FT_Long* args )
5575 {
5576 TT_GlyphZoneRec zp;
5577 FT_UShort refp;
5578 FT_F26Dot6 dx,
5579 dy;
5580
5581 FT_UShort limit, i;
5582
5583
5584 if ( BOUNDS( args[0], 2 ) )
5585 {
5586 if ( exc->pedantic_hinting )
5587 exc->error = FT_THROW( Invalid_Reference );
5588 return;
5589 }
5590
5591 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5594 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5595 /* Twilight zone has no real contours, so use `n_points'. */
5596 /* Normal zone's `n_points' includes phantoms, so must */
5597 /* use end of last contour. */
5598 if ( exc->GS.gep2 == 0 )
5599 limit = (FT_UShort)exc->zp2.n_points;
5600 else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
5601 limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
5602 else
5603 limit = 0;
5604
5605 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5606 for ( i = 0; i < limit; i++ )
5607 {
5608 if ( zp.cur != exc->zp2.cur || refp != i )
5609 Move_Zp2_Point( exc, i, dx, dy, FALSE );
5610 }
5611 }
5612
5613
5614 /*************************************************************************/
5615 /* */
5616 /* SHPIX[]: SHift points by a PIXel amount */
5617 /* Opcode range: 0x38 */
5618 /* Stack: f26.6 uint32... --> */
5619 /* */
5620 static void
5621 Ins_SHPIX( TT_ExecContext exc,
5622 FT_Long* args )
5623 {
5624 FT_F26Dot6 dx, dy;
5625 FT_UShort point;
5626 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5627 FT_Int B1, B2;
5628 #endif
5629 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5630 FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||
5631 exc->GS.gep1 == 0 ||
5632 exc->GS.gep2 == 0 );
5633 #endif
5634
5635
5636
5637 if ( exc->top < exc->GS.loop + 1 )
5638 {
5639 if ( exc->pedantic_hinting )
5754 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
5755 ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) )
5756 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5757 }
5758 else
5759 #endif
5760 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5761
5762 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5763 Skip:
5764 #endif
5765 exc->GS.loop--;
5766 }
5767
5768 Fail:
5769 exc->GS.loop = 1;
5770 exc->new_top = exc->args;
5771 }
5772
5773
5774 /*************************************************************************/
5775 /* */
5776 /* MSIRP[a]: Move Stack Indirect Relative Position */
5777 /* Opcode range: 0x3A-0x3B */
5778 /* Stack: f26.6 uint32 --> */
5779 /* */
5780 static void
5781 Ins_MSIRP( TT_ExecContext exc,
5782 FT_Long* args )
5783 {
5784 FT_UShort point = 0;
5785 FT_F26Dot6 distance;
5786 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5787 FT_F26Dot6 control_value_cutin = 0;
5788 FT_F26Dot6 delta;
5789
5790
5791 if ( SUBPIXEL_HINTING_INFINALITY )
5792 {
5793 control_value_cutin = exc->GS.control_value_cutin;
5794
5795 if ( exc->ignore_x_mode &&
5796 exc->GS.freeVector.x != 0 &&
5797 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
5798 control_value_cutin = 0;
5799 }
5829 if ( SUBPIXEL_HINTING_INFINALITY &&
5830 exc->ignore_x_mode &&
5831 exc->GS.freeVector.x != 0 &&
5832 delta >= control_value_cutin )
5833 distance = args[1];
5834 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5835
5836 exc->func_move( exc,
5837 &exc->zp1,
5838 point,
5839 SUB_LONG( args[1], distance ) );
5840
5841 exc->GS.rp1 = exc->GS.rp0;
5842 exc->GS.rp2 = point;
5843
5844 if ( ( exc->opcode & 1 ) != 0 )
5845 exc->GS.rp0 = point;
5846 }
5847
5848
5849 /*************************************************************************/
5850 /* */
5851 /* MDAP[a]: Move Direct Absolute Point */
5852 /* Opcode range: 0x2E-0x2F */
5853 /* Stack: uint32 --> */
5854 /* */
5855 static void
5856 Ins_MDAP( TT_ExecContext exc,
5857 FT_Long* args )
5858 {
5859 FT_UShort point;
5860 FT_F26Dot6 cur_dist;
5861 FT_F26Dot6 distance;
5862
5863
5864 point = (FT_UShort)args[0];
5865
5866 if ( BOUNDS( point, exc->zp0.n_points ) )
5867 {
5868 if ( exc->pedantic_hinting )
5869 exc->error = FT_THROW( Invalid_Reference );
5870 return;
5871 }
5872
5873 if ( ( exc->opcode & 1 ) != 0 )
5874 {
5883 exc->tt_metrics.compensations[0] ),
5884 cur_dist );
5885 else
5886 #endif
5887 distance = SUB_LONG(
5888 exc->func_round( exc,
5889 cur_dist,
5890 exc->tt_metrics.compensations[0] ),
5891 cur_dist );
5892 }
5893 else
5894 distance = 0;
5895
5896 exc->func_move( exc, &exc->zp0, point, distance );
5897
5898 exc->GS.rp0 = point;
5899 exc->GS.rp1 = point;
5900 }
5901
5902
5903 /*************************************************************************/
5904 /* */
5905 /* MIAP[a]: Move Indirect Absolute Point */
5906 /* Opcode range: 0x3E-0x3F */
5907 /* Stack: uint32 uint32 --> */
5908 /* */
5909 static void
5910 Ins_MIAP( TT_ExecContext exc,
5911 FT_Long* args )
5912 {
5913 FT_ULong cvtEntry;
5914 FT_UShort point;
5915 FT_F26Dot6 distance;
5916 FT_F26Dot6 org_dist;
5917 FT_F26Dot6 control_value_cutin;
5918
5919
5920 control_value_cutin = exc->GS.control_value_cutin;
5921 cvtEntry = (FT_ULong)args[1];
5922 point = (FT_UShort)args[0];
5923
5924 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5925 if ( SUBPIXEL_HINTING_INFINALITY &&
5926 exc->ignore_x_mode &&
5927 exc->GS.freeVector.x != 0 &&
5928 exc->GS.freeVector.y == 0 &&
6003 exc->ignore_x_mode &&
6004 exc->GS.freeVector.x != 0 )
6005 distance = Round_None( exc,
6006 distance,
6007 exc->tt_metrics.compensations[0] );
6008 else
6009 #endif
6010 distance = exc->func_round( exc,
6011 distance,
6012 exc->tt_metrics.compensations[0] );
6013 }
6014
6015 exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
6016
6017 Fail:
6018 exc->GS.rp0 = point;
6019 exc->GS.rp1 = point;
6020 }
6021
6022
6023 /*************************************************************************/
6024 /* */
6025 /* MDRP[abcde]: Move Direct Relative Point */
6026 /* Opcode range: 0xC0-0xDF */
6027 /* Stack: uint32 --> */
6028 /* */
6029 static void
6030 Ins_MDRP( TT_ExecContext exc,
6031 FT_Long* args )
6032 {
6033 FT_UShort point = 0;
6034 FT_F26Dot6 org_dist, distance, minimum_distance;
6035
6036
6037 minimum_distance = exc->GS.minimum_distance;
6038
6039 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6040 if ( SUBPIXEL_HINTING_INFINALITY &&
6041 exc->ignore_x_mode &&
6042 exc->GS.freeVector.x != 0 &&
6043 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6044 minimum_distance = 0;
6045 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6046
6047 point = (FT_UShort)args[0];
6048
6147 if ( distance > NEG_LONG( minimum_distance ) )
6148 distance = NEG_LONG( minimum_distance );
6149 }
6150 }
6151
6152 /* now move the point */
6153
6154 org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
6155
6156 exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );
6157
6158 Fail:
6159 exc->GS.rp1 = exc->GS.rp0;
6160 exc->GS.rp2 = point;
6161
6162 if ( ( exc->opcode & 16 ) != 0 )
6163 exc->GS.rp0 = point;
6164 }
6165
6166
6167 /*************************************************************************/
6168 /* */
6169 /* MIRP[abcde]: Move Indirect Relative Point */
6170 /* Opcode range: 0xE0-0xFF */
6171 /* Stack: int32? uint32 --> */
6172 /* */
6173 static void
6174 Ins_MIRP( TT_ExecContext exc,
6175 FT_Long* args )
6176 {
6177 FT_UShort point;
6178 FT_ULong cvtEntry;
6179
6180 FT_F26Dot6 cvt_dist,
6181 distance,
6182 cur_dist,
6183 org_dist,
6184 control_value_cutin,
6185 minimum_distance;
6186 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6187 FT_Int B1 = 0; /* pacify compiler */
6188 FT_Int B2 = 0;
6189 FT_Bool reverse_move = FALSE;
6190 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6191
6192
6193 minimum_distance = exc->GS.minimum_distance;
6194 control_value_cutin = exc->GS.control_value_cutin;
6195 point = (FT_UShort)args[0];
6196 cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) );
6197
6198 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6199 if ( SUBPIXEL_HINTING_INFINALITY &&
6200 exc->ignore_x_mode &&
6201 exc->GS.freeVector.x != 0 &&
6202 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6203 control_value_cutin = minimum_distance = 0;
6204 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6205
6206 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6207
6208 if ( BOUNDS( point, exc->zp1.n_points ) ||
6209 BOUNDSL( cvtEntry, exc->cvtSize + 1 ) ||
6210 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6211 {
6212 if ( exc->pedantic_hinting )
6213 exc->error = FT_THROW( Invalid_Reference );
6214 goto Fail;
6215 }
6216
6217 if ( !cvtEntry )
6218 cvt_dist = 0;
6219 else
6220 cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );
6221
6222 /* single width test */
6223
6224 if ( FT_ABS( cvt_dist - exc->GS.single_width_value ) <
6225 exc->GS.single_width_cutin )
6226 {
6227 if ( cvt_dist >= 0 )
6228 cvt_dist = exc->GS.single_width_value;
6229 else
6230 cvt_dist = -exc->GS.single_width_value;
6231 }
6232
6233 /* UNDOCUMENTED! The MS rasterizer does that with */
6234 /* twilight points (confirmed by Greg Hitchcock) */
6235 if ( exc->GS.gep1 == 0 )
6236 {
6237 exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x +
6238 TT_MulFix14( cvt_dist,
6239 exc->GS.freeVector.x );
6240 exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y +
6241 TT_MulFix14( cvt_dist,
6242 exc->GS.freeVector.y );
6243 exc->zp1.cur[point] = exc->zp1.org[point];
6244 }
6245
6246 org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );
6247 cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );
6248
6249 /* auto-flip test */
6250
6251 if ( exc->GS.auto_flip )
6252 {
6253 if ( ( org_dist ^ cvt_dist ) < 0 )
6254 cvt_dist = -cvt_dist;
6255 }
6256
6257 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6258 if ( SUBPIXEL_HINTING_INFINALITY &&
6259 exc->ignore_x_mode &&
6260 exc->GS.freeVector.y != 0 &&
6261 ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6262 {
6263 if ( cur_dist < -64 )
6264 cvt_dist -= 16;
6265 else if ( cur_dist > 64 && cur_dist < 84 )
6266 cvt_dist += 32;
6267 }
6268 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6269
6270 /* control value cut-in and round */
6271
6272 if ( ( exc->opcode & 4 ) != 0 )
6273 {
6274 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6275 /* refer to the same zone. */
6276
6277 if ( exc->GS.gep0 == exc->GS.gep1 )
6278 {
6279 FT_F26Dot6 delta;
6280
6281
6282 /* XXX: According to Greg Hitchcock, the following wording is */
6283 /* the right one: */
6284 /* */
6285 /* When the absolute difference between the value in */
6286 /* the table [CVT] and the measurement directly from */
6287 /* the outline is _greater_ than the cut_in value, the */
6288 /* outline measurement is used. */
6289 /* */
6290 /* This is from `instgly.doc'. The description in */
6291 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6292 /* it implies `>=' instead of `>'. */
6293
6294 delta = SUB_LONG( cvt_dist, org_dist );
6295 if ( delta < 0 )
6296 delta = NEG_LONG( delta );
6297
6298 if ( delta > control_value_cutin )
6299 cvt_dist = org_dist;
6300 }
6301
6302 distance = exc->func_round(
6303 exc,
6304 cvt_dist,
6305 exc->tt_metrics.compensations[exc->opcode & 3] );
6306 }
6307 else
6308 {
6309
6310 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6311 /* do cvt cut-in always in MIRP for sph */
6312 if ( SUBPIXEL_HINTING_INFINALITY &&
6313 exc->ignore_x_mode &&
6314 exc->GS.gep0 == exc->GS.gep1 )
6315 {
6316 FT_F26Dot6 delta;
6317
6318
6319 delta = SUB_LONG( cvt_dist, org_dist );
6320 if ( delta < 0 )
6321 delta = NEG_LONG( delta );
6322
6323 if ( delta > control_value_cutin )
6324 cvt_dist = org_dist;
6325 }
6326 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6327
6328 distance = Round_None(
6329 exc,
6330 cvt_dist,
6331 exc->tt_metrics.compensations[exc->opcode & 3] );
6332 }
6333
6334 /* minimum distance test */
6335
6336 if ( ( exc->opcode & 8 ) != 0 )
6337 {
6338 if ( org_dist >= 0 )
6395
6396 if ( reverse_move )
6397 exc->func_move( exc,
6398 &exc->zp1,
6399 point,
6400 SUB_LONG( cur_dist, distance ) );
6401 }
6402
6403 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6404
6405 Fail:
6406 exc->GS.rp1 = exc->GS.rp0;
6407
6408 if ( ( exc->opcode & 16 ) != 0 )
6409 exc->GS.rp0 = point;
6410
6411 exc->GS.rp2 = point;
6412 }
6413
6414
6415 /*************************************************************************/
6416 /* */
6417 /* ALIGNRP[]: ALIGN Relative Point */
6418 /* Opcode range: 0x3C */
6419 /* Stack: uint32 uint32... --> */
6420 /* */
6421 static void
6422 Ins_ALIGNRP( TT_ExecContext exc )
6423 {
6424 FT_UShort point;
6425 FT_F26Dot6 distance;
6426
6427
6428 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6429 if ( SUBPIXEL_HINTING_INFINALITY &&
6430 exc->ignore_x_mode &&
6431 exc->iup_called &&
6432 ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6433 {
6434 exc->error = FT_THROW( Invalid_Reference );
6435 goto Fail;
6436 }
6437 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6438
6439 if ( exc->top < exc->GS.loop ||
6440 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6458 return;
6459 }
6460 }
6461 else
6462 {
6463 distance = PROJECT( exc->zp1.cur + point,
6464 exc->zp0.cur + exc->GS.rp0 );
6465
6466 exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
6467 }
6468
6469 exc->GS.loop--;
6470 }
6471
6472 Fail:
6473 exc->GS.loop = 1;
6474 exc->new_top = exc->args;
6475 }
6476
6477
6478 /*************************************************************************/
6479 /* */
6480 /* ISECT[]: moves point to InterSECTion */
6481 /* Opcode range: 0x0F */
6482 /* Stack: 5 * uint32 --> */
6483 /* */
6484 static void
6485 Ins_ISECT( TT_ExecContext exc,
6486 FT_Long* args )
6487 {
6488 FT_UShort point,
6489 a0, a1,
6490 b0, b1;
6491
6492 FT_F26Dot6 discriminant, dotproduct;
6493
6494 FT_F26Dot6 dx, dy,
6495 dax, day,
6496 dbx, dby;
6497
6498 FT_F26Dot6 val;
6499
6500 FT_Vector R;
6501
6502
6503 point = (FT_UShort)args[0];
6554 exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );
6555 exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );
6556 }
6557 else
6558 {
6559 /* else, take the middle of the middles of A and B */
6560
6561 /* XXX: Block in backward_compatibility and/or post-IUP? */
6562 exc->zp2.cur[point].x =
6563 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),
6564 ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;
6565 exc->zp2.cur[point].y =
6566 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),
6567 ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;
6568 }
6569
6570 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6571 }
6572
6573
6574 /*************************************************************************/
6575 /* */
6576 /* ALIGNPTS[]: ALIGN PoinTS */
6577 /* Opcode range: 0x27 */
6578 /* Stack: uint32 uint32 --> */
6579 /* */
6580 static void
6581 Ins_ALIGNPTS( TT_ExecContext exc,
6582 FT_Long* args )
6583 {
6584 FT_UShort p1, p2;
6585 FT_F26Dot6 distance;
6586
6587
6588 p1 = (FT_UShort)args[0];
6589 p2 = (FT_UShort)args[1];
6590
6591 if ( BOUNDS( p1, exc->zp1.n_points ) ||
6592 BOUNDS( p2, exc->zp0.n_points ) )
6593 {
6594 if ( exc->pedantic_hinting )
6595 exc->error = FT_THROW( Invalid_Reference );
6596 return;
6597 }
6598
6599 distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;
6600
6601 exc->func_move( exc, &exc->zp1, p1, distance );
6602 exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );
6603 }
6604
6605
6606 /*************************************************************************/
6607 /* */
6608 /* IP[]: Interpolate Point */
6609 /* Opcode range: 0x39 */
6610 /* Stack: uint32... --> */
6611 /* */
6612
6613 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6614
6615 static void
6616 Ins_IP( TT_ExecContext exc )
6617 {
6618 FT_F26Dot6 old_range, cur_range;
6619 FT_Vector* orus_base;
6620 FT_Vector* cur_base;
6621 FT_Int twilight;
6622
6623
6624 if ( exc->top < exc->GS.loop )
6625 {
6626 if ( exc->pedantic_hinting )
6627 exc->error = FT_THROW( Invalid_Reference );
6628 goto Fail;
6629 }
6630
6631 /*
6746 /* new_dist = org_dist . */
6747
6748 new_dist = org_dist;
6749 }
6750 }
6751 else
6752 new_dist = 0;
6753
6754 exc->func_move( exc,
6755 &exc->zp2,
6756 (FT_UShort)point,
6757 SUB_LONG( new_dist, cur_dist ) );
6758 }
6759
6760 Fail:
6761 exc->GS.loop = 1;
6762 exc->new_top = exc->args;
6763 }
6764
6765
6766 /*************************************************************************/
6767 /* */
6768 /* UTP[a]: UnTouch Point */
6769 /* Opcode range: 0x29 */
6770 /* Stack: uint32 --> */
6771 /* */
6772 static void
6773 Ins_UTP( TT_ExecContext exc,
6774 FT_Long* args )
6775 {
6776 FT_UShort point;
6777 FT_Byte mask;
6778
6779
6780 point = (FT_UShort)args[0];
6781
6782 if ( BOUNDS( point, exc->zp0.n_points ) )
6783 {
6784 if ( exc->pedantic_hinting )
6785 exc->error = FT_THROW( Invalid_Reference );
6786 return;
6787 }
6788
6789 mask = 0xFF;
6790
6791 if ( exc->GS.freeVector.x != 0 )
6915
6916 else
6917 {
6918 if ( !scale_valid )
6919 {
6920 scale_valid = 1;
6921 scale = FT_DivFix( SUB_LONG( cur2, cur1 ),
6922 SUB_LONG( orus2, orus1 ) );
6923 }
6924
6925 x = ADD_LONG( cur1,
6926 FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),
6927 scale ) );
6928 }
6929 worker->curs[i].x = x;
6930 }
6931 }
6932 }
6933
6934
6935 /*************************************************************************/
6936 /* */
6937 /* IUP[a]: Interpolate Untouched Points */
6938 /* Opcode range: 0x30-0x31 */
6939 /* Stack: --> */
6940 /* */
6941 static void
6942 Ins_IUP( TT_ExecContext exc )
6943 {
6944 IUP_WorkerRec V;
6945 FT_Byte mask;
6946
6947 FT_UInt first_point; /* first point of contour */
6948 FT_UInt end_point; /* end point (last+1) of contour */
6949
6950 FT_UInt first_touched; /* first touched point in contour */
6951 FT_UInt cur_touched; /* current touched point in contour */
6952
6953 FT_UInt point; /* current point */
6954 FT_Short contour; /* current contour */
6955
6956
6957 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
6958 /* See `ttinterp.h' for details on backward compatibility mode. */
6959 /* Allow IUP until it has been called on both axes. Immediately */
6960 /* return on subsequent ones. */
7043 {
7044 _iup_worker_interpolate( &V,
7045 (FT_UShort)( cur_touched + 1 ),
7046 end_point,
7047 cur_touched,
7048 first_touched );
7049
7050 if ( first_touched > 0 )
7051 _iup_worker_interpolate( &V,
7052 first_point,
7053 first_touched - 1,
7054 cur_touched,
7055 first_touched );
7056 }
7057 }
7058 contour++;
7059 } while ( contour < exc->pts.n_contours );
7060 }
7061
7062
7063 /*************************************************************************/
7064 /* */
7065 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
7066 /* Opcode range: 0x5D,0x71,0x72 */
7067 /* Stack: uint32 (2 * uint32)... --> */
7068 /* */
7069 static void
7070 Ins_DELTAP( TT_ExecContext exc,
7071 FT_Long* args )
7072 {
7073 FT_ULong nump, k;
7074 FT_UShort A;
7075 FT_ULong C, P;
7076 FT_Long B;
7077 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7078 FT_UShort B1, B2;
7079
7080
7081 if ( SUBPIXEL_HINTING_INFINALITY &&
7082 exc->ignore_x_mode &&
7083 exc->iup_called &&
7084 ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7085 goto Fail;
7086 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7087
7088 P = (FT_ULong)exc->func_cur_ppem( exc );
7210 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
7211 ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )
7212 exc->func_move( exc, &exc->zp0, A, B );
7213 }
7214 else
7215 #endif
7216 exc->func_move( exc, &exc->zp0, A, B );
7217 }
7218 }
7219 }
7220 else
7221 if ( exc->pedantic_hinting )
7222 exc->error = FT_THROW( Invalid_Reference );
7223 }
7224
7225 Fail:
7226 exc->new_top = exc->args;
7227 }
7228
7229
7230 /*************************************************************************/
7231 /* */
7232 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
7233 /* Opcode range: 0x73,0x74,0x75 */
7234 /* Stack: uint32 (2 * uint32)... --> */
7235 /* */
7236 static void
7237 Ins_DELTAC( TT_ExecContext exc,
7238 FT_Long* args )
7239 {
7240 FT_ULong nump, k;
7241 FT_ULong A, C, P;
7242 FT_Long B;
7243
7244
7245 P = (FT_ULong)exc->func_cur_ppem( exc );
7246 nump = (FT_ULong)args[0];
7247
7248 for ( k = 1; k <= nump; k++ )
7249 {
7250 if ( exc->args < 2 )
7251 {
7252 if ( exc->pedantic_hinting )
7253 exc->error = FT_THROW( Too_Few_Arguments );
7254 exc->args = 0;
7255 goto Fail;
7288
7289 C += exc->GS.delta_base;
7290
7291 if ( P == C )
7292 {
7293 B = ( (FT_ULong)B & 0xF ) - 8;
7294 if ( B >= 0 )
7295 B++;
7296 B *= 1L << ( 6 - exc->GS.delta_shift );
7297
7298 exc->func_move_cvt( exc, A, B );
7299 }
7300 }
7301 }
7302
7303 Fail:
7304 exc->new_top = exc->args;
7305 }
7306
7307
7308 /*************************************************************************/
7309 /* */
7310 /* MISC. INSTRUCTIONS */
7311 /* */
7312 /*************************************************************************/
7313
7314
7315 /*************************************************************************/
7316 /* */
7317 /* GETINFO[]: GET INFOrmation */
7318 /* Opcode range: 0x88 */
7319 /* Stack: uint32 --> uint32 */
7320 /* */
7321 /* XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May */
7322 /* 2015) not documented in the OpenType specification. */
7323 /* */
7324 /* Selector bit 11 is incorrectly described as bit 8, while the */
7325 /* real meaning of bit 8 (vertical LCD subpixels) stays */
7326 /* undocumented. The same mistake can be found in Greg Hitchcock's */
7327 /* whitepaper. */
7328 /* */
7329 static void
7330 Ins_GETINFO( TT_ExecContext exc,
7331 FT_Long* args )
7332 {
7333 FT_Long K;
7334 TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face );
7335
7336
7337 K = 0;
7338
7339 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7340 /********************************/
7341 /* RASTERIZER VERSION */
7342 /* Selector Bit: 0 */
7343 /* Return Bit(s): 0-7 */
7344 /* */
7345 if ( SUBPIXEL_HINTING_INFINALITY &&
7346 ( args[0] & 1 ) != 0 &&
7347 exc->subpixel_hinting )
7348 {
7349 if ( exc->ignore_x_mode )
7350 {
7351 /* if in ClearType backward compatibility mode, */
7352 /* we sometimes change the TrueType version dynamically */
7353 K = exc->rasterizer_version;
7354 FT_TRACE6(( "Setting rasterizer version %d\n",
7355 exc->rasterizer_version ));
7356 }
7357 else
7358 K = TT_INTERPRETER_VERSION_38;
7359 }
7360 else
7361 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7362 if ( ( args[0] & 1 ) != 0 )
7363 K = driver->interpreter_version;
7364
7365 /********************************/
7366 /* GLYPH ROTATED */
7367 /* Selector Bit: 1 */
7368 /* Return Bit(s): 8 */
7369 /* */
7370 if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )
7371 K |= 1 << 8;
7372
7373 /********************************/
7374 /* GLYPH STRETCHED */
7375 /* Selector Bit: 2 */
7376 /* Return Bit(s): 9 */
7377 /* */
7378 if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )
7379 K |= 1 << 9;
7380
7381 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7382 /********************************/
7383 /* VARIATION GLYPH */
7384 /* Selector Bit: 3 */
7385 /* Return Bit(s): 10 */
7386 /* */
7387 /* XXX: UNDOCUMENTED! */
7388 if ( (args[0] & 8 ) != 0 && exc->face->blend )
7389 K |= 1 << 10;
7390 #endif
7391
7392 /********************************/
7393 /* BI-LEVEL HINTING AND */
7394 /* GRAYSCALE RENDERING */
7395 /* Selector Bit: 5 */
7396 /* Return Bit(s): 12 */
7397 /* */
7398 if ( ( args[0] & 32 ) != 0 && exc->grayscale )
7399 K |= 1 << 12;
7400
7401 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7402 /* Toggle the following flags only outside of monochrome mode. */
7403 /* Otherwise, instructions may behave weirdly and rendering results */
7404 /* may differ between v35 and v40 mode, e.g., in `Times New Roman */
7405 /* Bold Italic'. */
7406 if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
7407 {
7408 /********************************/
7409 /* HINTING FOR SUBPIXEL */
7410 /* Selector Bit: 6 */
7411 /* Return Bit(s): 13 */
7412 /* */
7413 /* v40 does subpixel hinting by default. */
7414 if ( ( args[0] & 64 ) != 0 )
7415 K |= 1 << 13;
7416
7417 /********************************/
7418 /* VERTICAL LCD SUBPIXELS? */
7419 /* Selector Bit: 8 */
7420 /* Return Bit(s): 15 */
7421 /* */
7422 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
7423 K |= 1 << 15;
7424
7425 /********************************/
7426 /* SUBPIXEL POSITIONED? */
7427 /* Selector Bit: 10 */
7428 /* Return Bit(s): 17 */
7429 /* */
7430 /* XXX: FreeType supports it, dependent on what client does? */
7431 if ( ( args[0] & 1024 ) != 0 )
7432 K |= 1 << 17;
7433
7434 /********************************/
7435 /* SYMMETRICAL SMOOTHING */
7436 /* Selector Bit: 11 */
7437 /* Return Bit(s): 18 */
7438 /* */
7439 /* The only smoothing method FreeType supports unless someone sets */
7440 /* FT_LOAD_TARGET_MONO. */
7441 if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
7442 K |= 1 << 18;
7443
7444 /********************************/
7445 /* CLEARTYPE HINTING AND */
7446 /* GRAYSCALE RENDERING */
7447 /* Selector Bit: 12 */
7448 /* Return Bit(s): 19 */
7449 /* */
7450 /* Grayscale rendering is what FreeType does anyway unless someone */
7451 /* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */
7452 if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
7453 K |= 1 << 19;
7454 }
7455 #endif
7456
7457 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7458
7459 if ( SUBPIXEL_HINTING_INFINALITY &&
7460 exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7461 {
7462
7463 if ( exc->rasterizer_version >= 37 )
7464 {
7465 /********************************/
7466 /* HINTING FOR SUBPIXEL */
7467 /* Selector Bit: 6 */
7468 /* Return Bit(s): 13 */
7469 /* */
7470 if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
7471 K |= 1 << 13;
7472
7473 /********************************/
7474 /* COMPATIBLE WIDTHS ENABLED */
7475 /* Selector Bit: 7 */
7476 /* Return Bit(s): 14 */
7477 /* */
7478 /* Functionality still needs to be added */
7479 if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
7480 K |= 1 << 14;
7481
7482 /********************************/
7483 /* VERTICAL LCD SUBPIXELS? */
7484 /* Selector Bit: 8 */
7485 /* Return Bit(s): 15 */
7486 /* */
7487 /* Functionality still needs to be added */
7488 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
7489 K |= 1 << 15;
7490
7491 /********************************/
7492 /* HINTING FOR BGR? */
7493 /* Selector Bit: 9 */
7494 /* Return Bit(s): 16 */
7495 /* */
7496 /* Functionality still needs to be added */
7497 if ( ( args[0] & 512 ) != 0 && exc->bgr )
7498 K |= 1 << 16;
7499
7500 if ( exc->rasterizer_version >= 38 )
7501 {
7502 /********************************/
7503 /* SUBPIXEL POSITIONED? */
7504 /* Selector Bit: 10 */
7505 /* Return Bit(s): 17 */
7506 /* */
7507 /* Functionality still needs to be added */
7508 if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
7509 K |= 1 << 17;
7510
7511 /********************************/
7512 /* SYMMETRICAL SMOOTHING */
7513 /* Selector Bit: 11 */
7514 /* Return Bit(s): 18 */
7515 /* */
7516 /* Functionality still needs to be added */
7517 if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
7518 K |= 1 << 18;
7519
7520 /********************************/
7521 /* GRAY CLEARTYPE */
7522 /* Selector Bit: 12 */
7523 /* Return Bit(s): 19 */
7524 /* */
7525 /* Functionality still needs to be added */
7526 if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
7527 K |= 1 << 19;
7528 }
7529 }
7530 }
7531
7532 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7533
7534 args[0] = K;
7535 }
7536
7537
7538 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7539
7540 /*************************************************************************/
7541 /* */
7542 /* GETVARIATION[]: get normalized variation (blend) coordinates */
7543 /* Opcode range: 0x91 */
7544 /* Stack: --> f2.14... */
7545 /* */
7546 /* XXX: UNDOCUMENTED! There is no official documentation from Apple for */
7547 /* this bytecode instruction. Active only if a font has GX */
7548 /* variation axes. */
7549 /* */
7550 static void
7551 Ins_GETVARIATION( TT_ExecContext exc,
7552 FT_Long* args )
7553 {
7554 FT_UInt num_axes = exc->face->blend->num_axis;
7555 FT_Fixed* coords = exc->face->blend->normalizedcoords;
7556
7557 FT_UInt i;
7558
7559
7560 if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) )
7561 {
7562 exc->error = FT_THROW( Stack_Overflow );
7563 return;
7564 }
7565
7566 if ( coords )
7567 {
7568 for ( i = 0; i < num_axes; i++ )
7569 args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
7570 }
7571 else
7572 {
7573 for ( i = 0; i < num_axes; i++ )
7574 args[i] = 0;
7575 }
7576 }
7577
7578
7579 /*************************************************************************/
7580 /* */
7581 /* GETDATA[]: no idea what this is good for */
7582 /* Opcode range: 0x92 */
7583 /* Stack: --> 17 */
7584 /* */
7585 /* XXX: UNDOCUMENTED! There is no documentation from Apple for this */
7586 /* very weird bytecode instruction. */
7587 /* */
7588 static void
7589 Ins_GETDATA( FT_Long* args )
7590 {
7591 args[0] = 17;
7592 }
7593
7594 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
7595
7596
7597 static void
7598 Ins_UNKNOWN( TT_ExecContext exc )
7599 {
7600 TT_DefRecord* def = exc->IDefs;
7601 TT_DefRecord* limit = def + exc->numIDefs;
7602
7603
7604 for ( ; def < limit; def++ )
7605 {
7606 if ( (FT_Byte)def->opc == exc->opcode && def->active )
7607 {
7615 }
7616
7617 call = exc->callStack + exc->callTop++;
7618
7619 call->Caller_Range = exc->curRange;
7620 call->Caller_IP = exc->IP + 1;
7621 call->Cur_Count = 1;
7622 call->Def = def;
7623
7624 Ins_Goto_CodeRange( exc, def->range, def->start );
7625
7626 exc->step_ins = FALSE;
7627 return;
7628 }
7629 }
7630
7631 exc->error = FT_THROW( Invalid_Opcode );
7632 }
7633
7634
7635 /*************************************************************************/
7636 /* */
7637 /* RUN */
7638 /* */
7639 /* This function executes a run of opcodes. It will exit in the */
7640 /* following cases: */
7641 /* */
7642 /* - Errors (in which case it returns FALSE). */
7643 /* */
7644 /* - Reaching the end of the main code range (returns TRUE). */
7645 /* Reaching the end of a code range within a function call is an */
7646 /* error. */
7647 /* */
7648 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7649 /* is set to TRUE (returns TRUE). */
7650 /* */
7651 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7652 /* an instruction trap or a normal termination. */
7653 /* */
7654 /* */
7655 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7656 /* behaviour is unsupported; here a DEBUG opcode is always an */
7657 /* error. */
7658 /* */
7659 /* */
7660 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7661 /* */
7662 /*************************************************************************/
7663
7664
7665 /* documentation is in ttinterp.h */
7666
7667 FT_EXPORT_DEF( FT_Error )
7668 TT_RunIns( TT_ExecContext exc )
7669 {
7670 FT_ULong ins_counter = 0; /* executed instructions counter */
7671 FT_ULong num_twilight_points;
7672 FT_UShort i;
7673
7674 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7675 FT_Byte opcode_pattern[1][2] = {
7676 /* #8 TypeMan Talk Align */
7677 {
7678 0x06, /* SPVTL */
7679 0x7D, /* RDTG */
7680 },
7681 };
7682 FT_UShort opcode_patterns = 1;
7784 exc->func_move_cvt = Move_CVT;
7785 }
7786
7787 Compute_Funcs( exc );
7788 Compute_Round( exc, (FT_Byte)exc->GS.round_state );
7789
7790 do
7791 {
7792 exc->opcode = exc->code[exc->IP];
7793
7794 #ifdef FT_DEBUG_LEVEL_TRACE
7795 {
7796 FT_Long cnt = FT_MIN( 8, exc->top );
7797 FT_Long n;
7798
7799
7800 /* if tracing level is 7, show current code position */
7801 /* and the first few stack elements also */
7802 FT_TRACE6(( " " ));
7803 FT_TRACE7(( "%06d ", exc->IP ));
7804 FT_TRACE6(( opcode_name[exc->opcode] + 2 ));
7805 FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'
7806 ? 2
7807 : 12 - ( *opcode_name[exc->opcode] - '0' ),
7808 "#" ));
7809 for ( n = 1; n <= cnt; n++ )
7810 FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
7811 FT_TRACE6(( "\n" ));
7812 }
7813 #endif /* FT_DEBUG_LEVEL_TRACE */
7814
7815 if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
7816 {
7817 if ( exc->IP + 1 >= exc->codeSize )
7818 goto LErrorCodeOverflow_;
7819
7820 exc->length = 2 - exc->length * exc->code[exc->IP + 1];
7821 }
7822
7823 if ( exc->IP + exc->length > exc->codeSize )
7824 goto LErrorCodeOverflow_;
|
1 /****************************************************************************
2 *
3 * ttinterp.c
4 *
5 * TrueType bytecode interpreter (body).
6 *
7 * Copyright (C) 1996-2019 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
20 /* issues; many thanks! */
21
22
23 #include <ft2build.h>
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_CALC_H
26 #include FT_TRIGONOMETRY_H
27 #include FT_SYSTEM_H
28 #include FT_DRIVER_H
29 #include FT_MULTIPLE_MASTERS_H
30
31 #include "ttinterp.h"
32 #include "tterrors.h"
33 #include "ttsubpix.h"
34 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
35 #include "ttgxvar.h"
36 #endif
37
38
39 #ifdef TT_USE_BYTECODE_INTERPRETER
40
41
42 /**************************************************************************
43 *
44 * The macro FT_COMPONENT is used in trace mode. It is an implicit
45 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
46 * messages during execution.
47 */
48 #undef FT_COMPONENT
49 #define FT_COMPONENT ttinterp
50
51
52 #define NO_SUBPIXEL_HINTING \
53 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
54 TT_INTERPRETER_VERSION_35 )
55
56 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
57 #define SUBPIXEL_HINTING_INFINALITY \
58 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
59 TT_INTERPRETER_VERSION_38 )
60 #endif
61
62 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
63 #define SUBPIXEL_HINTING_MINIMAL \
64 ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
65 TT_INTERPRETER_VERSION_40 )
66 #endif
67
68 #define PROJECT( v1, v2 ) \
69 exc->func_project( exc, \
70 SUB_LONG( (v1)->x, (v2)->x ), \
71 SUB_LONG( (v1)->y, (v2)->y ) )
72
73 #define DUALPROJ( v1, v2 ) \
74 exc->func_dualproj( exc, \
75 SUB_LONG( (v1)->x, (v2)->x ), \
76 SUB_LONG( (v1)->y, (v2)->y ) )
77
78 #define FAST_PROJECT( v ) \
79 exc->func_project( exc, (v)->x, (v)->y )
80
81 #define FAST_DUALPROJ( v ) \
82 exc->func_dualproj( exc, (v)->x, (v)->y )
83
84
85 /**************************************************************************
86 *
87 * Two simple bounds-checking macros.
88 */
89 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
90 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
91
92
93 #undef SUCCESS
94 #define SUCCESS 0
95
96 #undef FAILURE
97 #define FAILURE 1
98
99
100 /**************************************************************************
101 *
102 * CODERANGE FUNCTIONS
103 *
104 */
105
106
107 /**************************************************************************
108 *
109 * @Function:
110 * TT_Goto_CodeRange
111 *
112 * @Description:
113 * Switches to a new code range (updates the code related elements in
114 * `exec', and `IP').
115 *
116 * @Input:
117 * range ::
118 * The new execution code range.
119 *
120 * IP ::
121 * The new IP in the new code range.
122 *
123 * @InOut:
124 * exec ::
125 * The target execution context.
126 */
127 FT_LOCAL_DEF( void )
128 TT_Goto_CodeRange( TT_ExecContext exec,
129 FT_Int range,
130 FT_Long IP )
131 {
132 TT_CodeRange* coderange;
133
134
135 FT_ASSERT( range >= 1 && range <= 3 );
136
137 coderange = &exec->codeRangeTable[range - 1];
138
139 FT_ASSERT( coderange->base );
140
141 /* NOTE: Because the last instruction of a program may be a CALL */
142 /* which will return to the first byte *after* the code */
143 /* range, we test for IP <= Size instead of IP < Size. */
144 /* */
145 FT_ASSERT( IP <= coderange->size );
146
147 exec->code = coderange->base;
148 exec->codeSize = coderange->size;
149 exec->IP = IP;
150 exec->curRange = range;
151 }
152
153
154 /**************************************************************************
155 *
156 * @Function:
157 * TT_Set_CodeRange
158 *
159 * @Description:
160 * Sets a code range.
161 *
162 * @Input:
163 * range ::
164 * The code range index.
165 *
166 * base ::
167 * The new code base.
168 *
169 * length ::
170 * The range size in bytes.
171 *
172 * @InOut:
173 * exec ::
174 * The target execution context.
175 */
176 FT_LOCAL_DEF( void )
177 TT_Set_CodeRange( TT_ExecContext exec,
178 FT_Int range,
179 void* base,
180 FT_Long length )
181 {
182 FT_ASSERT( range >= 1 && range <= 3 );
183
184 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
185 exec->codeRangeTable[range - 1].size = length;
186 }
187
188
189 /**************************************************************************
190 *
191 * @Function:
192 * TT_Clear_CodeRange
193 *
194 * @Description:
195 * Clears a code range.
196 *
197 * @Input:
198 * range ::
199 * The code range index.
200 *
201 * @InOut:
202 * exec ::
203 * The target execution context.
204 */
205 FT_LOCAL_DEF( void )
206 TT_Clear_CodeRange( TT_ExecContext exec,
207 FT_Int range )
208 {
209 FT_ASSERT( range >= 1 && range <= 3 );
210
211 exec->codeRangeTable[range - 1].base = NULL;
212 exec->codeRangeTable[range - 1].size = 0;
213 }
214
215
216 /**************************************************************************
217 *
218 * EXECUTION CONTEXT ROUTINES
219 *
220 */
221
222
223 /**************************************************************************
224 *
225 * @Function:
226 * TT_Done_Context
227 *
228 * @Description:
229 * Destroys a given context.
230 *
231 * @Input:
232 * exec ::
233 * A handle to the target execution context.
234 *
235 * memory ::
236 * A handle to the parent memory object.
237 *
238 * @Note:
239 * Only the glyph loader and debugger should call this function.
240 */
241 FT_LOCAL_DEF( void )
242 TT_Done_Context( TT_ExecContext exec )
243 {
244 FT_Memory memory = exec->memory;
245
246
247 /* points zone */
248 exec->maxPoints = 0;
249 exec->maxContours = 0;
250
251 /* free stack */
252 FT_FREE( exec->stack );
253 exec->stackSize = 0;
254
255 /* free call stack */
256 FT_FREE( exec->callStack );
257 exec->callSize = 0;
258 exec->callTop = 0;
259
260 /* free glyph code range */
261 FT_FREE( exec->glyphIns );
262 exec->glyphSize = 0;
263
264 exec->size = NULL;
265 exec->face = NULL;
266
267 FT_FREE( exec );
268 }
269
270
271 /**************************************************************************
272 *
273 * @Function:
274 * Init_Context
275 *
276 * @Description:
277 * Initializes a context object.
278 *
279 * @Input:
280 * memory ::
281 * A handle to the parent memory object.
282 *
283 * @InOut:
284 * exec ::
285 * A handle to the target execution context.
286 *
287 * @Return:
288 * FreeType error code. 0 means success.
289 */
290 static FT_Error
291 Init_Context( TT_ExecContext exec,
292 FT_Memory memory )
293 {
294 FT_Error error;
295
296
297 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
298
299 exec->memory = memory;
300 exec->callSize = 32;
301
302 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
303 goto Fail_Memory;
304
305 /* all values in the context are set to 0 already, but this is */
306 /* here as a remainder */
307 exec->maxPoints = 0;
308 exec->maxContours = 0;
309
310 exec->stackSize = 0;
311 exec->glyphSize = 0;
312
313 exec->stack = NULL;
314 exec->glyphIns = NULL;
315
316 exec->face = NULL;
317 exec->size = NULL;
318
319 return FT_Err_Ok;
320
321 Fail_Memory:
322 FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
323 TT_Done_Context( exec );
324
325 return error;
326 }
327
328
329 /**************************************************************************
330 *
331 * @Function:
332 * Update_Max
333 *
334 * @Description:
335 * Checks the size of a buffer and reallocates it if necessary.
336 *
337 * @Input:
338 * memory ::
339 * A handle to the parent memory object.
340 *
341 * multiplier ::
342 * The size in bytes of each element in the buffer.
343 *
344 * new_max ::
345 * The new capacity (size) of the buffer.
346 *
347 * @InOut:
348 * size ::
349 * The address of the buffer's current size expressed
350 * in elements.
351 *
352 * buff ::
353 * The address of the buffer base pointer.
354 *
355 * @Return:
356 * FreeType error code. 0 means success.
357 */
358 FT_LOCAL_DEF( FT_Error )
359 Update_Max( FT_Memory memory,
360 FT_ULong* size,
361 FT_ULong multiplier,
362 void* _pbuff,
363 FT_ULong new_max )
364 {
365 FT_Error error;
366 void** pbuff = (void**)_pbuff;
367
368
369 if ( *size < new_max )
370 {
371 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
372 return error;
373 *size = new_max;
374 }
375
376 return FT_Err_Ok;
377 }
378
379
380 /**************************************************************************
381 *
382 * @Function:
383 * TT_Load_Context
384 *
385 * @Description:
386 * Prepare an execution context for glyph hinting.
387 *
388 * @Input:
389 * face ::
390 * A handle to the source face object.
391 *
392 * size ::
393 * A handle to the source size object.
394 *
395 * @InOut:
396 * exec ::
397 * A handle to the target execution context.
398 *
399 * @Return:
400 * FreeType error code. 0 means success.
401 *
402 * @Note:
403 * Only the glyph loader and debugger should call this function.
404 */
405 FT_LOCAL_DEF( FT_Error )
406 TT_Load_Context( TT_ExecContext exec,
407 TT_Face face,
408 TT_Size size )
409 {
410 FT_Int i;
411 FT_ULong tmp;
412 TT_MaxProfile* maxp;
413 FT_Error error;
414
415
416 exec->face = face;
417 maxp = &face->max_profile;
418 exec->size = size;
419
420 if ( size )
421 {
422 exec->numFDefs = size->num_function_defs;
423 exec->maxFDefs = size->max_function_defs;
424 exec->numIDefs = size->num_instruction_defs;
471 sizeof ( FT_Byte ),
472 (void*)&exec->glyphIns,
473 maxp->maxSizeOfInstructions );
474 exec->glyphSize = (FT_UShort)tmp;
475 if ( error )
476 return error;
477
478 exec->pts.n_points = 0;
479 exec->pts.n_contours = 0;
480
481 exec->zp1 = exec->pts;
482 exec->zp2 = exec->pts;
483 exec->zp0 = exec->pts;
484
485 exec->instruction_trap = FALSE;
486
487 return FT_Err_Ok;
488 }
489
490
491 /**************************************************************************
492 *
493 * @Function:
494 * TT_Save_Context
495 *
496 * @Description:
497 * Saves the code ranges in a `size' object.
498 *
499 * @Input:
500 * exec ::
501 * A handle to the source execution context.
502 *
503 * @InOut:
504 * size ::
505 * A handle to the target size object.
506 *
507 * @Note:
508 * Only the glyph loader and debugger should call this function.
509 */
510 FT_LOCAL_DEF( void )
511 TT_Save_Context( TT_ExecContext exec,
512 TT_Size size )
513 {
514 FT_Int i;
515
516
517 /* XXX: Will probably disappear soon with all the code range */
518 /* management, which is now rather obsolete. */
519 /* */
520 size->num_function_defs = exec->numFDefs;
521 size->num_instruction_defs = exec->numIDefs;
522
523 size->max_func = exec->maxFunc;
524 size->max_ins = exec->maxIns;
525
526 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
527 size->codeRangeTable[i] = exec->codeRangeTable[i];
528 }
529
530
531 /**************************************************************************
532 *
533 * @Function:
534 * TT_Run_Context
535 *
536 * @Description:
537 * Executes one or more instructions in the execution context.
538 *
539 * @Input:
540 * exec ::
541 * A handle to the target execution context.
542 *
543 * @Return:
544 * TrueType error code. 0 means success.
545 */
546 FT_LOCAL_DEF( FT_Error )
547 TT_Run_Context( TT_ExecContext exec )
548 {
549 TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
550
551 exec->zp0 = exec->pts;
552 exec->zp1 = exec->pts;
553 exec->zp2 = exec->pts;
554
555 exec->GS.gep0 = 1;
556 exec->GS.gep1 = 1;
557 exec->GS.gep2 = 1;
558
559 exec->GS.projVector.x = 0x4000;
560 exec->GS.projVector.y = 0x0000;
561
562 exec->GS.freeVector = exec->GS.projVector;
563 exec->GS.dualVector = exec->GS.projVector;
564
565 exec->GS.round_state = 1;
609 goto Fail;
610
611 memory = driver->root.root.memory;
612
613 /* allocate object */
614 if ( FT_NEW( exec ) )
615 goto Fail;
616
617 /* initialize it; in case of error this deallocates `exec' too */
618 error = Init_Context( exec, memory );
619 if ( error )
620 goto Fail;
621
622 return exec;
623
624 Fail:
625 return NULL;
626 }
627
628
629 /**************************************************************************
630 *
631 * Before an opcode is executed, the interpreter verifies that there are
632 * enough arguments on the stack, with the help of the `Pop_Push_Count'
633 * table.
634 *
635 * For each opcode, the first column gives the number of arguments that
636 * are popped from the stack; the second one gives the number of those
637 * that are pushed in result.
638 *
639 * Opcodes which have a varying number of parameters in the data stream
640 * (NPUSHB, NPUSHW) are handled specially; they have a negative value in
641 * the `opcode_length' table, and the value in `Pop_Push_Count' is set
642 * to zero.
643 *
644 */
645
646
647 #undef PACK
648 #define PACK( x, y ) ( ( x << 4 ) | y )
649
650
651 static
652 const FT_Byte Pop_Push_Count[256] =
653 {
654 /* opcodes are gathered in groups of 16 */
655 /* please keep the spaces as they are */
656
657 /* SVTCA y */ PACK( 0, 0 ),
658 /* SVTCA x */ PACK( 0, 0 ),
659 /* SPvTCA y */ PACK( 0, 0 ),
660 /* SPvTCA x */ PACK( 0, 0 ),
661 /* SFvTCA y */ PACK( 0, 0 ),
662 /* SFvTCA x */ PACK( 0, 0 ),
663 /* SPvTL // */ PACK( 2, 0 ),
664 /* SPvTL + */ PACK( 2, 0 ),
1129 "7 INS_$AE",
1130 "7 INS_$AF",
1131
1132 "8 PushB[0]",
1133 "8 PushB[1]",
1134 "8 PushB[2]",
1135 "8 PushB[3]",
1136 "8 PushB[4]",
1137 "8 PushB[5]",
1138 "8 PushB[6]",
1139 "8 PushB[7]",
1140 "8 PushW[0]",
1141 "8 PushW[1]",
1142 "8 PushW[2]",
1143 "8 PushW[3]",
1144 "8 PushW[4]",
1145 "8 PushW[5]",
1146 "8 PushW[6]",
1147 "8 PushW[7]",
1148
1149 "7 MDRP[G]",
1150 "7 MDRP[B]",
1151 "7 MDRP[W]",
1152 "7 MDRP[?]",
1153 "8 MDRP[rG]",
1154 "8 MDRP[rB]",
1155 "8 MDRP[rW]",
1156 "8 MDRP[r?]",
1157 "8 MDRP[mG]",
1158 "8 MDRP[mB]",
1159 "8 MDRP[mW]",
1160 "8 MDRP[m?]",
1161 "9 MDRP[mrG]",
1162 "9 MDRP[mrB]",
1163 "9 MDRP[mrW]",
1164 "9 MDRP[mr?]",
1165
1166 "8 MDRP[pG]",
1167 "8 MDRP[pB]",
1168 "8 MDRP[pW]",
1169 "8 MDRP[p?]",
1170 "9 MDRP[prG]",
1171 "9 MDRP[prB]",
1172 "9 MDRP[prW]",
1173 "9 MDRP[pr?]",
1174 "9 MDRP[pmG]",
1175 "9 MDRP[pmB]",
1176 "9 MDRP[pmW]",
1177 "9 MDRP[pm?]",
1178 "A MDRP[pmrG]",
1179 "A MDRP[pmrB]",
1180 "A MDRP[pmrW]",
1181 "A MDRP[pmr?]",
1182
1183 "7 MIRP[G]",
1184 "7 MIRP[B]",
1185 "7 MIRP[W]",
1186 "7 MIRP[?]",
1187 "8 MIRP[rG]",
1188 "8 MIRP[rB]",
1189 "8 MIRP[rW]",
1190 "8 MIRP[r?]",
1191 "8 MIRP[mG]",
1192 "8 MIRP[mB]",
1193 "8 MIRP[mW]",
1194 "8 MIRP[m?]",
1195 "9 MIRP[mrG]",
1196 "9 MIRP[mrB]",
1197 "9 MIRP[mrW]",
1198 "9 MIRP[mr?]",
1199
1200 "8 MIRP[pG]",
1201 "8 MIRP[pB]",
1202 "8 MIRP[pW]",
1203 "8 MIRP[p?]",
1204 "9 MIRP[prG]",
1205 "9 MIRP[prB]",
1206 "9 MIRP[prW]",
1207 "9 MIRP[pr?]",
1208 "9 MIRP[pmG]",
1209 "9 MIRP[pmB]",
1210 "9 MIRP[pmW]",
1211 "9 MIRP[pm?]",
1212 "A MIRP[pmrG]",
1213 "A MIRP[pmrB]",
1214 "A MIRP[pmrW]",
1215 "A MIRP[pmr?]"
1216 };
1217
1218 #endif /* FT_DEBUG_LEVEL_TRACE */
1219
1220
1221 static
1222 const FT_Char opcode_length[256] =
1223 {
1224 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1225 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1226 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1227 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1228
1229 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1230 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1231 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1232 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1233
1234 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1235 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1448
1449 /* add them */
1450 lo = lo1 + lo2;
1451 hi = hi1 + hi2 + ( lo < lo1 );
1452
1453 /* divide the result by 2^14 with rounding */
1454 s = hi >> 31;
1455 l = lo + (FT_UInt32)s;
1456 hi += s + ( l < lo );
1457 lo = l;
1458
1459 l = lo + 0x2000U;
1460 hi += ( l < lo );
1461
1462 return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
1463 }
1464
1465 #endif /* TT_DotFix14 */
1466
1467
1468 /**************************************************************************
1469 *
1470 * @Function:
1471 * Current_Ratio
1472 *
1473 * @Description:
1474 * Returns the current aspect ratio scaling factor depending on the
1475 * projection vector's state and device resolutions.
1476 *
1477 * @Return:
1478 * The aspect ratio in 16.16 format, always <= 1.0 .
1479 */
1480 static FT_Long
1481 Current_Ratio( TT_ExecContext exc )
1482 {
1483 if ( !exc->tt_metrics.ratio )
1484 {
1485 if ( exc->GS.projVector.y == 0 )
1486 exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;
1487
1488 else if ( exc->GS.projVector.x == 0 )
1489 exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;
1490
1491 else
1492 {
1493 FT_F26Dot6 x, y;
1494
1495
1496 x = TT_MulFix14( exc->tt_metrics.x_ratio,
1497 exc->GS.projVector.x );
1498 y = TT_MulFix14( exc->tt_metrics.y_ratio,
1499 exc->GS.projVector.y );
1501 }
1502 }
1503 return exc->tt_metrics.ratio;
1504 }
1505
1506
1507 FT_CALLBACK_DEF( FT_Long )
1508 Current_Ppem( TT_ExecContext exc )
1509 {
1510 return exc->tt_metrics.ppem;
1511 }
1512
1513
1514 FT_CALLBACK_DEF( FT_Long )
1515 Current_Ppem_Stretched( TT_ExecContext exc )
1516 {
1517 return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );
1518 }
1519
1520
1521 /**************************************************************************
1522 *
1523 * Functions related to the control value table (CVT).
1524 *
1525 */
1526
1527
1528 FT_CALLBACK_DEF( FT_F26Dot6 )
1529 Read_CVT( TT_ExecContext exc,
1530 FT_ULong idx )
1531 {
1532 return exc->cvt[idx];
1533 }
1534
1535
1536 FT_CALLBACK_DEF( FT_F26Dot6 )
1537 Read_CVT_Stretched( TT_ExecContext exc,
1538 FT_ULong idx )
1539 {
1540 return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
1541 }
1542
1543
1544 FT_CALLBACK_DEF( void )
1545 Write_CVT( TT_ExecContext exc,
1547 FT_F26Dot6 value )
1548 {
1549 exc->cvt[idx] = value;
1550 }
1551
1552
1553 FT_CALLBACK_DEF( void )
1554 Write_CVT_Stretched( TT_ExecContext exc,
1555 FT_ULong idx,
1556 FT_F26Dot6 value )
1557 {
1558 exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
1559 }
1560
1561
1562 FT_CALLBACK_DEF( void )
1563 Move_CVT( TT_ExecContext exc,
1564 FT_ULong idx,
1565 FT_F26Dot6 value )
1566 {
1567 exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value );
1568 }
1569
1570
1571 FT_CALLBACK_DEF( void )
1572 Move_CVT_Stretched( TT_ExecContext exc,
1573 FT_ULong idx,
1574 FT_F26Dot6 value )
1575 {
1576 exc->cvt[idx] = ADD_LONG( exc->cvt[idx],
1577 FT_DivFix( value, Current_Ratio( exc ) ) );
1578 }
1579
1580
1581 /**************************************************************************
1582 *
1583 * @Function:
1584 * GetShortIns
1585 *
1586 * @Description:
1587 * Returns a short integer taken from the instruction stream at
1588 * address IP.
1589 *
1590 * @Return:
1591 * Short read at code[IP].
1592 *
1593 * @Note:
1594 * This one could become a macro.
1595 */
1596 static FT_Short
1597 GetShortIns( TT_ExecContext exc )
1598 {
1599 /* Reading a byte stream so there is no endianness (DaveP) */
1600 exc->IP += 2;
1601 return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
1602 exc->code[exc->IP - 1] );
1603 }
1604
1605
1606 /**************************************************************************
1607 *
1608 * @Function:
1609 * Ins_Goto_CodeRange
1610 *
1611 * @Description:
1612 * Goes to a certain code range in the instruction stream.
1613 *
1614 * @Input:
1615 * aRange ::
1616 * The index of the code range.
1617 *
1618 * aIP ::
1619 * The new IP address in the code range.
1620 *
1621 * @Return:
1622 * SUCCESS or FAILURE.
1623 */
1624 static FT_Bool
1625 Ins_Goto_CodeRange( TT_ExecContext exc,
1626 FT_Int aRange,
1627 FT_Long aIP )
1628 {
1629 TT_CodeRange* range;
1630
1631
1632 if ( aRange < 1 || aRange > 3 )
1633 {
1634 exc->error = FT_THROW( Bad_Argument );
1635 return FAILURE;
1636 }
1637
1638 range = &exc->codeRangeTable[aRange - 1];
1639
1640 if ( !range->base ) /* invalid coderange */
1641 {
1642 exc->error = FT_THROW( Invalid_CodeRange );
1643 return FAILURE;
1645
1646 /* NOTE: Because the last instruction of a program may be a CALL */
1647 /* which will return to the first byte *after* the code */
1648 /* range, we test for aIP <= Size, instead of aIP < Size. */
1649
1650 if ( aIP > range->size )
1651 {
1652 exc->error = FT_THROW( Code_Overflow );
1653 return FAILURE;
1654 }
1655
1656 exc->code = range->base;
1657 exc->codeSize = range->size;
1658 exc->IP = aIP;
1659 exc->curRange = aRange;
1660
1661 return SUCCESS;
1662 }
1663
1664
1665 /**************************************************************************
1666 *
1667 * @Function:
1668 * Direct_Move
1669 *
1670 * @Description:
1671 * Moves a point by a given distance along the freedom vector. The
1672 * point will be `touched'.
1673 *
1674 * @Input:
1675 * point ::
1676 * The index of the point to move.
1677 *
1678 * distance ::
1679 * The distance to apply.
1680 *
1681 * @InOut:
1682 * zone ::
1683 * The affected glyph zone.
1684 *
1685 * @Note:
1686 * See `ttinterp.h' for details on backward compatibility mode.
1687 * `Touches' the point.
1688 */
1689 static void
1690 Direct_Move( TT_ExecContext exc,
1691 TT_GlyphZone zone,
1692 FT_UShort point,
1693 FT_F26Dot6 distance )
1694 {
1695 FT_F26Dot6 v;
1696
1697
1698 v = exc->GS.freeVector.x;
1699
1700 if ( v != 0 )
1701 {
1702 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1703 if ( SUBPIXEL_HINTING_INFINALITY &&
1704 ( !exc->ignore_x_mode ||
1705 ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
1706 zone->cur[point].x = ADD_LONG( zone->cur[point].x,
1707 FT_MulDiv( distance,
1708 v,
1734 v = exc->GS.freeVector.y;
1735
1736 if ( v != 0 )
1737 {
1738 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1739 if ( !( SUBPIXEL_HINTING_MINIMAL &&
1740 exc->backward_compatibility &&
1741 exc->iupx_called &&
1742 exc->iupy_called ) )
1743 #endif
1744 zone->cur[point].y = ADD_LONG( zone->cur[point].y,
1745 FT_MulDiv( distance,
1746 v,
1747 exc->F_dot_P ) );
1748
1749 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1750 }
1751 }
1752
1753
1754 /**************************************************************************
1755 *
1756 * @Function:
1757 * Direct_Move_Orig
1758 *
1759 * @Description:
1760 * Moves the *original* position of a point by a given distance along
1761 * the freedom vector. Obviously, the point will not be `touched'.
1762 *
1763 * @Input:
1764 * point ::
1765 * The index of the point to move.
1766 *
1767 * distance ::
1768 * The distance to apply.
1769 *
1770 * @InOut:
1771 * zone ::
1772 * The affected glyph zone.
1773 */
1774 static void
1775 Direct_Move_Orig( TT_ExecContext exc,
1776 TT_GlyphZone zone,
1777 FT_UShort point,
1778 FT_F26Dot6 distance )
1779 {
1780 FT_F26Dot6 v;
1781
1782
1783 v = exc->GS.freeVector.x;
1784
1785 if ( v != 0 )
1786 zone->org[point].x = ADD_LONG( zone->org[point].x,
1787 FT_MulDiv( distance,
1788 v,
1789 exc->F_dot_P ) );
1790
1791 v = exc->GS.freeVector.y;
1792
1793 if ( v != 0 )
1794 zone->org[point].y = ADD_LONG( zone->org[point].y,
1795 FT_MulDiv( distance,
1796 v,
1797 exc->F_dot_P ) );
1798 }
1799
1800
1801 /**************************************************************************
1802 *
1803 * Special versions of Direct_Move()
1804 *
1805 * The following versions are used whenever both vectors are both
1806 * along one of the coordinate unit vectors, i.e. in 90% of the cases.
1807 * See `ttinterp.h' for details on backward compatibility mode.
1808 *
1809 */
1810
1811
1812 static void
1813 Direct_Move_X( TT_ExecContext exc,
1814 TT_GlyphZone zone,
1815 FT_UShort point,
1816 FT_F26Dot6 distance )
1817 {
1818 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1819 if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
1820 zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1821 else
1822 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1823
1824 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1825 if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
1826 zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
1827 else
1828 #endif
1829
1836
1837 static void
1838 Direct_Move_Y( TT_ExecContext exc,
1839 TT_GlyphZone zone,
1840 FT_UShort point,
1841 FT_F26Dot6 distance )
1842 {
1843 FT_UNUSED( exc );
1844
1845 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1846 if ( !( SUBPIXEL_HINTING_MINIMAL &&
1847 exc->backward_compatibility &&
1848 exc->iupx_called && exc->iupy_called ) )
1849 #endif
1850 zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );
1851
1852 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1853 }
1854
1855
1856 /**************************************************************************
1857 *
1858 * Special versions of Direct_Move_Orig()
1859 *
1860 * The following versions are used whenever both vectors are both
1861 * along one of the coordinate unit vectors, i.e. in 90% of the cases.
1862 *
1863 */
1864
1865
1866 static void
1867 Direct_Move_Orig_X( TT_ExecContext exc,
1868 TT_GlyphZone zone,
1869 FT_UShort point,
1870 FT_F26Dot6 distance )
1871 {
1872 FT_UNUSED( exc );
1873
1874 zone->org[point].x = ADD_LONG( zone->org[point].x, distance );
1875 }
1876
1877
1878 static void
1879 Direct_Move_Orig_Y( TT_ExecContext exc,
1880 TT_GlyphZone zone,
1881 FT_UShort point,
1882 FT_F26Dot6 distance )
1883 {
1884 FT_UNUSED( exc );
1885
1886 zone->org[point].y = ADD_LONG( zone->org[point].y, distance );
1887 }
1888
1889
1890 /**************************************************************************
1891 *
1892 * @Function:
1893 * Round_None
1894 *
1895 * @Description:
1896 * Does not round, but adds engine compensation.
1897 *
1898 * @Input:
1899 * distance ::
1900 * The distance (not) to round.
1901 *
1902 * compensation ::
1903 * The engine compensation.
1904 *
1905 * @Return:
1906 * The compensated distance.
1907 *
1908 * @Note:
1909 * The TrueType specification says very few about the relationship
1910 * between rounding and engine compensation. However, it seems from
1911 * the description of super round that we should add the compensation
1912 * before rounding.
1913 */
1914 static FT_F26Dot6
1915 Round_None( TT_ExecContext exc,
1916 FT_F26Dot6 distance,
1917 FT_F26Dot6 compensation )
1918 {
1919 FT_F26Dot6 val;
1920
1921 FT_UNUSED( exc );
1922
1923
1924 if ( distance >= 0 )
1925 {
1926 val = ADD_LONG( distance, compensation );
1927 if ( val < 0 )
1928 val = 0;
1929 }
1930 else
1931 {
1932 val = SUB_LONG( distance, compensation );
1933 if ( val > 0 )
1934 val = 0;
1935 }
1936 return val;
1937 }
1938
1939
1940 /**************************************************************************
1941 *
1942 * @Function:
1943 * Round_To_Grid
1944 *
1945 * @Description:
1946 * Rounds value to grid after adding engine compensation.
1947 *
1948 * @Input:
1949 * distance ::
1950 * The distance to round.
1951 *
1952 * compensation ::
1953 * The engine compensation.
1954 *
1955 * @Return:
1956 * Rounded distance.
1957 */
1958 static FT_F26Dot6
1959 Round_To_Grid( TT_ExecContext exc,
1960 FT_F26Dot6 distance,
1961 FT_F26Dot6 compensation )
1962 {
1963 FT_F26Dot6 val;
1964
1965 FT_UNUSED( exc );
1966
1967
1968 if ( distance >= 0 )
1969 {
1970 val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );
1971 if ( val < 0 )
1972 val = 0;
1973 }
1974 else
1975 {
1976 val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,
1977 distance ) ) );
1978 if ( val > 0 )
1979 val = 0;
1980 }
1981
1982 return val;
1983 }
1984
1985
1986 /**************************************************************************
1987 *
1988 * @Function:
1989 * Round_To_Half_Grid
1990 *
1991 * @Description:
1992 * Rounds value to half grid after adding engine compensation.
1993 *
1994 * @Input:
1995 * distance ::
1996 * The distance to round.
1997 *
1998 * compensation ::
1999 * The engine compensation.
2000 *
2001 * @Return:
2002 * Rounded distance.
2003 */
2004 static FT_F26Dot6
2005 Round_To_Half_Grid( TT_ExecContext exc,
2006 FT_F26Dot6 distance,
2007 FT_F26Dot6 compensation )
2008 {
2009 FT_F26Dot6 val;
2010
2011 FT_UNUSED( exc );
2012
2013
2014 if ( distance >= 0 )
2015 {
2016 val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),
2017 32 );
2018 if ( val < 0 )
2019 val = 32;
2020 }
2021 else
2022 {
2023 val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,
2024 distance ) ),
2025 32 ) );
2026 if ( val > 0 )
2027 val = -32;
2028 }
2029
2030 return val;
2031 }
2032
2033
2034 /**************************************************************************
2035 *
2036 * @Function:
2037 * Round_Down_To_Grid
2038 *
2039 * @Description:
2040 * Rounds value down to grid after adding engine compensation.
2041 *
2042 * @Input:
2043 * distance ::
2044 * The distance to round.
2045 *
2046 * compensation ::
2047 * The engine compensation.
2048 *
2049 * @Return:
2050 * Rounded distance.
2051 */
2052 static FT_F26Dot6
2053 Round_Down_To_Grid( TT_ExecContext exc,
2054 FT_F26Dot6 distance,
2055 FT_F26Dot6 compensation )
2056 {
2057 FT_F26Dot6 val;
2058
2059 FT_UNUSED( exc );
2060
2061
2062 if ( distance >= 0 )
2063 {
2064 val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );
2065 if ( val < 0 )
2066 val = 0;
2067 }
2068 else
2069 {
2070 val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );
2071 if ( val > 0 )
2072 val = 0;
2073 }
2074
2075 return val;
2076 }
2077
2078
2079 /**************************************************************************
2080 *
2081 * @Function:
2082 * Round_Up_To_Grid
2083 *
2084 * @Description:
2085 * Rounds value up to grid after adding engine compensation.
2086 *
2087 * @Input:
2088 * distance ::
2089 * The distance to round.
2090 *
2091 * compensation ::
2092 * The engine compensation.
2093 *
2094 * @Return:
2095 * Rounded distance.
2096 */
2097 static FT_F26Dot6
2098 Round_Up_To_Grid( TT_ExecContext exc,
2099 FT_F26Dot6 distance,
2100 FT_F26Dot6 compensation )
2101 {
2102 FT_F26Dot6 val;
2103
2104 FT_UNUSED( exc );
2105
2106
2107 if ( distance >= 0 )
2108 {
2109 val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );
2110 if ( val < 0 )
2111 val = 0;
2112 }
2113 else
2114 {
2115 val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,
2116 distance ) ) );
2117 if ( val > 0 )
2118 val = 0;
2119 }
2120
2121 return val;
2122 }
2123
2124
2125 /**************************************************************************
2126 *
2127 * @Function:
2128 * Round_To_Double_Grid
2129 *
2130 * @Description:
2131 * Rounds value to double grid after adding engine compensation.
2132 *
2133 * @Input:
2134 * distance ::
2135 * The distance to round.
2136 *
2137 * compensation ::
2138 * The engine compensation.
2139 *
2140 * @Return:
2141 * Rounded distance.
2142 */
2143 static FT_F26Dot6
2144 Round_To_Double_Grid( TT_ExecContext exc,
2145 FT_F26Dot6 distance,
2146 FT_F26Dot6 compensation )
2147 {
2148 FT_F26Dot6 val;
2149
2150 FT_UNUSED( exc );
2151
2152
2153 if ( distance >= 0 )
2154 {
2155 val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );
2156 if ( val < 0 )
2157 val = 0;
2158 }
2159 else
2160 {
2161 val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),
2162 32 ) );
2163 if ( val > 0 )
2164 val = 0;
2165 }
2166
2167 return val;
2168 }
2169
2170
2171 /**************************************************************************
2172 *
2173 * @Function:
2174 * Round_Super
2175 *
2176 * @Description:
2177 * Super-rounds value to grid after adding engine compensation.
2178 *
2179 * @Input:
2180 * distance ::
2181 * The distance to round.
2182 *
2183 * compensation ::
2184 * The engine compensation.
2185 *
2186 * @Return:
2187 * Rounded distance.
2188 *
2189 * @Note:
2190 * The TrueType specification says very little about the relationship
2191 * between rounding and engine compensation. However, it seems from
2192 * the description of super round that we should add the compensation
2193 * before rounding.
2194 */
2195 static FT_F26Dot6
2196 Round_Super( TT_ExecContext exc,
2197 FT_F26Dot6 distance,
2198 FT_F26Dot6 compensation )
2199 {
2200 FT_F26Dot6 val;
2201
2202
2203 if ( distance >= 0 )
2204 {
2205 val = ADD_LONG( distance,
2206 exc->threshold - exc->phase + compensation ) &
2207 -exc->period;
2208 val = ADD_LONG( val, exc->phase );
2209 if ( val < 0 )
2210 val = exc->phase;
2211 }
2212 else
2213 {
2214 val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,
2215 distance ) &
2216 -exc->period );
2217 val = SUB_LONG( val, exc->phase );
2218 if ( val > 0 )
2219 val = -exc->phase;
2220 }
2221
2222 return val;
2223 }
2224
2225
2226 /**************************************************************************
2227 *
2228 * @Function:
2229 * Round_Super_45
2230 *
2231 * @Description:
2232 * Super-rounds value to grid after adding engine compensation.
2233 *
2234 * @Input:
2235 * distance ::
2236 * The distance to round.
2237 *
2238 * compensation ::
2239 * The engine compensation.
2240 *
2241 * @Return:
2242 * Rounded distance.
2243 *
2244 * @Note:
2245 * There is a separate function for Round_Super_45() as we may need
2246 * greater precision.
2247 */
2248 static FT_F26Dot6
2249 Round_Super_45( TT_ExecContext exc,
2250 FT_F26Dot6 distance,
2251 FT_F26Dot6 compensation )
2252 {
2253 FT_F26Dot6 val;
2254
2255
2256 if ( distance >= 0 )
2257 {
2258 val = ( ADD_LONG( distance,
2259 exc->threshold - exc->phase + compensation ) /
2260 exc->period ) * exc->period;
2261 val = ADD_LONG( val, exc->phase );
2262 if ( val < 0 )
2263 val = exc->phase;
2264 }
2265 else
2266 {
2267 val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,
2268 distance ) /
2269 exc->period ) * exc->period );
2270 val = SUB_LONG( val, exc->phase );
2271 if ( val > 0 )
2272 val = -exc->phase;
2273 }
2274
2275 return val;
2276 }
2277
2278
2279 /**************************************************************************
2280 *
2281 * @Function:
2282 * Compute_Round
2283 *
2284 * @Description:
2285 * Sets the rounding mode.
2286 *
2287 * @Input:
2288 * round_mode ::
2289 * The rounding mode to be used.
2290 */
2291 static void
2292 Compute_Round( TT_ExecContext exc,
2293 FT_Byte round_mode )
2294 {
2295 switch ( round_mode )
2296 {
2297 case TT_Round_Off:
2298 exc->func_round = (TT_Round_Func)Round_None;
2299 break;
2300
2301 case TT_Round_To_Grid:
2302 exc->func_round = (TT_Round_Func)Round_To_Grid;
2303 break;
2304
2305 case TT_Round_Up_To_Grid:
2306 exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
2307 break;
2308
2309 case TT_Round_Down_To_Grid:
2310 exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
2312
2313 case TT_Round_To_Half_Grid:
2314 exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
2315 break;
2316
2317 case TT_Round_To_Double_Grid:
2318 exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
2319 break;
2320
2321 case TT_Round_Super:
2322 exc->func_round = (TT_Round_Func)Round_Super;
2323 break;
2324
2325 case TT_Round_Super_45:
2326 exc->func_round = (TT_Round_Func)Round_Super_45;
2327 break;
2328 }
2329 }
2330
2331
2332 /**************************************************************************
2333 *
2334 * @Function:
2335 * SetSuperRound
2336 *
2337 * @Description:
2338 * Sets Super Round parameters.
2339 *
2340 * @Input:
2341 * GridPeriod ::
2342 * The grid period.
2343 *
2344 * selector ::
2345 * The SROUND opcode.
2346 */
2347 static void
2348 SetSuperRound( TT_ExecContext exc,
2349 FT_F2Dot14 GridPeriod,
2350 FT_Long selector )
2351 {
2352 switch ( (FT_Int)( selector & 0xC0 ) )
2353 {
2354 case 0:
2355 exc->period = GridPeriod / 2;
2356 break;
2357
2358 case 0x40:
2359 exc->period = GridPeriod;
2360 break;
2361
2362 case 0x80:
2363 exc->period = GridPeriod * 2;
2364 break;
2365
2366 /* This opcode is reserved, but... */
2383 exc->phase = exc->period / 2;
2384 break;
2385
2386 case 0x30:
2387 exc->phase = exc->period * 3 / 4;
2388 break;
2389 }
2390
2391 if ( ( selector & 0x0F ) == 0 )
2392 exc->threshold = exc->period - 1;
2393 else
2394 exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;
2395
2396 /* convert to F26Dot6 format */
2397 exc->period >>= 8;
2398 exc->phase >>= 8;
2399 exc->threshold >>= 8;
2400 }
2401
2402
2403 /**************************************************************************
2404 *
2405 * @Function:
2406 * Project
2407 *
2408 * @Description:
2409 * Computes the projection of vector given by (v2-v1) along the
2410 * current projection vector.
2411 *
2412 * @Input:
2413 * v1 ::
2414 * First input vector.
2415 * v2 ::
2416 * Second input vector.
2417 *
2418 * @Return:
2419 * The distance in F26dot6 format.
2420 */
2421 static FT_F26Dot6
2422 Project( TT_ExecContext exc,
2423 FT_Pos dx,
2424 FT_Pos dy )
2425 {
2426 return TT_DotFix14( dx, dy,
2427 exc->GS.projVector.x,
2428 exc->GS.projVector.y );
2429 }
2430
2431
2432 /**************************************************************************
2433 *
2434 * @Function:
2435 * Dual_Project
2436 *
2437 * @Description:
2438 * Computes the projection of the vector given by (v2-v1) along the
2439 * current dual vector.
2440 *
2441 * @Input:
2442 * v1 ::
2443 * First input vector.
2444 * v2 ::
2445 * Second input vector.
2446 *
2447 * @Return:
2448 * The distance in F26dot6 format.
2449 */
2450 static FT_F26Dot6
2451 Dual_Project( TT_ExecContext exc,
2452 FT_Pos dx,
2453 FT_Pos dy )
2454 {
2455 return TT_DotFix14( dx, dy,
2456 exc->GS.dualVector.x,
2457 exc->GS.dualVector.y );
2458 }
2459
2460
2461 /**************************************************************************
2462 *
2463 * @Function:
2464 * Project_x
2465 *
2466 * @Description:
2467 * Computes the projection of the vector given by (v2-v1) along the
2468 * horizontal axis.
2469 *
2470 * @Input:
2471 * v1 ::
2472 * First input vector.
2473 * v2 ::
2474 * Second input vector.
2475 *
2476 * @Return:
2477 * The distance in F26dot6 format.
2478 */
2479 static FT_F26Dot6
2480 Project_x( TT_ExecContext exc,
2481 FT_Pos dx,
2482 FT_Pos dy )
2483 {
2484 FT_UNUSED( exc );
2485 FT_UNUSED( dy );
2486
2487 return dx;
2488 }
2489
2490
2491 /**************************************************************************
2492 *
2493 * @Function:
2494 * Project_y
2495 *
2496 * @Description:
2497 * Computes the projection of the vector given by (v2-v1) along the
2498 * vertical axis.
2499 *
2500 * @Input:
2501 * v1 ::
2502 * First input vector.
2503 * v2 ::
2504 * Second input vector.
2505 *
2506 * @Return:
2507 * The distance in F26dot6 format.
2508 */
2509 static FT_F26Dot6
2510 Project_y( TT_ExecContext exc,
2511 FT_Pos dx,
2512 FT_Pos dy )
2513 {
2514 FT_UNUSED( exc );
2515 FT_UNUSED( dx );
2516
2517 return dy;
2518 }
2519
2520
2521 /**************************************************************************
2522 *
2523 * @Function:
2524 * Compute_Funcs
2525 *
2526 * @Description:
2527 * Computes the projection and movement function pointers according
2528 * to the current graphics state.
2529 */
2530 static void
2531 Compute_Funcs( TT_ExecContext exc )
2532 {
2533 if ( exc->GS.freeVector.x == 0x4000 )
2534 exc->F_dot_P = exc->GS.projVector.x;
2535 else if ( exc->GS.freeVector.y == 0x4000 )
2536 exc->F_dot_P = exc->GS.projVector.y;
2537 else
2538 exc->F_dot_P =
2539 ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
2540 (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
2541
2542 if ( exc->GS.projVector.x == 0x4000 )
2543 exc->func_project = (TT_Project_Func)Project_x;
2544 else if ( exc->GS.projVector.y == 0x4000 )
2545 exc->func_project = (TT_Project_Func)Project_y;
2546 else
2547 exc->func_project = (TT_Project_Func)Project;
2548
2549 if ( exc->GS.dualVector.x == 0x4000 )
2564 exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2565 }
2566 else if ( exc->GS.freeVector.y == 0x4000 )
2567 {
2568 exc->func_move = (TT_Move_Func)Direct_Move_Y;
2569 exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2570 }
2571 }
2572
2573 /* at small sizes, F_dot_P can become too small, resulting */
2574 /* in overflows and `spikes' in a number of glyphs like `w'. */
2575
2576 if ( FT_ABS( exc->F_dot_P ) < 0x400L )
2577 exc->F_dot_P = 0x4000L;
2578
2579 /* Disable cached aspect ratio */
2580 exc->tt_metrics.ratio = 0;
2581 }
2582
2583
2584 /**************************************************************************
2585 *
2586 * @Function:
2587 * Normalize
2588 *
2589 * @Description:
2590 * Norms a vector.
2591 *
2592 * @Input:
2593 * Vx ::
2594 * The horizontal input vector coordinate.
2595 * Vy ::
2596 * The vertical input vector coordinate.
2597 *
2598 * @Output:
2599 * R ::
2600 * The normed unit vector.
2601 *
2602 * @Return:
2603 * Returns FAILURE if a vector parameter is zero.
2604 *
2605 * @Note:
2606 * In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and
2607 * R is undefined.
2608 */
2609 static FT_Bool
2610 Normalize( FT_F26Dot6 Vx,
2611 FT_F26Dot6 Vy,
2612 FT_UnitVector* R )
2613 {
2614 FT_Vector V;
2615
2616
2617 if ( Vx == 0 && Vy == 0 )
2618 {
2619 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2620 /* to normalize the vector (0,0). Return immediately. */
2621 return SUCCESS;
2622 }
2623
2624 V.x = Vx;
2625 V.y = Vy;
2626
2627 FT_Vector_NormLen( &V );
2628
2629 R->x = (FT_F2Dot14)( V.x / 4 );
2630 R->y = (FT_F2Dot14)( V.y / 4 );
2631
2632 return SUCCESS;
2633 }
2634
2635
2636 /**************************************************************************
2637 *
2638 * Here we start with the implementation of the various opcodes.
2639 *
2640 */
2641
2642
2643 #define ARRAY_BOUND_ERROR \
2644 do \
2645 { \
2646 exc->error = FT_THROW( Invalid_Reference ); \
2647 return; \
2648 } while (0)
2649
2650
2651 /**************************************************************************
2652 *
2653 * MPPEM[]: Measure Pixel Per EM
2654 * Opcode range: 0x4B
2655 * Stack: --> Euint16
2656 */
2657 static void
2658 Ins_MPPEM( TT_ExecContext exc,
2659 FT_Long* args )
2660 {
2661 args[0] = exc->func_cur_ppem( exc );
2662 }
2663
2664
2665 /**************************************************************************
2666 *
2667 * MPS[]: Measure Point Size
2668 * Opcode range: 0x4C
2669 * Stack: --> Euint16
2670 */
2671 static void
2672 Ins_MPS( TT_ExecContext exc,
2673 FT_Long* args )
2674 {
2675 if ( NO_SUBPIXEL_HINTING )
2676 {
2677 /* Microsoft's GDI bytecode interpreter always returns value 12; */
2678 /* we return the current PPEM value instead. */
2679 args[0] = exc->func_cur_ppem( exc );
2680 }
2681 else
2682 {
2683 /* A possible practical application of the MPS instruction is to */
2684 /* implement optical scaling and similar features, which should be */
2685 /* based on perceptual attributes, thus independent of the */
2686 /* resolution. */
2687 args[0] = exc->pointSize;
2688 }
2689 }
2690
2691
2692 /**************************************************************************
2693 *
2694 * DUP[]: DUPlicate the stack's top element
2695 * Opcode range: 0x20
2696 * Stack: StkElt --> StkElt StkElt
2697 */
2698 static void
2699 Ins_DUP( FT_Long* args )
2700 {
2701 args[1] = args[0];
2702 }
2703
2704
2705 /**************************************************************************
2706 *
2707 * POP[]: POP the stack's top element
2708 * Opcode range: 0x21
2709 * Stack: StkElt -->
2710 */
2711 static void
2712 Ins_POP( void )
2713 {
2714 /* nothing to do */
2715 }
2716
2717
2718 /**************************************************************************
2719 *
2720 * CLEAR[]: CLEAR the entire stack
2721 * Opcode range: 0x22
2722 * Stack: StkElt... -->
2723 */
2724 static void
2725 Ins_CLEAR( TT_ExecContext exc )
2726 {
2727 exc->new_top = 0;
2728 }
2729
2730
2731 /**************************************************************************
2732 *
2733 * SWAP[]: SWAP the stack's top two elements
2734 * Opcode range: 0x23
2735 * Stack: 2 * StkElt --> 2 * StkElt
2736 */
2737 static void
2738 Ins_SWAP( FT_Long* args )
2739 {
2740 FT_Long L;
2741
2742
2743 L = args[0];
2744 args[0] = args[1];
2745 args[1] = L;
2746 }
2747
2748
2749 /**************************************************************************
2750 *
2751 * DEPTH[]: return the stack DEPTH
2752 * Opcode range: 0x24
2753 * Stack: --> uint32
2754 */
2755 static void
2756 Ins_DEPTH( TT_ExecContext exc,
2757 FT_Long* args )
2758 {
2759 args[0] = exc->top;
2760 }
2761
2762
2763 /**************************************************************************
2764 *
2765 * LT[]: Less Than
2766 * Opcode range: 0x50
2767 * Stack: int32? int32? --> bool
2768 */
2769 static void
2770 Ins_LT( FT_Long* args )
2771 {
2772 args[0] = ( args[0] < args[1] );
2773 }
2774
2775
2776 /**************************************************************************
2777 *
2778 * LTEQ[]: Less Than or EQual
2779 * Opcode range: 0x51
2780 * Stack: int32? int32? --> bool
2781 */
2782 static void
2783 Ins_LTEQ( FT_Long* args )
2784 {
2785 args[0] = ( args[0] <= args[1] );
2786 }
2787
2788
2789 /**************************************************************************
2790 *
2791 * GT[]: Greater Than
2792 * Opcode range: 0x52
2793 * Stack: int32? int32? --> bool
2794 */
2795 static void
2796 Ins_GT( FT_Long* args )
2797 {
2798 args[0] = ( args[0] > args[1] );
2799 }
2800
2801
2802 /**************************************************************************
2803 *
2804 * GTEQ[]: Greater Than or EQual
2805 * Opcode range: 0x53
2806 * Stack: int32? int32? --> bool
2807 */
2808 static void
2809 Ins_GTEQ( FT_Long* args )
2810 {
2811 args[0] = ( args[0] >= args[1] );
2812 }
2813
2814
2815 /**************************************************************************
2816 *
2817 * EQ[]: EQual
2818 * Opcode range: 0x54
2819 * Stack: StkElt StkElt --> bool
2820 */
2821 static void
2822 Ins_EQ( FT_Long* args )
2823 {
2824 args[0] = ( args[0] == args[1] );
2825 }
2826
2827
2828 /**************************************************************************
2829 *
2830 * NEQ[]: Not EQual
2831 * Opcode range: 0x55
2832 * Stack: StkElt StkElt --> bool
2833 */
2834 static void
2835 Ins_NEQ( FT_Long* args )
2836 {
2837 args[0] = ( args[0] != args[1] );
2838 }
2839
2840
2841 /**************************************************************************
2842 *
2843 * ODD[]: Is ODD
2844 * Opcode range: 0x56
2845 * Stack: f26.6 --> bool
2846 */
2847 static void
2848 Ins_ODD( TT_ExecContext exc,
2849 FT_Long* args )
2850 {
2851 args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 );
2852 }
2853
2854
2855 /**************************************************************************
2856 *
2857 * EVEN[]: Is EVEN
2858 * Opcode range: 0x57
2859 * Stack: f26.6 --> bool
2860 */
2861 static void
2862 Ins_EVEN( TT_ExecContext exc,
2863 FT_Long* args )
2864 {
2865 args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 );
2866 }
2867
2868
2869 /**************************************************************************
2870 *
2871 * AND[]: logical AND
2872 * Opcode range: 0x5A
2873 * Stack: uint32 uint32 --> uint32
2874 */
2875 static void
2876 Ins_AND( FT_Long* args )
2877 {
2878 args[0] = ( args[0] && args[1] );
2879 }
2880
2881
2882 /**************************************************************************
2883 *
2884 * OR[]: logical OR
2885 * Opcode range: 0x5B
2886 * Stack: uint32 uint32 --> uint32
2887 */
2888 static void
2889 Ins_OR( FT_Long* args )
2890 {
2891 args[0] = ( args[0] || args[1] );
2892 }
2893
2894
2895 /**************************************************************************
2896 *
2897 * NOT[]: logical NOT
2898 * Opcode range: 0x5C
2899 * Stack: StkElt --> uint32
2900 */
2901 static void
2902 Ins_NOT( FT_Long* args )
2903 {
2904 args[0] = !args[0];
2905 }
2906
2907
2908 /**************************************************************************
2909 *
2910 * ADD[]: ADD
2911 * Opcode range: 0x60
2912 * Stack: f26.6 f26.6 --> f26.6
2913 */
2914 static void
2915 Ins_ADD( FT_Long* args )
2916 {
2917 args[0] = ADD_LONG( args[0], args[1] );
2918 }
2919
2920
2921 /**************************************************************************
2922 *
2923 * SUB[]: SUBtract
2924 * Opcode range: 0x61
2925 * Stack: f26.6 f26.6 --> f26.6
2926 */
2927 static void
2928 Ins_SUB( FT_Long* args )
2929 {
2930 args[0] = SUB_LONG( args[0], args[1] );
2931 }
2932
2933
2934 /**************************************************************************
2935 *
2936 * DIV[]: DIVide
2937 * Opcode range: 0x62
2938 * Stack: f26.6 f26.6 --> f26.6
2939 */
2940 static void
2941 Ins_DIV( TT_ExecContext exc,
2942 FT_Long* args )
2943 {
2944 if ( args[1] == 0 )
2945 exc->error = FT_THROW( Divide_By_Zero );
2946 else
2947 args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
2948 }
2949
2950
2951 /**************************************************************************
2952 *
2953 * MUL[]: MULtiply
2954 * Opcode range: 0x63
2955 * Stack: f26.6 f26.6 --> f26.6
2956 */
2957 static void
2958 Ins_MUL( FT_Long* args )
2959 {
2960 args[0] = FT_MulDiv( args[0], args[1], 64L );
2961 }
2962
2963
2964 /**************************************************************************
2965 *
2966 * ABS[]: ABSolute value
2967 * Opcode range: 0x64
2968 * Stack: f26.6 --> f26.6
2969 */
2970 static void
2971 Ins_ABS( FT_Long* args )
2972 {
2973 if ( args[0] < 0 )
2974 args[0] = NEG_LONG( args[0] );
2975 }
2976
2977
2978 /**************************************************************************
2979 *
2980 * NEG[]: NEGate
2981 * Opcode range: 0x65
2982 * Stack: f26.6 --> f26.6
2983 */
2984 static void
2985 Ins_NEG( FT_Long* args )
2986 {
2987 args[0] = NEG_LONG( args[0] );
2988 }
2989
2990
2991 /**************************************************************************
2992 *
2993 * FLOOR[]: FLOOR
2994 * Opcode range: 0x66
2995 * Stack: f26.6 --> f26.6
2996 */
2997 static void
2998 Ins_FLOOR( FT_Long* args )
2999 {
3000 args[0] = FT_PIX_FLOOR( args[0] );
3001 }
3002
3003
3004 /**************************************************************************
3005 *
3006 * CEILING[]: CEILING
3007 * Opcode range: 0x67
3008 * Stack: f26.6 --> f26.6
3009 */
3010 static void
3011 Ins_CEILING( FT_Long* args )
3012 {
3013 args[0] = FT_PIX_CEIL_LONG( args[0] );
3014 }
3015
3016
3017 /**************************************************************************
3018 *
3019 * RS[]: Read Store
3020 * Opcode range: 0x43
3021 * Stack: uint32 --> uint32
3022 */
3023 static void
3024 Ins_RS( TT_ExecContext exc,
3025 FT_Long* args )
3026 {
3027 FT_ULong I = (FT_ULong)args[0];
3028
3029
3030 if ( BOUNDSL( I, exc->storeSize ) )
3031 {
3032 if ( exc->pedantic_hinting )
3033 ARRAY_BOUND_ERROR;
3034 else
3035 args[0] = 0;
3036 }
3037 else
3038 {
3039 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3040 /* subpixel hinting - avoid Typeman Dstroke and */
3041 /* IStroke and Vacuform rounds */
3042 if ( SUBPIXEL_HINTING_INFINALITY &&
3043 exc->ignore_x_mode &&
3044 ( ( I == 24 &&
3045 ( exc->face->sph_found_func_flags &
3046 ( SPH_FDEF_SPACING_1 |
3047 SPH_FDEF_SPACING_2 ) ) ) ||
3048 ( I == 22 &&
3049 ( exc->sph_in_func_flags &
3050 SPH_FDEF_TYPEMAN_STROKES ) ) ||
3051 ( I == 8 &&
3052 ( exc->face->sph_found_func_flags &
3053 SPH_FDEF_VACUFORM_ROUND_1 ) &&
3054 exc->iup_called ) ) )
3055 args[0] = 0;
3056 else
3057 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3058 args[0] = exc->storage[I];
3059 }
3060 }
3061
3062
3063 /**************************************************************************
3064 *
3065 * WS[]: Write Store
3066 * Opcode range: 0x42
3067 * Stack: uint32 uint32 -->
3068 */
3069 static void
3070 Ins_WS( TT_ExecContext exc,
3071 FT_Long* args )
3072 {
3073 FT_ULong I = (FT_ULong)args[0];
3074
3075
3076 if ( BOUNDSL( I, exc->storeSize ) )
3077 {
3078 if ( exc->pedantic_hinting )
3079 ARRAY_BOUND_ERROR;
3080 }
3081 else
3082 exc->storage[I] = args[1];
3083 }
3084
3085
3086 /**************************************************************************
3087 *
3088 * WCVTP[]: Write CVT in Pixel units
3089 * Opcode range: 0x44
3090 * Stack: f26.6 uint32 -->
3091 */
3092 static void
3093 Ins_WCVTP( TT_ExecContext exc,
3094 FT_Long* args )
3095 {
3096 FT_ULong I = (FT_ULong)args[0];
3097
3098
3099 if ( BOUNDSL( I, exc->cvtSize ) )
3100 {
3101 if ( exc->pedantic_hinting )
3102 ARRAY_BOUND_ERROR;
3103 }
3104 else
3105 exc->func_write_cvt( exc, I, args[1] );
3106 }
3107
3108
3109 /**************************************************************************
3110 *
3111 * WCVTF[]: Write CVT in Funits
3112 * Opcode range: 0x70
3113 * Stack: uint32 uint32 -->
3114 */
3115 static void
3116 Ins_WCVTF( TT_ExecContext exc,
3117 FT_Long* args )
3118 {
3119 FT_ULong I = (FT_ULong)args[0];
3120
3121
3122 if ( BOUNDSL( I, exc->cvtSize ) )
3123 {
3124 if ( exc->pedantic_hinting )
3125 ARRAY_BOUND_ERROR;
3126 }
3127 else
3128 exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );
3129 }
3130
3131
3132 /**************************************************************************
3133 *
3134 * RCVT[]: Read CVT
3135 * Opcode range: 0x45
3136 * Stack: uint32 --> f26.6
3137 */
3138 static void
3139 Ins_RCVT( TT_ExecContext exc,
3140 FT_Long* args )
3141 {
3142 FT_ULong I = (FT_ULong)args[0];
3143
3144
3145 if ( BOUNDSL( I, exc->cvtSize ) )
3146 {
3147 if ( exc->pedantic_hinting )
3148 ARRAY_BOUND_ERROR;
3149 else
3150 args[0] = 0;
3151 }
3152 else
3153 args[0] = exc->func_read_cvt( exc, I );
3154 }
3155
3156
3157 /**************************************************************************
3158 *
3159 * AA[]: Adjust Angle
3160 * Opcode range: 0x7F
3161 * Stack: uint32 -->
3162 */
3163 static void
3164 Ins_AA( void )
3165 {
3166 /* intentionally no longer supported */
3167 }
3168
3169
3170 /**************************************************************************
3171 *
3172 * DEBUG[]: DEBUG. Unsupported.
3173 * Opcode range: 0x4F
3174 * Stack: uint32 -->
3175 *
3176 * Note: The original instruction pops a value from the stack.
3177 */
3178 static void
3179 Ins_DEBUG( TT_ExecContext exc )
3180 {
3181 exc->error = FT_THROW( Debug_OpCode );
3182 }
3183
3184
3185 /**************************************************************************
3186 *
3187 * ROUND[ab]: ROUND value
3188 * Opcode range: 0x68-0x6B
3189 * Stack: f26.6 --> f26.6
3190 */
3191 static void
3192 Ins_ROUND( TT_ExecContext exc,
3193 FT_Long* args )
3194 {
3195 args[0] = exc->func_round(
3196 exc,
3197 args[0],
3198 exc->tt_metrics.compensations[exc->opcode - 0x68] );
3199 }
3200
3201
3202 /**************************************************************************
3203 *
3204 * NROUND[ab]: No ROUNDing of value
3205 * Opcode range: 0x6C-0x6F
3206 * Stack: f26.6 --> f26.6
3207 */
3208 static void
3209 Ins_NROUND( TT_ExecContext exc,
3210 FT_Long* args )
3211 {
3212 args[0] = Round_None(
3213 exc,
3214 args[0],
3215 exc->tt_metrics.compensations[exc->opcode - 0x6C] );
3216 }
3217
3218
3219 /**************************************************************************
3220 *
3221 * MAX[]: MAXimum
3222 * Opcode range: 0x8B
3223 * Stack: int32? int32? --> int32
3224 */
3225 static void
3226 Ins_MAX( FT_Long* args )
3227 {
3228 if ( args[1] > args[0] )
3229 args[0] = args[1];
3230 }
3231
3232
3233 /**************************************************************************
3234 *
3235 * MIN[]: MINimum
3236 * Opcode range: 0x8C
3237 * Stack: int32? int32? --> int32
3238 */
3239 static void
3240 Ins_MIN( FT_Long* args )
3241 {
3242 if ( args[1] < args[0] )
3243 args[0] = args[1];
3244 }
3245
3246
3247 /**************************************************************************
3248 *
3249 * MINDEX[]: Move INDEXed element
3250 * Opcode range: 0x26
3251 * Stack: int32? --> StkElt
3252 */
3253 static void
3254 Ins_MINDEX( TT_ExecContext exc,
3255 FT_Long* args )
3256 {
3257 FT_Long L, K;
3258
3259
3260 L = args[0];
3261
3262 if ( L <= 0 || L > exc->args )
3263 {
3264 if ( exc->pedantic_hinting )
3265 exc->error = FT_THROW( Invalid_Reference );
3266 }
3267 else
3268 {
3269 K = exc->stack[exc->args - L];
3270
3271 FT_ARRAY_MOVE( &exc->stack[exc->args - L ],
3272 &exc->stack[exc->args - L + 1],
3273 ( L - 1 ) );
3274
3275 exc->stack[exc->args - 1] = K;
3276 }
3277 }
3278
3279
3280 /**************************************************************************
3281 *
3282 * CINDEX[]: Copy INDEXed element
3283 * Opcode range: 0x25
3284 * Stack: int32 --> StkElt
3285 */
3286 static void
3287 Ins_CINDEX( TT_ExecContext exc,
3288 FT_Long* args )
3289 {
3290 FT_Long L;
3291
3292
3293 L = args[0];
3294
3295 if ( L <= 0 || L > exc->args )
3296 {
3297 if ( exc->pedantic_hinting )
3298 exc->error = FT_THROW( Invalid_Reference );
3299 args[0] = 0;
3300 }
3301 else
3302 args[0] = exc->stack[exc->args - L];
3303 }
3304
3305
3306 /**************************************************************************
3307 *
3308 * ROLL[]: ROLL top three elements
3309 * Opcode range: 0x8A
3310 * Stack: 3 * StkElt --> 3 * StkElt
3311 */
3312 static void
3313 Ins_ROLL( FT_Long* args )
3314 {
3315 FT_Long A, B, C;
3316
3317
3318 A = args[2];
3319 B = args[1];
3320 C = args[0];
3321
3322 args[2] = C;
3323 args[1] = A;
3324 args[0] = B;
3325 }
3326
3327
3328 /**************************************************************************
3329 *
3330 * MANAGING THE FLOW OF CONTROL
3331 *
3332 */
3333
3334
3335 /**************************************************************************
3336 *
3337 * SLOOP[]: Set LOOP variable
3338 * Opcode range: 0x17
3339 * Stack: int32? -->
3340 */
3341 static void
3342 Ins_SLOOP( TT_ExecContext exc,
3343 FT_Long* args )
3344 {
3345 if ( args[0] < 0 )
3346 exc->error = FT_THROW( Bad_Argument );
3347 else
3348 {
3349 /* we heuristically limit the number of loops to 16 bits */
3350 exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0];
3351 }
3352 }
3353
3354
3355 static FT_Bool
3356 SkipCode( TT_ExecContext exc )
3357 {
3358 exc->IP += exc->length;
3359
3360 if ( exc->IP < exc->codeSize )
3362 exc->opcode = exc->code[exc->IP];
3363
3364 exc->length = opcode_length[exc->opcode];
3365 if ( exc->length < 0 )
3366 {
3367 if ( exc->IP + 1 >= exc->codeSize )
3368 goto Fail_Overflow;
3369 exc->length = 2 - exc->length * exc->code[exc->IP + 1];
3370 }
3371
3372 if ( exc->IP + exc->length <= exc->codeSize )
3373 return SUCCESS;
3374 }
3375
3376 Fail_Overflow:
3377 exc->error = FT_THROW( Code_Overflow );
3378 return FAILURE;
3379 }
3380
3381
3382 /**************************************************************************
3383 *
3384 * IF[]: IF test
3385 * Opcode range: 0x58
3386 * Stack: StkElt -->
3387 */
3388 static void
3389 Ins_IF( TT_ExecContext exc,
3390 FT_Long* args )
3391 {
3392 FT_Int nIfs;
3393 FT_Bool Out;
3394
3395
3396 if ( args[0] != 0 )
3397 return;
3398
3399 nIfs = 1;
3400 Out = 0;
3401
3402 do
3403 {
3404 if ( SkipCode( exc ) == FAILURE )
3405 return;
3406
3407 switch ( exc->opcode )
3408 {
3409 case 0x58: /* IF */
3410 nIfs++;
3411 break;
3412
3413 case 0x1B: /* ELSE */
3414 Out = FT_BOOL( nIfs == 1 );
3415 break;
3416
3417 case 0x59: /* EIF */
3418 nIfs--;
3419 Out = FT_BOOL( nIfs == 0 );
3420 break;
3421 }
3422 } while ( Out == 0 );
3423 }
3424
3425
3426 /**************************************************************************
3427 *
3428 * ELSE[]: ELSE
3429 * Opcode range: 0x1B
3430 * Stack: -->
3431 */
3432 static void
3433 Ins_ELSE( TT_ExecContext exc )
3434 {
3435 FT_Int nIfs;
3436
3437
3438 nIfs = 1;
3439
3440 do
3441 {
3442 if ( SkipCode( exc ) == FAILURE )
3443 return;
3444
3445 switch ( exc->opcode )
3446 {
3447 case 0x58: /* IF */
3448 nIfs++;
3449 break;
3450
3451 case 0x59: /* EIF */
3452 nIfs--;
3453 break;
3454 }
3455 } while ( nIfs != 0 );
3456 }
3457
3458
3459 /**************************************************************************
3460 *
3461 * EIF[]: End IF
3462 * Opcode range: 0x59
3463 * Stack: -->
3464 */
3465 static void
3466 Ins_EIF( void )
3467 {
3468 /* nothing to do */
3469 }
3470
3471
3472 /**************************************************************************
3473 *
3474 * JMPR[]: JuMP Relative
3475 * Opcode range: 0x1C
3476 * Stack: int32 -->
3477 */
3478 static void
3479 Ins_JMPR( TT_ExecContext exc,
3480 FT_Long* args )
3481 {
3482 if ( args[0] == 0 && exc->args == 0 )
3483 {
3484 exc->error = FT_THROW( Bad_Argument );
3485 return;
3486 }
3487
3488 exc->IP += args[0];
3489 if ( exc->IP < 0 ||
3490 ( exc->callTop > 0 &&
3491 exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
3492 {
3493 exc->error = FT_THROW( Bad_Argument );
3494 return;
3495 }
3496
3497 exc->step_ins = FALSE;
3498
3499 if ( args[0] < 0 )
3500 {
3501 if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
3502 exc->error = FT_THROW( Execution_Too_Long );
3503 }
3504 }
3505
3506
3507 /**************************************************************************
3508 *
3509 * JROT[]: Jump Relative On True
3510 * Opcode range: 0x78
3511 * Stack: StkElt int32 -->
3512 */
3513 static void
3514 Ins_JROT( TT_ExecContext exc,
3515 FT_Long* args )
3516 {
3517 if ( args[1] != 0 )
3518 Ins_JMPR( exc, args );
3519 }
3520
3521
3522 /**************************************************************************
3523 *
3524 * JROF[]: Jump Relative On False
3525 * Opcode range: 0x79
3526 * Stack: StkElt int32 -->
3527 */
3528 static void
3529 Ins_JROF( TT_ExecContext exc,
3530 FT_Long* args )
3531 {
3532 if ( args[1] == 0 )
3533 Ins_JMPR( exc, args );
3534 }
3535
3536
3537 /**************************************************************************
3538 *
3539 * DEFINING AND USING FUNCTIONS AND INSTRUCTIONS
3540 *
3541 */
3542
3543
3544 /**************************************************************************
3545 *
3546 * FDEF[]: Function DEFinition
3547 * Opcode range: 0x2C
3548 * Stack: uint32 -->
3549 */
3550 static void
3551 Ins_FDEF( TT_ExecContext exc,
3552 FT_Long* args )
3553 {
3554 FT_ULong n;
3555 TT_DefRecord* rec;
3556 TT_DefRecord* limit;
3557
3558 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3559 /* arguments to opcodes are skipped by `SKIP_Code' */
3560 FT_Byte opcode_pattern[9][12] = {
3561 /* #0 inline delta function 1 */
3562 {
3563 0x4B, /* PPEM */
3564 0x53, /* GTEQ */
3565 0x23, /* SWAP */
3566 0x4B, /* PPEM */
3567 0x51, /* LTEQ */
3568 0x5A, /* AND */
3569 0x58, /* IF */
3827 ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
3828 }
3829
3830 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3831
3832 switch ( exc->opcode )
3833 {
3834 case 0x89: /* IDEF */
3835 case 0x2C: /* FDEF */
3836 exc->error = FT_THROW( Nested_DEFS );
3837 return;
3838
3839 case 0x2D: /* ENDF */
3840 rec->end = exc->IP;
3841 return;
3842 }
3843 }
3844 }
3845
3846
3847 /**************************************************************************
3848 *
3849 * ENDF[]: END Function definition
3850 * Opcode range: 0x2D
3851 * Stack: -->
3852 */
3853 static void
3854 Ins_ENDF( TT_ExecContext exc )
3855 {
3856 TT_CallRec* pRec;
3857
3858
3859 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
3860 exc->sph_in_func_flags = 0x0000;
3861 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
3862
3863 if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */
3864 {
3865 exc->error = FT_THROW( ENDF_In_Exec_Stream );
3866 return;
3867 }
3868
3869 exc->callTop--;
3870
3871 pRec = &exc->callStack[exc->callTop];
3872
3876
3877 if ( pRec->Cur_Count > 0 )
3878 {
3879 exc->callTop++;
3880 exc->IP = pRec->Def->start;
3881 }
3882 else
3883 /* Loop through the current function */
3884 Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );
3885
3886 /* Exit the current call frame. */
3887
3888 /* NOTE: If the last instruction of a program is a */
3889 /* CALL or LOOPCALL, the return address is */
3890 /* always out of the code range. This is a */
3891 /* valid address, and it is why we do not test */
3892 /* the result of Ins_Goto_CodeRange() here! */
3893 }
3894
3895
3896 /**************************************************************************
3897 *
3898 * CALL[]: CALL function
3899 * Opcode range: 0x2B
3900 * Stack: uint32? -->
3901 */
3902 static void
3903 Ins_CALL( TT_ExecContext exc,
3904 FT_Long* args )
3905 {
3906 FT_ULong F;
3907 TT_CallRec* pCrec;
3908 TT_DefRecord* def;
3909
3910
3911 /* first of all, check the index */
3912
3913 F = (FT_ULong)args[0];
3914 if ( BOUNDSL( F, exc->maxFunc + 1 ) )
3915 goto Fail;
3916
3917 /* Except for some old Apple fonts, all functions in a TrueType */
3918 /* font are defined in increasing order, starting from 0. This */
3919 /* means that we normally have */
3920 /* */
3921 /* exc->maxFunc+1 == exc->numFDefs */
3965 pCrec = exc->callStack + exc->callTop;
3966
3967 pCrec->Caller_Range = exc->curRange;
3968 pCrec->Caller_IP = exc->IP + 1;
3969 pCrec->Cur_Count = 1;
3970 pCrec->Def = def;
3971
3972 exc->callTop++;
3973
3974 Ins_Goto_CodeRange( exc, def->range, def->start );
3975
3976 exc->step_ins = FALSE;
3977
3978 return;
3979
3980 Fail:
3981 exc->error = FT_THROW( Invalid_Reference );
3982 }
3983
3984
3985 /**************************************************************************
3986 *
3987 * LOOPCALL[]: LOOP and CALL function
3988 * Opcode range: 0x2A
3989 * Stack: uint32? Eint16? -->
3990 */
3991 static void
3992 Ins_LOOPCALL( TT_ExecContext exc,
3993 FT_Long* args )
3994 {
3995 FT_ULong F;
3996 TT_CallRec* pCrec;
3997 TT_DefRecord* def;
3998
3999
4000 /* first of all, check the index */
4001 F = (FT_ULong)args[1];
4002 if ( BOUNDSL( F, exc->maxFunc + 1 ) )
4003 goto Fail;
4004
4005 /* Except for some old Apple fonts, all functions in a TrueType */
4006 /* font are defined in increasing order, starting from 0. This */
4007 /* means that we normally have */
4008 /* */
4009 /* exc->maxFunc+1 == exc->numFDefs */
4010 /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */
4058 pCrec->Def = def;
4059
4060 exc->callTop++;
4061
4062 Ins_Goto_CodeRange( exc, def->range, def->start );
4063
4064 exc->step_ins = FALSE;
4065
4066 exc->loopcall_counter += (FT_ULong)args[0];
4067 if ( exc->loopcall_counter > exc->loopcall_counter_max )
4068 exc->error = FT_THROW( Execution_Too_Long );
4069 }
4070
4071 return;
4072
4073 Fail:
4074 exc->error = FT_THROW( Invalid_Reference );
4075 }
4076
4077
4078 /**************************************************************************
4079 *
4080 * IDEF[]: Instruction DEFinition
4081 * Opcode range: 0x89
4082 * Stack: Eint8 -->
4083 */
4084 static void
4085 Ins_IDEF( TT_ExecContext exc,
4086 FT_Long* args )
4087 {
4088 TT_DefRecord* def;
4089 TT_DefRecord* limit;
4090
4091
4092 /* we enable IDEF only in `prep' or `fpgm' */
4093 if ( exc->curRange == tt_coderange_glyph )
4094 {
4095 exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
4096 return;
4097 }
4098
4099 /* First of all, look for the same function in our table */
4100
4101 def = exc->IDefs;
4102 limit = def + exc->numIDefs;
4103
4133
4134 /* Now skip the whole function definition. */
4135 /* We don't allow nested IDEFs & FDEFs. */
4136
4137 while ( SkipCode( exc ) == SUCCESS )
4138 {
4139 switch ( exc->opcode )
4140 {
4141 case 0x89: /* IDEF */
4142 case 0x2C: /* FDEF */
4143 exc->error = FT_THROW( Nested_DEFS );
4144 return;
4145 case 0x2D: /* ENDF */
4146 def->end = exc->IP;
4147 return;
4148 }
4149 }
4150 }
4151
4152
4153 /**************************************************************************
4154 *
4155 * PUSHING DATA ONTO THE INTERPRETER STACK
4156 *
4157 */
4158
4159
4160 /**************************************************************************
4161 *
4162 * NPUSHB[]: PUSH N Bytes
4163 * Opcode range: 0x40
4164 * Stack: --> uint32...
4165 */
4166 static void
4167 Ins_NPUSHB( TT_ExecContext exc,
4168 FT_Long* args )
4169 {
4170 FT_UShort L, K;
4171
4172
4173 L = (FT_UShort)exc->code[exc->IP + 1];
4174
4175 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4176 {
4177 exc->error = FT_THROW( Stack_Overflow );
4178 return;
4179 }
4180
4181 for ( K = 1; K <= L; K++ )
4182 args[K - 1] = exc->code[exc->IP + K + 1];
4183
4184 exc->new_top += L;
4185 }
4186
4187
4188 /**************************************************************************
4189 *
4190 * NPUSHW[]: PUSH N Words
4191 * Opcode range: 0x41
4192 * Stack: --> int32...
4193 */
4194 static void
4195 Ins_NPUSHW( TT_ExecContext exc,
4196 FT_Long* args )
4197 {
4198 FT_UShort L, K;
4199
4200
4201 L = (FT_UShort)exc->code[exc->IP + 1];
4202
4203 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4204 {
4205 exc->error = FT_THROW( Stack_Overflow );
4206 return;
4207 }
4208
4209 exc->IP += 2;
4210
4211 for ( K = 0; K < L; K++ )
4212 args[K] = GetShortIns( exc );
4213
4214 exc->step_ins = FALSE;
4215 exc->new_top += L;
4216 }
4217
4218
4219 /**************************************************************************
4220 *
4221 * PUSHB[abc]: PUSH Bytes
4222 * Opcode range: 0xB0-0xB7
4223 * Stack: --> uint32...
4224 */
4225 static void
4226 Ins_PUSHB( TT_ExecContext exc,
4227 FT_Long* args )
4228 {
4229 FT_UShort L, K;
4230
4231
4232 L = (FT_UShort)( exc->opcode - 0xB0 + 1 );
4233
4234 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4235 {
4236 exc->error = FT_THROW( Stack_Overflow );
4237 return;
4238 }
4239
4240 for ( K = 1; K <= L; K++ )
4241 args[K - 1] = exc->code[exc->IP + K];
4242 }
4243
4244
4245 /**************************************************************************
4246 *
4247 * PUSHW[abc]: PUSH Words
4248 * Opcode range: 0xB8-0xBF
4249 * Stack: --> int32...
4250 */
4251 static void
4252 Ins_PUSHW( TT_ExecContext exc,
4253 FT_Long* args )
4254 {
4255 FT_UShort L, K;
4256
4257
4258 L = (FT_UShort)( exc->opcode - 0xB8 + 1 );
4259
4260 if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
4261 {
4262 exc->error = FT_THROW( Stack_Overflow );
4263 return;
4264 }
4265
4266 exc->IP++;
4267
4268 for ( K = 0; K < L; K++ )
4269 args[K] = GetShortIns( exc );
4270
4271 exc->step_ins = FALSE;
4272 }
4273
4274
4275 /**************************************************************************
4276 *
4277 * MANAGING THE GRAPHICS STATE
4278 *
4279 */
4280
4281
4282 static FT_Bool
4283 Ins_SxVTL( TT_ExecContext exc,
4284 FT_UShort aIdx1,
4285 FT_UShort aIdx2,
4286 FT_UnitVector* Vec )
4287 {
4288 FT_Long A, B, C;
4289 FT_Vector* p1;
4290 FT_Vector* p2;
4291
4292 FT_Byte opcode = exc->opcode;
4293
4294
4295 if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
4296 BOUNDS( aIdx2, exc->zp1.n_points ) )
4297 {
4298 if ( exc->pedantic_hinting )
4299 exc->error = FT_THROW( Invalid_Reference );
4313
4314 if ( A == 0 && B == 0 )
4315 {
4316 A = 0x4000;
4317 opcode = 0;
4318 }
4319
4320 if ( ( opcode & 1 ) != 0 )
4321 {
4322 C = B; /* counter clockwise rotation */
4323 B = A;
4324 A = NEG_LONG( C );
4325 }
4326
4327 Normalize( A, B, Vec );
4328
4329 return SUCCESS;
4330 }
4331
4332
4333 /**************************************************************************
4334 *
4335 * SVTCA[a]: Set (F and P) Vectors to Coordinate Axis
4336 * Opcode range: 0x00-0x01
4337 * Stack: -->
4338 *
4339 * SPvTCA[a]: Set PVector to Coordinate Axis
4340 * Opcode range: 0x02-0x03
4341 * Stack: -->
4342 *
4343 * SFvTCA[a]: Set FVector to Coordinate Axis
4344 * Opcode range: 0x04-0x05
4345 * Stack: -->
4346 */
4347 static void
4348 Ins_SxyTCA( TT_ExecContext exc )
4349 {
4350 FT_Short AA, BB;
4351
4352 FT_Byte opcode = exc->opcode;
4353
4354
4355 AA = (FT_Short)( ( opcode & 1 ) << 14 );
4356 BB = (FT_Short)( AA ^ 0x4000 );
4357
4358 if ( opcode < 4 )
4359 {
4360 exc->GS.projVector.x = AA;
4361 exc->GS.projVector.y = BB;
4362
4363 exc->GS.dualVector.x = AA;
4364 exc->GS.dualVector.y = BB;
4365 }
4366
4367 if ( ( opcode & 2 ) == 0 )
4368 {
4369 exc->GS.freeVector.x = AA;
4370 exc->GS.freeVector.y = BB;
4371 }
4372
4373 Compute_Funcs( exc );
4374 }
4375
4376
4377 /**************************************************************************
4378 *
4379 * SPvTL[a]: Set PVector To Line
4380 * Opcode range: 0x06-0x07
4381 * Stack: uint32 uint32 -->
4382 */
4383 static void
4384 Ins_SPVTL( TT_ExecContext exc,
4385 FT_Long* args )
4386 {
4387 if ( Ins_SxVTL( exc,
4388 (FT_UShort)args[1],
4389 (FT_UShort)args[0],
4390 &exc->GS.projVector ) == SUCCESS )
4391 {
4392 exc->GS.dualVector = exc->GS.projVector;
4393 Compute_Funcs( exc );
4394 }
4395 }
4396
4397
4398 /**************************************************************************
4399 *
4400 * SFvTL[a]: Set FVector To Line
4401 * Opcode range: 0x08-0x09
4402 * Stack: uint32 uint32 -->
4403 */
4404 static void
4405 Ins_SFVTL( TT_ExecContext exc,
4406 FT_Long* args )
4407 {
4408 if ( Ins_SxVTL( exc,
4409 (FT_UShort)args[1],
4410 (FT_UShort)args[0],
4411 &exc->GS.freeVector ) == SUCCESS )
4412 {
4413 Compute_Funcs( exc );
4414 }
4415 }
4416
4417
4418 /**************************************************************************
4419 *
4420 * SFvTPv[]: Set FVector To PVector
4421 * Opcode range: 0x0E
4422 * Stack: -->
4423 */
4424 static void
4425 Ins_SFVTPV( TT_ExecContext exc )
4426 {
4427 exc->GS.freeVector = exc->GS.projVector;
4428 Compute_Funcs( exc );
4429 }
4430
4431
4432 /**************************************************************************
4433 *
4434 * SPvFS[]: Set PVector From Stack
4435 * Opcode range: 0x0A
4436 * Stack: f2.14 f2.14 -->
4437 */
4438 static void
4439 Ins_SPVFS( TT_ExecContext exc,
4440 FT_Long* args )
4441 {
4442 FT_Short S;
4443 FT_Long X, Y;
4444
4445
4446 /* Only use low 16bits, then sign extend */
4447 S = (FT_Short)args[1];
4448 Y = (FT_Long)S;
4449 S = (FT_Short)args[0];
4450 X = (FT_Long)S;
4451
4452 Normalize( X, Y, &exc->GS.projVector );
4453
4454 exc->GS.dualVector = exc->GS.projVector;
4455 Compute_Funcs( exc );
4456 }
4457
4458
4459 /**************************************************************************
4460 *
4461 * SFvFS[]: Set FVector From Stack
4462 * Opcode range: 0x0B
4463 * Stack: f2.14 f2.14 -->
4464 */
4465 static void
4466 Ins_SFVFS( TT_ExecContext exc,
4467 FT_Long* args )
4468 {
4469 FT_Short S;
4470 FT_Long X, Y;
4471
4472
4473 /* Only use low 16bits, then sign extend */
4474 S = (FT_Short)args[1];
4475 Y = (FT_Long)S;
4476 S = (FT_Short)args[0];
4477 X = S;
4478
4479 Normalize( X, Y, &exc->GS.freeVector );
4480 Compute_Funcs( exc );
4481 }
4482
4483
4484 /**************************************************************************
4485 *
4486 * GPv[]: Get Projection Vector
4487 * Opcode range: 0x0C
4488 * Stack: ef2.14 --> ef2.14
4489 */
4490 static void
4491 Ins_GPV( TT_ExecContext exc,
4492 FT_Long* args )
4493 {
4494 args[0] = exc->GS.projVector.x;
4495 args[1] = exc->GS.projVector.y;
4496 }
4497
4498
4499 /**************************************************************************
4500 *
4501 * GFv[]: Get Freedom Vector
4502 * Opcode range: 0x0D
4503 * Stack: ef2.14 --> ef2.14
4504 */
4505 static void
4506 Ins_GFV( TT_ExecContext exc,
4507 FT_Long* args )
4508 {
4509 args[0] = exc->GS.freeVector.x;
4510 args[1] = exc->GS.freeVector.y;
4511 }
4512
4513
4514 /**************************************************************************
4515 *
4516 * SRP0[]: Set Reference Point 0
4517 * Opcode range: 0x10
4518 * Stack: uint32 -->
4519 */
4520 static void
4521 Ins_SRP0( TT_ExecContext exc,
4522 FT_Long* args )
4523 {
4524 exc->GS.rp0 = (FT_UShort)args[0];
4525 }
4526
4527
4528 /**************************************************************************
4529 *
4530 * SRP1[]: Set Reference Point 1
4531 * Opcode range: 0x11
4532 * Stack: uint32 -->
4533 */
4534 static void
4535 Ins_SRP1( TT_ExecContext exc,
4536 FT_Long* args )
4537 {
4538 exc->GS.rp1 = (FT_UShort)args[0];
4539 }
4540
4541
4542 /**************************************************************************
4543 *
4544 * SRP2[]: Set Reference Point 2
4545 * Opcode range: 0x12
4546 * Stack: uint32 -->
4547 */
4548 static void
4549 Ins_SRP2( TT_ExecContext exc,
4550 FT_Long* args )
4551 {
4552 exc->GS.rp2 = (FT_UShort)args[0];
4553 }
4554
4555
4556 /**************************************************************************
4557 *
4558 * SMD[]: Set Minimum Distance
4559 * Opcode range: 0x1A
4560 * Stack: f26.6 -->
4561 */
4562 static void
4563 Ins_SMD( TT_ExecContext exc,
4564 FT_Long* args )
4565 {
4566 exc->GS.minimum_distance = args[0];
4567 }
4568
4569
4570 /**************************************************************************
4571 *
4572 * SCVTCI[]: Set Control Value Table Cut In
4573 * Opcode range: 0x1D
4574 * Stack: f26.6 -->
4575 */
4576 static void
4577 Ins_SCVTCI( TT_ExecContext exc,
4578 FT_Long* args )
4579 {
4580 exc->GS.control_value_cutin = (FT_F26Dot6)args[0];
4581 }
4582
4583
4584 /**************************************************************************
4585 *
4586 * SSWCI[]: Set Single Width Cut In
4587 * Opcode range: 0x1E
4588 * Stack: f26.6 -->
4589 */
4590 static void
4591 Ins_SSWCI( TT_ExecContext exc,
4592 FT_Long* args )
4593 {
4594 exc->GS.single_width_cutin = (FT_F26Dot6)args[0];
4595 }
4596
4597
4598 /**************************************************************************
4599 *
4600 * SSW[]: Set Single Width
4601 * Opcode range: 0x1F
4602 * Stack: int32? -->
4603 */
4604 static void
4605 Ins_SSW( TT_ExecContext exc,
4606 FT_Long* args )
4607 {
4608 exc->GS.single_width_value = FT_MulFix( args[0],
4609 exc->tt_metrics.scale );
4610 }
4611
4612
4613 /**************************************************************************
4614 *
4615 * FLIPON[]: Set auto-FLIP to ON
4616 * Opcode range: 0x4D
4617 * Stack: -->
4618 */
4619 static void
4620 Ins_FLIPON( TT_ExecContext exc )
4621 {
4622 exc->GS.auto_flip = TRUE;
4623 }
4624
4625
4626 /**************************************************************************
4627 *
4628 * FLIPOFF[]: Set auto-FLIP to OFF
4629 * Opcode range: 0x4E
4630 * Stack: -->
4631 */
4632 static void
4633 Ins_FLIPOFF( TT_ExecContext exc )
4634 {
4635 exc->GS.auto_flip = FALSE;
4636 }
4637
4638
4639 /**************************************************************************
4640 *
4641 * SANGW[]: Set ANGle Weight
4642 * Opcode range: 0x7E
4643 * Stack: uint32 -->
4644 */
4645 static void
4646 Ins_SANGW( void )
4647 {
4648 /* instruction not supported anymore */
4649 }
4650
4651
4652 /**************************************************************************
4653 *
4654 * SDB[]: Set Delta Base
4655 * Opcode range: 0x5E
4656 * Stack: uint32 -->
4657 */
4658 static void
4659 Ins_SDB( TT_ExecContext exc,
4660 FT_Long* args )
4661 {
4662 exc->GS.delta_base = (FT_UShort)args[0];
4663 }
4664
4665
4666 /**************************************************************************
4667 *
4668 * SDS[]: Set Delta Shift
4669 * Opcode range: 0x5F
4670 * Stack: uint32 -->
4671 */
4672 static void
4673 Ins_SDS( TT_ExecContext exc,
4674 FT_Long* args )
4675 {
4676 if ( (FT_ULong)args[0] > 6UL )
4677 exc->error = FT_THROW( Bad_Argument );
4678 else
4679 exc->GS.delta_shift = (FT_UShort)args[0];
4680 }
4681
4682
4683 /**************************************************************************
4684 *
4685 * RTHG[]: Round To Half Grid
4686 * Opcode range: 0x19
4687 * Stack: -->
4688 */
4689 static void
4690 Ins_RTHG( TT_ExecContext exc )
4691 {
4692 exc->GS.round_state = TT_Round_To_Half_Grid;
4693 exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
4694 }
4695
4696
4697 /**************************************************************************
4698 *
4699 * RTG[]: Round To Grid
4700 * Opcode range: 0x18
4701 * Stack: -->
4702 */
4703 static void
4704 Ins_RTG( TT_ExecContext exc )
4705 {
4706 exc->GS.round_state = TT_Round_To_Grid;
4707 exc->func_round = (TT_Round_Func)Round_To_Grid;
4708 }
4709
4710
4711 /**************************************************************************
4712 * RTDG[]: Round To Double Grid
4713 * Opcode range: 0x3D
4714 * Stack: -->
4715 */
4716 static void
4717 Ins_RTDG( TT_ExecContext exc )
4718 {
4719 exc->GS.round_state = TT_Round_To_Double_Grid;
4720 exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
4721 }
4722
4723
4724 /**************************************************************************
4725 * RUTG[]: Round Up To Grid
4726 * Opcode range: 0x7C
4727 * Stack: -->
4728 */
4729 static void
4730 Ins_RUTG( TT_ExecContext exc )
4731 {
4732 exc->GS.round_state = TT_Round_Up_To_Grid;
4733 exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
4734 }
4735
4736
4737 /**************************************************************************
4738 *
4739 * RDTG[]: Round Down To Grid
4740 * Opcode range: 0x7D
4741 * Stack: -->
4742 */
4743 static void
4744 Ins_RDTG( TT_ExecContext exc )
4745 {
4746 exc->GS.round_state = TT_Round_Down_To_Grid;
4747 exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
4748 }
4749
4750
4751 /**************************************************************************
4752 *
4753 * ROFF[]: Round OFF
4754 * Opcode range: 0x7A
4755 * Stack: -->
4756 */
4757 static void
4758 Ins_ROFF( TT_ExecContext exc )
4759 {
4760 exc->GS.round_state = TT_Round_Off;
4761 exc->func_round = (TT_Round_Func)Round_None;
4762 }
4763
4764
4765 /**************************************************************************
4766 *
4767 * SROUND[]: Super ROUND
4768 * Opcode range: 0x76
4769 * Stack: Eint8 -->
4770 */
4771 static void
4772 Ins_SROUND( TT_ExecContext exc,
4773 FT_Long* args )
4774 {
4775 SetSuperRound( exc, 0x4000, args[0] );
4776
4777 exc->GS.round_state = TT_Round_Super;
4778 exc->func_round = (TT_Round_Func)Round_Super;
4779 }
4780
4781
4782 /**************************************************************************
4783 *
4784 * S45ROUND[]: Super ROUND 45 degrees
4785 * Opcode range: 0x77
4786 * Stack: uint32 -->
4787 */
4788 static void
4789 Ins_S45ROUND( TT_ExecContext exc,
4790 FT_Long* args )
4791 {
4792 SetSuperRound( exc, 0x2D41, args[0] );
4793
4794 exc->GS.round_state = TT_Round_Super_45;
4795 exc->func_round = (TT_Round_Func)Round_Super_45;
4796 }
4797
4798
4799 /**************************************************************************
4800 *
4801 * GC[a]: Get Coordinate projected onto
4802 * Opcode range: 0x46-0x47
4803 * Stack: uint32 --> f26.6
4804 *
4805 * XXX: UNDOCUMENTED: Measures from the original glyph must be taken
4806 * along the dual projection vector!
4807 */
4808 static void
4809 Ins_GC( TT_ExecContext exc,
4810 FT_Long* args )
4811 {
4812 FT_ULong L;
4813 FT_F26Dot6 R;
4814
4815
4816 L = (FT_ULong)args[0];
4817
4818 if ( BOUNDSL( L, exc->zp2.n_points ) )
4819 {
4820 if ( exc->pedantic_hinting )
4821 exc->error = FT_THROW( Invalid_Reference );
4822 R = 0;
4823 }
4824 else
4825 {
4826 if ( exc->opcode & 1 )
4827 R = FAST_DUALPROJ( &exc->zp2.org[L] );
4828 else
4829 R = FAST_PROJECT( &exc->zp2.cur[L] );
4830 }
4831
4832 args[0] = R;
4833 }
4834
4835
4836 /**************************************************************************
4837 *
4838 * SCFS[]: Set Coordinate From Stack
4839 * Opcode range: 0x48
4840 * Stack: f26.6 uint32 -->
4841 *
4842 * Formula:
4843 *
4844 * OA := OA + ( value - OA.p )/( f.p ) * f
4845 */
4846 static void
4847 Ins_SCFS( TT_ExecContext exc,
4848 FT_Long* args )
4849 {
4850 FT_Long K;
4851 FT_UShort L;
4852
4853
4854 L = (FT_UShort)args[0];
4855
4856 if ( BOUNDS( L, exc->zp2.n_points ) )
4857 {
4858 if ( exc->pedantic_hinting )
4859 exc->error = FT_THROW( Invalid_Reference );
4860 return;
4861 }
4862
4863 K = FAST_PROJECT( &exc->zp2.cur[L] );
4864
4865 exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );
4866
4867 /* UNDOCUMENTED! The MS rasterizer does that with */
4868 /* twilight points (confirmed by Greg Hitchcock) */
4869 if ( exc->GS.gep2 == 0 )
4870 exc->zp2.org[L] = exc->zp2.cur[L];
4871 }
4872
4873
4874 /**************************************************************************
4875 *
4876 * MD[a]: Measure Distance
4877 * Opcode range: 0x49-0x4A
4878 * Stack: uint32 uint32 --> f26.6
4879 *
4880 * XXX: UNDOCUMENTED: Measure taken in the original glyph must be along
4881 * the dual projection vector.
4882 *
4883 * XXX: UNDOCUMENTED: Flag attributes are inverted!
4884 * 0 => measure distance in original outline
4885 * 1 => measure distance in grid-fitted outline
4886 *
4887 * XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1!
4888 */
4889 static void
4890 Ins_MD( TT_ExecContext exc,
4891 FT_Long* args )
4892 {
4893 FT_UShort K, L;
4894 FT_F26Dot6 D;
4895
4896
4897 K = (FT_UShort)args[1];
4898 L = (FT_UShort)args[0];
4899
4900 if ( BOUNDS( L, exc->zp0.n_points ) ||
4901 BOUNDS( K, exc->zp1.n_points ) )
4902 {
4903 if ( exc->pedantic_hinting )
4904 exc->error = FT_THROW( Invalid_Reference );
4905 D = 0;
4906 }
4907 else
4908 {
4941 vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );
4942
4943 D = FAST_DUALPROJ( &vec );
4944 }
4945 }
4946 }
4947 }
4948
4949 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
4950 /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
4951 if ( SUBPIXEL_HINTING_INFINALITY &&
4952 exc->ignore_x_mode &&
4953 FT_ABS( D ) == 64 )
4954 D += 1;
4955 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
4956
4957 args[0] = D;
4958 }
4959
4960
4961 /**************************************************************************
4962 *
4963 * SDPvTL[a]: Set Dual PVector to Line
4964 * Opcode range: 0x86-0x87
4965 * Stack: uint32 uint32 -->
4966 */
4967 static void
4968 Ins_SDPVTL( TT_ExecContext exc,
4969 FT_Long* args )
4970 {
4971 FT_Long A, B, C;
4972 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4973
4974 FT_Byte opcode = exc->opcode;
4975
4976
4977 p1 = (FT_UShort)args[1];
4978 p2 = (FT_UShort)args[0];
4979
4980 if ( BOUNDS( p2, exc->zp1.n_points ) ||
4981 BOUNDS( p1, exc->zp2.n_points ) )
4982 {
4983 if ( exc->pedantic_hinting )
4984 exc->error = FT_THROW( Invalid_Reference );
4985 return;
4986 }
5024
5025 if ( A == 0 && B == 0 )
5026 {
5027 A = 0x4000;
5028 opcode = 0;
5029 }
5030 }
5031
5032 if ( ( opcode & 1 ) != 0 )
5033 {
5034 C = B; /* counter clockwise rotation */
5035 B = A;
5036 A = NEG_LONG( C );
5037 }
5038
5039 Normalize( A, B, &exc->GS.projVector );
5040 Compute_Funcs( exc );
5041 }
5042
5043
5044 /**************************************************************************
5045 *
5046 * SZP0[]: Set Zone Pointer 0
5047 * Opcode range: 0x13
5048 * Stack: uint32 -->
5049 */
5050 static void
5051 Ins_SZP0( TT_ExecContext exc,
5052 FT_Long* args )
5053 {
5054 switch ( (FT_Int)args[0] )
5055 {
5056 case 0:
5057 exc->zp0 = exc->twilight;
5058 break;
5059
5060 case 1:
5061 exc->zp0 = exc->pts;
5062 break;
5063
5064 default:
5065 if ( exc->pedantic_hinting )
5066 exc->error = FT_THROW( Invalid_Reference );
5067 return;
5068 }
5069
5070 exc->GS.gep0 = (FT_UShort)args[0];
5071 }
5072
5073
5074 /**************************************************************************
5075 *
5076 * SZP1[]: Set Zone Pointer 1
5077 * Opcode range: 0x14
5078 * Stack: uint32 -->
5079 */
5080 static void
5081 Ins_SZP1( TT_ExecContext exc,
5082 FT_Long* args )
5083 {
5084 switch ( (FT_Int)args[0] )
5085 {
5086 case 0:
5087 exc->zp1 = exc->twilight;
5088 break;
5089
5090 case 1:
5091 exc->zp1 = exc->pts;
5092 break;
5093
5094 default:
5095 if ( exc->pedantic_hinting )
5096 exc->error = FT_THROW( Invalid_Reference );
5097 return;
5098 }
5099
5100 exc->GS.gep1 = (FT_UShort)args[0];
5101 }
5102
5103
5104 /**************************************************************************
5105 *
5106 * SZP2[]: Set Zone Pointer 2
5107 * Opcode range: 0x15
5108 * Stack: uint32 -->
5109 */
5110 static void
5111 Ins_SZP2( TT_ExecContext exc,
5112 FT_Long* args )
5113 {
5114 switch ( (FT_Int)args[0] )
5115 {
5116 case 0:
5117 exc->zp2 = exc->twilight;
5118 break;
5119
5120 case 1:
5121 exc->zp2 = exc->pts;
5122 break;
5123
5124 default:
5125 if ( exc->pedantic_hinting )
5126 exc->error = FT_THROW( Invalid_Reference );
5127 return;
5128 }
5129
5130 exc->GS.gep2 = (FT_UShort)args[0];
5131 }
5132
5133
5134 /**************************************************************************
5135 *
5136 * SZPS[]: Set Zone PointerS
5137 * Opcode range: 0x16
5138 * Stack: uint32 -->
5139 */
5140 static void
5141 Ins_SZPS( TT_ExecContext exc,
5142 FT_Long* args )
5143 {
5144 switch ( (FT_Int)args[0] )
5145 {
5146 case 0:
5147 exc->zp0 = exc->twilight;
5148 break;
5149
5150 case 1:
5151 exc->zp0 = exc->pts;
5152 break;
5153
5154 default:
5155 if ( exc->pedantic_hinting )
5156 exc->error = FT_THROW( Invalid_Reference );
5157 return;
5158 }
5159
5160 exc->zp1 = exc->zp0;
5161 exc->zp2 = exc->zp0;
5162
5163 exc->GS.gep0 = (FT_UShort)args[0];
5164 exc->GS.gep1 = (FT_UShort)args[0];
5165 exc->GS.gep2 = (FT_UShort)args[0];
5166 }
5167
5168
5169 /**************************************************************************
5170 *
5171 * INSTCTRL[]: INSTruction ConTRoL
5172 * Opcode range: 0x8E
5173 * Stack: int32 int32 -->
5174 */
5175 static void
5176 Ins_INSTCTRL( TT_ExecContext exc,
5177 FT_Long* args )
5178 {
5179 FT_ULong K, L, Kf;
5180
5181
5182 K = (FT_ULong)args[1];
5183 L = (FT_ULong)args[0];
5184
5185 /* selector values cannot be `OR'ed; */
5186 /* they are indices starting with index 1, not flags */
5187 if ( K < 1 || K > 3 )
5188 {
5189 if ( exc->pedantic_hinting )
5190 exc->error = FT_THROW( Invalid_Reference );
5191 return;
5192 }
5193
5194 /* convert index to flag value */
5211 if ( K == 3 )
5212 {
5213 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5214 /* INSTCTRL modifying flag 3 also has an effect */
5215 /* outside of the CVT program */
5216 if ( SUBPIXEL_HINTING_INFINALITY )
5217 exc->ignore_x_mode = FT_BOOL( L == 4 );
5218 #endif
5219
5220 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5221 /* Native ClearType fonts sign a waiver that turns off all backward */
5222 /* compatibility hacks and lets them program points to the grid like */
5223 /* it's 1996. They might sign a waiver for just one glyph, though. */
5224 if ( SUBPIXEL_HINTING_MINIMAL )
5225 exc->backward_compatibility = !FT_BOOL( L == 4 );
5226 #endif
5227 }
5228 }
5229
5230
5231 /**************************************************************************
5232 *
5233 * SCANCTRL[]: SCAN ConTRoL
5234 * Opcode range: 0x85
5235 * Stack: uint32? -->
5236 */
5237 static void
5238 Ins_SCANCTRL( TT_ExecContext exc,
5239 FT_Long* args )
5240 {
5241 FT_Int A;
5242
5243
5244 /* Get Threshold */
5245 A = (FT_Int)( args[0] & 0xFF );
5246
5247 if ( A == 0xFF )
5248 {
5249 exc->GS.scan_control = TRUE;
5250 return;
5251 }
5252 else if ( A == 0 )
5253 {
5254 exc->GS.scan_control = FALSE;
5255 return;
5256 }
5258 if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )
5259 exc->GS.scan_control = TRUE;
5260
5261 if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )
5262 exc->GS.scan_control = TRUE;
5263
5264 if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )
5265 exc->GS.scan_control = TRUE;
5266
5267 if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )
5268 exc->GS.scan_control = FALSE;
5269
5270 if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )
5271 exc->GS.scan_control = FALSE;
5272
5273 if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )
5274 exc->GS.scan_control = FALSE;
5275 }
5276
5277
5278 /**************************************************************************
5279 *
5280 * SCANTYPE[]: SCAN TYPE
5281 * Opcode range: 0x8D
5282 * Stack: uint16 -->
5283 */
5284 static void
5285 Ins_SCANTYPE( TT_ExecContext exc,
5286 FT_Long* args )
5287 {
5288 if ( args[0] >= 0 )
5289 exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;
5290 }
5291
5292
5293 /**************************************************************************
5294 *
5295 * MANAGING OUTLINES
5296 *
5297 */
5298
5299
5300 /**************************************************************************
5301 *
5302 * FLIPPT[]: FLIP PoinT
5303 * Opcode range: 0x80
5304 * Stack: uint32... -->
5305 */
5306 static void
5307 Ins_FLIPPT( TT_ExecContext exc )
5308 {
5309 FT_UShort point;
5310
5311
5312 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5313 /* See `ttinterp.h' for details on backward compatibility mode. */
5314 if ( SUBPIXEL_HINTING_MINIMAL &&
5315 exc->backward_compatibility &&
5316 exc->iupx_called &&
5317 exc->iupy_called )
5318 goto Fail;
5319 #endif
5320
5321 if ( exc->top < exc->GS.loop )
5322 {
5323 if ( exc->pedantic_hinting )
5324 exc->error = FT_THROW( Too_Few_Arguments );
5325 goto Fail;
5334 if ( BOUNDS( point, exc->pts.n_points ) )
5335 {
5336 if ( exc->pedantic_hinting )
5337 {
5338 exc->error = FT_THROW( Invalid_Reference );
5339 return;
5340 }
5341 }
5342 else
5343 exc->pts.tags[point] ^= FT_CURVE_TAG_ON;
5344
5345 exc->GS.loop--;
5346 }
5347
5348 Fail:
5349 exc->GS.loop = 1;
5350 exc->new_top = exc->args;
5351 }
5352
5353
5354 /**************************************************************************
5355 *
5356 * FLIPRGON[]: FLIP RanGe ON
5357 * Opcode range: 0x81
5358 * Stack: uint32 uint32 -->
5359 */
5360 static void
5361 Ins_FLIPRGON( TT_ExecContext exc,
5362 FT_Long* args )
5363 {
5364 FT_UShort I, K, L;
5365
5366
5367 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5368 /* See `ttinterp.h' for details on backward compatibility mode. */
5369 if ( SUBPIXEL_HINTING_MINIMAL &&
5370 exc->backward_compatibility &&
5371 exc->iupx_called &&
5372 exc->iupy_called )
5373 return;
5374 #endif
5375
5376 K = (FT_UShort)args[1];
5377 L = (FT_UShort)args[0];
5378
5379 if ( BOUNDS( K, exc->pts.n_points ) ||
5380 BOUNDS( L, exc->pts.n_points ) )
5381 {
5382 if ( exc->pedantic_hinting )
5383 exc->error = FT_THROW( Invalid_Reference );
5384 return;
5385 }
5386
5387 for ( I = L; I <= K; I++ )
5388 exc->pts.tags[I] |= FT_CURVE_TAG_ON;
5389 }
5390
5391
5392 /**************************************************************************
5393 *
5394 * FLIPRGOFF: FLIP RanGe OFF
5395 * Opcode range: 0x82
5396 * Stack: uint32 uint32 -->
5397 */
5398 static void
5399 Ins_FLIPRGOFF( TT_ExecContext exc,
5400 FT_Long* args )
5401 {
5402 FT_UShort I, K, L;
5403
5404
5405 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5406 /* See `ttinterp.h' for details on backward compatibility mode. */
5407 if ( SUBPIXEL_HINTING_MINIMAL &&
5408 exc->backward_compatibility &&
5409 exc->iupx_called &&
5410 exc->iupy_called )
5411 return;
5412 #endif
5413
5414 K = (FT_UShort)args[1];
5415 L = (FT_UShort)args[0];
5416
5417 if ( BOUNDS( K, exc->pts.n_points ) ||
5489 if ( touch )
5490 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5491 }
5492
5493 if ( exc->GS.freeVector.y != 0 )
5494 {
5495 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5496 if ( !( SUBPIXEL_HINTING_MINIMAL &&
5497 exc->backward_compatibility &&
5498 exc->iupx_called &&
5499 exc->iupy_called ) )
5500 #endif
5501 exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );
5502
5503 if ( touch )
5504 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5505 }
5506 }
5507
5508
5509 /**************************************************************************
5510 *
5511 * SHP[a]: SHift Point by the last point
5512 * Opcode range: 0x32-0x33
5513 * Stack: uint32... -->
5514 */
5515 static void
5516 Ins_SHP( TT_ExecContext exc )
5517 {
5518 TT_GlyphZoneRec zp;
5519 FT_UShort refp;
5520
5521 FT_F26Dot6 dx, dy;
5522 FT_UShort point;
5523
5524
5525 if ( exc->top < exc->GS.loop )
5526 {
5527 if ( exc->pedantic_hinting )
5528 exc->error = FT_THROW( Invalid_Reference );
5529 goto Fail;
5530 }
5531
5532 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5533 return;
5534
5546 }
5547 }
5548 else
5549 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5550 /* doesn't follow Cleartype spec but produces better result */
5551 if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
5552 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5553 else
5554 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5555 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5556
5557 exc->GS.loop--;
5558 }
5559
5560 Fail:
5561 exc->GS.loop = 1;
5562 exc->new_top = exc->args;
5563 }
5564
5565
5566 /**************************************************************************
5567 *
5568 * SHC[a]: SHift Contour
5569 * Opcode range: 0x34-35
5570 * Stack: uint32 -->
5571 *
5572 * UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual)
5573 * contour in the twilight zone, namely contour number
5574 * zero which includes all points of it.
5575 */
5576 static void
5577 Ins_SHC( TT_ExecContext exc,
5578 FT_Long* args )
5579 {
5580 TT_GlyphZoneRec zp;
5581 FT_UShort refp;
5582 FT_F26Dot6 dx, dy;
5583
5584 FT_Short contour, bounds;
5585 FT_UShort start, limit, i;
5586
5587
5588 contour = (FT_Short)args[0];
5589 bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
5590
5591 if ( BOUNDS( contour, bounds ) )
5592 {
5593 if ( exc->pedantic_hinting )
5594 exc->error = FT_THROW( Invalid_Reference );
5595 return;
5602 start = 0;
5603 else
5604 start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
5605 exc->zp2.first_point );
5606
5607 /* we use the number of points if in the twilight zone */
5608 if ( exc->GS.gep2 == 0 )
5609 limit = exc->zp2.n_points;
5610 else
5611 limit = (FT_UShort)( exc->zp2.contours[contour] -
5612 exc->zp2.first_point + 1 );
5613
5614 for ( i = start; i < limit; i++ )
5615 {
5616 if ( zp.cur != exc->zp2.cur || refp != i )
5617 Move_Zp2_Point( exc, i, dx, dy, TRUE );
5618 }
5619 }
5620
5621
5622 /**************************************************************************
5623 *
5624 * SHZ[a]: SHift Zone
5625 * Opcode range: 0x36-37
5626 * Stack: uint32 -->
5627 */
5628 static void
5629 Ins_SHZ( TT_ExecContext exc,
5630 FT_Long* args )
5631 {
5632 TT_GlyphZoneRec zp;
5633 FT_UShort refp;
5634 FT_F26Dot6 dx,
5635 dy;
5636
5637 FT_UShort limit, i;
5638
5639
5640 if ( BOUNDS( args[0], 2 ) )
5641 {
5642 if ( exc->pedantic_hinting )
5643 exc->error = FT_THROW( Invalid_Reference );
5644 return;
5645 }
5646
5647 if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
5650 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5651 /* Twilight zone has no real contours, so use `n_points'. */
5652 /* Normal zone's `n_points' includes phantoms, so must */
5653 /* use end of last contour. */
5654 if ( exc->GS.gep2 == 0 )
5655 limit = (FT_UShort)exc->zp2.n_points;
5656 else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
5657 limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
5658 else
5659 limit = 0;
5660
5661 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5662 for ( i = 0; i < limit; i++ )
5663 {
5664 if ( zp.cur != exc->zp2.cur || refp != i )
5665 Move_Zp2_Point( exc, i, dx, dy, FALSE );
5666 }
5667 }
5668
5669
5670 /**************************************************************************
5671 *
5672 * SHPIX[]: SHift points by a PIXel amount
5673 * Opcode range: 0x38
5674 * Stack: f26.6 uint32... -->
5675 */
5676 static void
5677 Ins_SHPIX( TT_ExecContext exc,
5678 FT_Long* args )
5679 {
5680 FT_F26Dot6 dx, dy;
5681 FT_UShort point;
5682 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5683 FT_Int B1, B2;
5684 #endif
5685 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
5686 FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||
5687 exc->GS.gep1 == 0 ||
5688 exc->GS.gep2 == 0 );
5689 #endif
5690
5691
5692
5693 if ( exc->top < exc->GS.loop + 1 )
5694 {
5695 if ( exc->pedantic_hinting )
5810 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
5811 ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) )
5812 Move_Zp2_Point( exc, point, 0, dy, TRUE );
5813 }
5814 else
5815 #endif
5816 Move_Zp2_Point( exc, point, dx, dy, TRUE );
5817
5818 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5819 Skip:
5820 #endif
5821 exc->GS.loop--;
5822 }
5823
5824 Fail:
5825 exc->GS.loop = 1;
5826 exc->new_top = exc->args;
5827 }
5828
5829
5830 /**************************************************************************
5831 *
5832 * MSIRP[a]: Move Stack Indirect Relative Position
5833 * Opcode range: 0x3A-0x3B
5834 * Stack: f26.6 uint32 -->
5835 */
5836 static void
5837 Ins_MSIRP( TT_ExecContext exc,
5838 FT_Long* args )
5839 {
5840 FT_UShort point = 0;
5841 FT_F26Dot6 distance;
5842 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5843 FT_F26Dot6 control_value_cutin = 0;
5844 FT_F26Dot6 delta;
5845
5846
5847 if ( SUBPIXEL_HINTING_INFINALITY )
5848 {
5849 control_value_cutin = exc->GS.control_value_cutin;
5850
5851 if ( exc->ignore_x_mode &&
5852 exc->GS.freeVector.x != 0 &&
5853 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
5854 control_value_cutin = 0;
5855 }
5885 if ( SUBPIXEL_HINTING_INFINALITY &&
5886 exc->ignore_x_mode &&
5887 exc->GS.freeVector.x != 0 &&
5888 delta >= control_value_cutin )
5889 distance = args[1];
5890 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
5891
5892 exc->func_move( exc,
5893 &exc->zp1,
5894 point,
5895 SUB_LONG( args[1], distance ) );
5896
5897 exc->GS.rp1 = exc->GS.rp0;
5898 exc->GS.rp2 = point;
5899
5900 if ( ( exc->opcode & 1 ) != 0 )
5901 exc->GS.rp0 = point;
5902 }
5903
5904
5905 /**************************************************************************
5906 *
5907 * MDAP[a]: Move Direct Absolute Point
5908 * Opcode range: 0x2E-0x2F
5909 * Stack: uint32 -->
5910 */
5911 static void
5912 Ins_MDAP( TT_ExecContext exc,
5913 FT_Long* args )
5914 {
5915 FT_UShort point;
5916 FT_F26Dot6 cur_dist;
5917 FT_F26Dot6 distance;
5918
5919
5920 point = (FT_UShort)args[0];
5921
5922 if ( BOUNDS( point, exc->zp0.n_points ) )
5923 {
5924 if ( exc->pedantic_hinting )
5925 exc->error = FT_THROW( Invalid_Reference );
5926 return;
5927 }
5928
5929 if ( ( exc->opcode & 1 ) != 0 )
5930 {
5939 exc->tt_metrics.compensations[0] ),
5940 cur_dist );
5941 else
5942 #endif
5943 distance = SUB_LONG(
5944 exc->func_round( exc,
5945 cur_dist,
5946 exc->tt_metrics.compensations[0] ),
5947 cur_dist );
5948 }
5949 else
5950 distance = 0;
5951
5952 exc->func_move( exc, &exc->zp0, point, distance );
5953
5954 exc->GS.rp0 = point;
5955 exc->GS.rp1 = point;
5956 }
5957
5958
5959 /**************************************************************************
5960 *
5961 * MIAP[a]: Move Indirect Absolute Point
5962 * Opcode range: 0x3E-0x3F
5963 * Stack: uint32 uint32 -->
5964 */
5965 static void
5966 Ins_MIAP( TT_ExecContext exc,
5967 FT_Long* args )
5968 {
5969 FT_ULong cvtEntry;
5970 FT_UShort point;
5971 FT_F26Dot6 distance;
5972 FT_F26Dot6 org_dist;
5973 FT_F26Dot6 control_value_cutin;
5974
5975
5976 control_value_cutin = exc->GS.control_value_cutin;
5977 cvtEntry = (FT_ULong)args[1];
5978 point = (FT_UShort)args[0];
5979
5980 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
5981 if ( SUBPIXEL_HINTING_INFINALITY &&
5982 exc->ignore_x_mode &&
5983 exc->GS.freeVector.x != 0 &&
5984 exc->GS.freeVector.y == 0 &&
6059 exc->ignore_x_mode &&
6060 exc->GS.freeVector.x != 0 )
6061 distance = Round_None( exc,
6062 distance,
6063 exc->tt_metrics.compensations[0] );
6064 else
6065 #endif
6066 distance = exc->func_round( exc,
6067 distance,
6068 exc->tt_metrics.compensations[0] );
6069 }
6070
6071 exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
6072
6073 Fail:
6074 exc->GS.rp0 = point;
6075 exc->GS.rp1 = point;
6076 }
6077
6078
6079 /**************************************************************************
6080 *
6081 * MDRP[abcde]: Move Direct Relative Point
6082 * Opcode range: 0xC0-0xDF
6083 * Stack: uint32 -->
6084 */
6085 static void
6086 Ins_MDRP( TT_ExecContext exc,
6087 FT_Long* args )
6088 {
6089 FT_UShort point = 0;
6090 FT_F26Dot6 org_dist, distance, minimum_distance;
6091
6092
6093 minimum_distance = exc->GS.minimum_distance;
6094
6095 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6096 if ( SUBPIXEL_HINTING_INFINALITY &&
6097 exc->ignore_x_mode &&
6098 exc->GS.freeVector.x != 0 &&
6099 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6100 minimum_distance = 0;
6101 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6102
6103 point = (FT_UShort)args[0];
6104
6203 if ( distance > NEG_LONG( minimum_distance ) )
6204 distance = NEG_LONG( minimum_distance );
6205 }
6206 }
6207
6208 /* now move the point */
6209
6210 org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
6211
6212 exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );
6213
6214 Fail:
6215 exc->GS.rp1 = exc->GS.rp0;
6216 exc->GS.rp2 = point;
6217
6218 if ( ( exc->opcode & 16 ) != 0 )
6219 exc->GS.rp0 = point;
6220 }
6221
6222
6223 /**************************************************************************
6224 *
6225 * MIRP[abcde]: Move Indirect Relative Point
6226 * Opcode range: 0xE0-0xFF
6227 * Stack: int32? uint32 -->
6228 */
6229 static void
6230 Ins_MIRP( TT_ExecContext exc,
6231 FT_Long* args )
6232 {
6233 FT_UShort point;
6234 FT_ULong cvtEntry;
6235
6236 FT_F26Dot6 cvt_dist,
6237 distance,
6238 cur_dist,
6239 org_dist,
6240 control_value_cutin,
6241 minimum_distance;
6242 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6243 FT_Int B1 = 0; /* pacify compiler */
6244 FT_Int B2 = 0;
6245 FT_Bool reverse_move = FALSE;
6246 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6247
6248 FT_F26Dot6 delta;
6249
6250
6251 minimum_distance = exc->GS.minimum_distance;
6252 control_value_cutin = exc->GS.control_value_cutin;
6253 point = (FT_UShort)args[0];
6254 cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) );
6255
6256 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6257 if ( SUBPIXEL_HINTING_INFINALITY &&
6258 exc->ignore_x_mode &&
6259 exc->GS.freeVector.x != 0 &&
6260 !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6261 control_value_cutin = minimum_distance = 0;
6262 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6263
6264 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6265
6266 if ( BOUNDS( point, exc->zp1.n_points ) ||
6267 BOUNDSL( cvtEntry, exc->cvtSize + 1 ) ||
6268 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6269 {
6270 if ( exc->pedantic_hinting )
6271 exc->error = FT_THROW( Invalid_Reference );
6272 goto Fail;
6273 }
6274
6275 if ( !cvtEntry )
6276 cvt_dist = 0;
6277 else
6278 cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );
6279
6280 /* single width test */
6281
6282 delta = SUB_LONG( cvt_dist, exc->GS.single_width_value );
6283 if ( delta < 0 )
6284 delta = NEG_LONG( delta );
6285
6286 if ( delta < exc->GS.single_width_cutin )
6287 {
6288 if ( cvt_dist >= 0 )
6289 cvt_dist = exc->GS.single_width_value;
6290 else
6291 cvt_dist = -exc->GS.single_width_value;
6292 }
6293
6294 /* UNDOCUMENTED! The MS rasterizer does that with */
6295 /* twilight points (confirmed by Greg Hitchcock) */
6296 if ( exc->GS.gep1 == 0 )
6297 {
6298 exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x +
6299 TT_MulFix14( cvt_dist,
6300 exc->GS.freeVector.x );
6301 exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y +
6302 TT_MulFix14( cvt_dist,
6303 exc->GS.freeVector.y );
6304 exc->zp1.cur[point] = exc->zp1.org[point];
6305 }
6306
6307 org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );
6308 cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );
6309
6310 /* auto-flip test */
6311
6312 if ( exc->GS.auto_flip )
6313 {
6314 if ( ( org_dist ^ cvt_dist ) < 0 )
6315 cvt_dist = NEG_LONG( cvt_dist );
6316 }
6317
6318 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6319 if ( SUBPIXEL_HINTING_INFINALITY &&
6320 exc->ignore_x_mode &&
6321 exc->GS.freeVector.y != 0 &&
6322 ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6323 {
6324 if ( cur_dist < -64 )
6325 cvt_dist -= 16;
6326 else if ( cur_dist > 64 && cur_dist < 84 )
6327 cvt_dist += 32;
6328 }
6329 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6330
6331 /* control value cut-in and round */
6332
6333 if ( ( exc->opcode & 4 ) != 0 )
6334 {
6335 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6336 /* refer to the same zone. */
6337
6338 if ( exc->GS.gep0 == exc->GS.gep1 )
6339 {
6340 /* XXX: According to Greg Hitchcock, the following wording is */
6341 /* the right one: */
6342 /* */
6343 /* When the absolute difference between the value in */
6344 /* the table [CVT] and the measurement directly from */
6345 /* the outline is _greater_ than the cut_in value, the */
6346 /* outline measurement is used. */
6347 /* */
6348 /* This is from `instgly.doc'. The description in */
6349 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6350 /* it implies `>=' instead of `>'. */
6351
6352 delta = SUB_LONG( cvt_dist, org_dist );
6353 if ( delta < 0 )
6354 delta = NEG_LONG( delta );
6355
6356 if ( delta > control_value_cutin )
6357 cvt_dist = org_dist;
6358 }
6359
6360 distance = exc->func_round(
6361 exc,
6362 cvt_dist,
6363 exc->tt_metrics.compensations[exc->opcode & 3] );
6364 }
6365 else
6366 {
6367
6368 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6369 /* do cvt cut-in always in MIRP for sph */
6370 if ( SUBPIXEL_HINTING_INFINALITY &&
6371 exc->ignore_x_mode &&
6372 exc->GS.gep0 == exc->GS.gep1 )
6373 {
6374 delta = SUB_LONG( cvt_dist, org_dist );
6375 if ( delta < 0 )
6376 delta = NEG_LONG( delta );
6377
6378 if ( delta > control_value_cutin )
6379 cvt_dist = org_dist;
6380 }
6381 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6382
6383 distance = Round_None(
6384 exc,
6385 cvt_dist,
6386 exc->tt_metrics.compensations[exc->opcode & 3] );
6387 }
6388
6389 /* minimum distance test */
6390
6391 if ( ( exc->opcode & 8 ) != 0 )
6392 {
6393 if ( org_dist >= 0 )
6450
6451 if ( reverse_move )
6452 exc->func_move( exc,
6453 &exc->zp1,
6454 point,
6455 SUB_LONG( cur_dist, distance ) );
6456 }
6457
6458 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6459
6460 Fail:
6461 exc->GS.rp1 = exc->GS.rp0;
6462
6463 if ( ( exc->opcode & 16 ) != 0 )
6464 exc->GS.rp0 = point;
6465
6466 exc->GS.rp2 = point;
6467 }
6468
6469
6470 /**************************************************************************
6471 *
6472 * ALIGNRP[]: ALIGN Relative Point
6473 * Opcode range: 0x3C
6474 * Stack: uint32 uint32... -->
6475 */
6476 static void
6477 Ins_ALIGNRP( TT_ExecContext exc )
6478 {
6479 FT_UShort point;
6480 FT_F26Dot6 distance;
6481
6482
6483 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
6484 if ( SUBPIXEL_HINTING_INFINALITY &&
6485 exc->ignore_x_mode &&
6486 exc->iup_called &&
6487 ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6488 {
6489 exc->error = FT_THROW( Invalid_Reference );
6490 goto Fail;
6491 }
6492 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
6493
6494 if ( exc->top < exc->GS.loop ||
6495 BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
6513 return;
6514 }
6515 }
6516 else
6517 {
6518 distance = PROJECT( exc->zp1.cur + point,
6519 exc->zp0.cur + exc->GS.rp0 );
6520
6521 exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
6522 }
6523
6524 exc->GS.loop--;
6525 }
6526
6527 Fail:
6528 exc->GS.loop = 1;
6529 exc->new_top = exc->args;
6530 }
6531
6532
6533 /**************************************************************************
6534 *
6535 * ISECT[]: moves point to InterSECTion
6536 * Opcode range: 0x0F
6537 * Stack: 5 * uint32 -->
6538 */
6539 static void
6540 Ins_ISECT( TT_ExecContext exc,
6541 FT_Long* args )
6542 {
6543 FT_UShort point,
6544 a0, a1,
6545 b0, b1;
6546
6547 FT_F26Dot6 discriminant, dotproduct;
6548
6549 FT_F26Dot6 dx, dy,
6550 dax, day,
6551 dbx, dby;
6552
6553 FT_F26Dot6 val;
6554
6555 FT_Vector R;
6556
6557
6558 point = (FT_UShort)args[0];
6609 exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );
6610 exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );
6611 }
6612 else
6613 {
6614 /* else, take the middle of the middles of A and B */
6615
6616 /* XXX: Block in backward_compatibility and/or post-IUP? */
6617 exc->zp2.cur[point].x =
6618 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),
6619 ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;
6620 exc->zp2.cur[point].y =
6621 ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),
6622 ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;
6623 }
6624
6625 exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6626 }
6627
6628
6629 /**************************************************************************
6630 *
6631 * ALIGNPTS[]: ALIGN PoinTS
6632 * Opcode range: 0x27
6633 * Stack: uint32 uint32 -->
6634 */
6635 static void
6636 Ins_ALIGNPTS( TT_ExecContext exc,
6637 FT_Long* args )
6638 {
6639 FT_UShort p1, p2;
6640 FT_F26Dot6 distance;
6641
6642
6643 p1 = (FT_UShort)args[0];
6644 p2 = (FT_UShort)args[1];
6645
6646 if ( BOUNDS( p1, exc->zp1.n_points ) ||
6647 BOUNDS( p2, exc->zp0.n_points ) )
6648 {
6649 if ( exc->pedantic_hinting )
6650 exc->error = FT_THROW( Invalid_Reference );
6651 return;
6652 }
6653
6654 distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;
6655
6656 exc->func_move( exc, &exc->zp1, p1, distance );
6657 exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );
6658 }
6659
6660
6661 /**************************************************************************
6662 *
6663 * IP[]: Interpolate Point
6664 * Opcode range: 0x39
6665 * Stack: uint32... -->
6666 */
6667
6668 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6669
6670 static void
6671 Ins_IP( TT_ExecContext exc )
6672 {
6673 FT_F26Dot6 old_range, cur_range;
6674 FT_Vector* orus_base;
6675 FT_Vector* cur_base;
6676 FT_Int twilight;
6677
6678
6679 if ( exc->top < exc->GS.loop )
6680 {
6681 if ( exc->pedantic_hinting )
6682 exc->error = FT_THROW( Invalid_Reference );
6683 goto Fail;
6684 }
6685
6686 /*
6801 /* new_dist = org_dist . */
6802
6803 new_dist = org_dist;
6804 }
6805 }
6806 else
6807 new_dist = 0;
6808
6809 exc->func_move( exc,
6810 &exc->zp2,
6811 (FT_UShort)point,
6812 SUB_LONG( new_dist, cur_dist ) );
6813 }
6814
6815 Fail:
6816 exc->GS.loop = 1;
6817 exc->new_top = exc->args;
6818 }
6819
6820
6821 /**************************************************************************
6822 *
6823 * UTP[a]: UnTouch Point
6824 * Opcode range: 0x29
6825 * Stack: uint32 -->
6826 */
6827 static void
6828 Ins_UTP( TT_ExecContext exc,
6829 FT_Long* args )
6830 {
6831 FT_UShort point;
6832 FT_Byte mask;
6833
6834
6835 point = (FT_UShort)args[0];
6836
6837 if ( BOUNDS( point, exc->zp0.n_points ) )
6838 {
6839 if ( exc->pedantic_hinting )
6840 exc->error = FT_THROW( Invalid_Reference );
6841 return;
6842 }
6843
6844 mask = 0xFF;
6845
6846 if ( exc->GS.freeVector.x != 0 )
6970
6971 else
6972 {
6973 if ( !scale_valid )
6974 {
6975 scale_valid = 1;
6976 scale = FT_DivFix( SUB_LONG( cur2, cur1 ),
6977 SUB_LONG( orus2, orus1 ) );
6978 }
6979
6980 x = ADD_LONG( cur1,
6981 FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),
6982 scale ) );
6983 }
6984 worker->curs[i].x = x;
6985 }
6986 }
6987 }
6988
6989
6990 /**************************************************************************
6991 *
6992 * IUP[a]: Interpolate Untouched Points
6993 * Opcode range: 0x30-0x31
6994 * Stack: -->
6995 */
6996 static void
6997 Ins_IUP( TT_ExecContext exc )
6998 {
6999 IUP_WorkerRec V;
7000 FT_Byte mask;
7001
7002 FT_UInt first_point; /* first point of contour */
7003 FT_UInt end_point; /* end point (last+1) of contour */
7004
7005 FT_UInt first_touched; /* first touched point in contour */
7006 FT_UInt cur_touched; /* current touched point in contour */
7007
7008 FT_UInt point; /* current point */
7009 FT_Short contour; /* current contour */
7010
7011
7012 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7013 /* See `ttinterp.h' for details on backward compatibility mode. */
7014 /* Allow IUP until it has been called on both axes. Immediately */
7015 /* return on subsequent ones. */
7098 {
7099 _iup_worker_interpolate( &V,
7100 (FT_UShort)( cur_touched + 1 ),
7101 end_point,
7102 cur_touched,
7103 first_touched );
7104
7105 if ( first_touched > 0 )
7106 _iup_worker_interpolate( &V,
7107 first_point,
7108 first_touched - 1,
7109 cur_touched,
7110 first_touched );
7111 }
7112 }
7113 contour++;
7114 } while ( contour < exc->pts.n_contours );
7115 }
7116
7117
7118 /**************************************************************************
7119 *
7120 * DELTAPn[]: DELTA exceptions P1, P2, P3
7121 * Opcode range: 0x5D,0x71,0x72
7122 * Stack: uint32 (2 * uint32)... -->
7123 */
7124 static void
7125 Ins_DELTAP( TT_ExecContext exc,
7126 FT_Long* args )
7127 {
7128 FT_ULong nump, k;
7129 FT_UShort A;
7130 FT_ULong C, P;
7131 FT_Long B;
7132 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7133 FT_UShort B1, B2;
7134
7135
7136 if ( SUBPIXEL_HINTING_INFINALITY &&
7137 exc->ignore_x_mode &&
7138 exc->iup_called &&
7139 ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7140 goto Fail;
7141 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7142
7143 P = (FT_ULong)exc->func_cur_ppem( exc );
7265 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
7266 ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )
7267 exc->func_move( exc, &exc->zp0, A, B );
7268 }
7269 else
7270 #endif
7271 exc->func_move( exc, &exc->zp0, A, B );
7272 }
7273 }
7274 }
7275 else
7276 if ( exc->pedantic_hinting )
7277 exc->error = FT_THROW( Invalid_Reference );
7278 }
7279
7280 Fail:
7281 exc->new_top = exc->args;
7282 }
7283
7284
7285 /**************************************************************************
7286 *
7287 * DELTACn[]: DELTA exceptions C1, C2, C3
7288 * Opcode range: 0x73,0x74,0x75
7289 * Stack: uint32 (2 * uint32)... -->
7290 */
7291 static void
7292 Ins_DELTAC( TT_ExecContext exc,
7293 FT_Long* args )
7294 {
7295 FT_ULong nump, k;
7296 FT_ULong A, C, P;
7297 FT_Long B;
7298
7299
7300 P = (FT_ULong)exc->func_cur_ppem( exc );
7301 nump = (FT_ULong)args[0];
7302
7303 for ( k = 1; k <= nump; k++ )
7304 {
7305 if ( exc->args < 2 )
7306 {
7307 if ( exc->pedantic_hinting )
7308 exc->error = FT_THROW( Too_Few_Arguments );
7309 exc->args = 0;
7310 goto Fail;
7343
7344 C += exc->GS.delta_base;
7345
7346 if ( P == C )
7347 {
7348 B = ( (FT_ULong)B & 0xF ) - 8;
7349 if ( B >= 0 )
7350 B++;
7351 B *= 1L << ( 6 - exc->GS.delta_shift );
7352
7353 exc->func_move_cvt( exc, A, B );
7354 }
7355 }
7356 }
7357
7358 Fail:
7359 exc->new_top = exc->args;
7360 }
7361
7362
7363 /**************************************************************************
7364 *
7365 * MISC. INSTRUCTIONS
7366 *
7367 */
7368
7369
7370 /**************************************************************************
7371 *
7372 * GETINFO[]: GET INFOrmation
7373 * Opcode range: 0x88
7374 * Stack: uint32 --> uint32
7375 *
7376 * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May
7377 * 2015) not documented in the OpenType specification.
7378 *
7379 * Selector bit 11 is incorrectly described as bit 8, while the
7380 * real meaning of bit 8 (vertical LCD subpixels) stays
7381 * undocumented. The same mistake can be found in Greg Hitchcock's
7382 * whitepaper.
7383 */
7384 static void
7385 Ins_GETINFO( TT_ExecContext exc,
7386 FT_Long* args )
7387 {
7388 FT_Long K;
7389 TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face );
7390
7391
7392 K = 0;
7393
7394 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7395 /*********************************
7396 * RASTERIZER VERSION
7397 * Selector Bit: 0
7398 * Return Bit(s): 0-7
7399 */
7400 if ( SUBPIXEL_HINTING_INFINALITY &&
7401 ( args[0] & 1 ) != 0 &&
7402 exc->subpixel_hinting )
7403 {
7404 if ( exc->ignore_x_mode )
7405 {
7406 /* if in ClearType backward compatibility mode, */
7407 /* we sometimes change the TrueType version dynamically */
7408 K = exc->rasterizer_version;
7409 FT_TRACE6(( "Setting rasterizer version %d\n",
7410 exc->rasterizer_version ));
7411 }
7412 else
7413 K = TT_INTERPRETER_VERSION_38;
7414 }
7415 else
7416 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7417 if ( ( args[0] & 1 ) != 0 )
7418 K = driver->interpreter_version;
7419
7420 /*********************************
7421 * GLYPH ROTATED
7422 * Selector Bit: 1
7423 * Return Bit(s): 8
7424 */
7425 if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )
7426 K |= 1 << 8;
7427
7428 /*********************************
7429 * GLYPH STRETCHED
7430 * Selector Bit: 2
7431 * Return Bit(s): 9
7432 */
7433 if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )
7434 K |= 1 << 9;
7435
7436 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7437 /*********************************
7438 * VARIATION GLYPH
7439 * Selector Bit: 3
7440 * Return Bit(s): 10
7441 *
7442 * XXX: UNDOCUMENTED!
7443 */
7444 if ( (args[0] & 8 ) != 0 && exc->face->blend )
7445 K |= 1 << 10;
7446 #endif
7447
7448 /*********************************
7449 * BI-LEVEL HINTING AND
7450 * GRAYSCALE RENDERING
7451 * Selector Bit: 5
7452 * Return Bit(s): 12
7453 */
7454 if ( ( args[0] & 32 ) != 0 && exc->grayscale )
7455 K |= 1 << 12;
7456
7457 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
7458 /* Toggle the following flags only outside of monochrome mode. */
7459 /* Otherwise, instructions may behave weirdly and rendering results */
7460 /* may differ between v35 and v40 mode, e.g., in `Times New Roman */
7461 /* Bold Italic'. */
7462 if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
7463 {
7464 /*********************************
7465 * HINTING FOR SUBPIXEL
7466 * Selector Bit: 6
7467 * Return Bit(s): 13
7468 *
7469 * v40 does subpixel hinting by default.
7470 */
7471 if ( ( args[0] & 64 ) != 0 )
7472 K |= 1 << 13;
7473
7474 /*********************************
7475 * VERTICAL LCD SUBPIXELS?
7476 * Selector Bit: 8
7477 * Return Bit(s): 15
7478 */
7479 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
7480 K |= 1 << 15;
7481
7482 /*********************************
7483 * SUBPIXEL POSITIONED?
7484 * Selector Bit: 10
7485 * Return Bit(s): 17
7486 *
7487 * XXX: FreeType supports it, dependent on what client does?
7488 */
7489 if ( ( args[0] & 1024 ) != 0 )
7490 K |= 1 << 17;
7491
7492 /*********************************
7493 * SYMMETRICAL SMOOTHING
7494 * Selector Bit: 11
7495 * Return Bit(s): 18
7496 *
7497 * The only smoothing method FreeType supports unless someone sets
7498 * FT_LOAD_TARGET_MONO.
7499 */
7500 if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
7501 K |= 1 << 18;
7502
7503 /*********************************
7504 * CLEARTYPE HINTING AND
7505 * GRAYSCALE RENDERING
7506 * Selector Bit: 12
7507 * Return Bit(s): 19
7508 *
7509 * Grayscale rendering is what FreeType does anyway unless someone
7510 * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V)
7511 */
7512 if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
7513 K |= 1 << 19;
7514 }
7515 #endif
7516
7517 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7518
7519 if ( SUBPIXEL_HINTING_INFINALITY &&
7520 exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7521 {
7522
7523 if ( exc->rasterizer_version >= 37 )
7524 {
7525 /*********************************
7526 * HINTING FOR SUBPIXEL
7527 * Selector Bit: 6
7528 * Return Bit(s): 13
7529 */
7530 if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
7531 K |= 1 << 13;
7532
7533 /*********************************
7534 * COMPATIBLE WIDTHS ENABLED
7535 * Selector Bit: 7
7536 * Return Bit(s): 14
7537 *
7538 * Functionality still needs to be added
7539 */
7540 if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
7541 K |= 1 << 14;
7542
7543 /*********************************
7544 * VERTICAL LCD SUBPIXELS?
7545 * Selector Bit: 8
7546 * Return Bit(s): 15
7547 *
7548 * Functionality still needs to be added
7549 */
7550 if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
7551 K |= 1 << 15;
7552
7553 /*********************************
7554 * HINTING FOR BGR?
7555 * Selector Bit: 9
7556 * Return Bit(s): 16
7557 *
7558 * Functionality still needs to be added
7559 */
7560 if ( ( args[0] & 512 ) != 0 && exc->bgr )
7561 K |= 1 << 16;
7562
7563 if ( exc->rasterizer_version >= 38 )
7564 {
7565 /*********************************
7566 * SUBPIXEL POSITIONED?
7567 * Selector Bit: 10
7568 * Return Bit(s): 17
7569 *
7570 * Functionality still needs to be added
7571 */
7572 if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
7573 K |= 1 << 17;
7574
7575 /*********************************
7576 * SYMMETRICAL SMOOTHING
7577 * Selector Bit: 11
7578 * Return Bit(s): 18
7579 *
7580 * Functionality still needs to be added
7581 */
7582 if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
7583 K |= 1 << 18;
7584
7585 /*********************************
7586 * GRAY CLEARTYPE
7587 * Selector Bit: 12
7588 * Return Bit(s): 19
7589 *
7590 * Functionality still needs to be added
7591 */
7592 if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
7593 K |= 1 << 19;
7594 }
7595 }
7596 }
7597
7598 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
7599
7600 args[0] = K;
7601 }
7602
7603
7604 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
7605
7606 /**************************************************************************
7607 *
7608 * GETVARIATION[]: get normalized variation (blend) coordinates
7609 * Opcode range: 0x91
7610 * Stack: --> f2.14...
7611 *
7612 * XXX: UNDOCUMENTED! There is no official documentation from Apple for
7613 * this bytecode instruction. Active only if a font has GX
7614 * variation axes.
7615 */
7616 static void
7617 Ins_GETVARIATION( TT_ExecContext exc,
7618 FT_Long* args )
7619 {
7620 FT_UInt num_axes = exc->face->blend->num_axis;
7621 FT_Fixed* coords = exc->face->blend->normalizedcoords;
7622
7623 FT_UInt i;
7624
7625
7626 if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) )
7627 {
7628 exc->error = FT_THROW( Stack_Overflow );
7629 return;
7630 }
7631
7632 if ( coords )
7633 {
7634 for ( i = 0; i < num_axes; i++ )
7635 args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
7636 }
7637 else
7638 {
7639 for ( i = 0; i < num_axes; i++ )
7640 args[i] = 0;
7641 }
7642 }
7643
7644
7645 /**************************************************************************
7646 *
7647 * GETDATA[]: no idea what this is good for
7648 * Opcode range: 0x92
7649 * Stack: --> 17
7650 *
7651 * XXX: UNDOCUMENTED! There is no documentation from Apple for this
7652 * very weird bytecode instruction.
7653 */
7654 static void
7655 Ins_GETDATA( FT_Long* args )
7656 {
7657 args[0] = 17;
7658 }
7659
7660 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
7661
7662
7663 static void
7664 Ins_UNKNOWN( TT_ExecContext exc )
7665 {
7666 TT_DefRecord* def = exc->IDefs;
7667 TT_DefRecord* limit = def + exc->numIDefs;
7668
7669
7670 for ( ; def < limit; def++ )
7671 {
7672 if ( (FT_Byte)def->opc == exc->opcode && def->active )
7673 {
7681 }
7682
7683 call = exc->callStack + exc->callTop++;
7684
7685 call->Caller_Range = exc->curRange;
7686 call->Caller_IP = exc->IP + 1;
7687 call->Cur_Count = 1;
7688 call->Def = def;
7689
7690 Ins_Goto_CodeRange( exc, def->range, def->start );
7691
7692 exc->step_ins = FALSE;
7693 return;
7694 }
7695 }
7696
7697 exc->error = FT_THROW( Invalid_Opcode );
7698 }
7699
7700
7701 /**************************************************************************
7702 *
7703 * RUN
7704 *
7705 * This function executes a run of opcodes. It will exit in the
7706 * following cases:
7707 *
7708 * - Errors (in which case it returns FALSE).
7709 *
7710 * - Reaching the end of the main code range (returns TRUE).
7711 * Reaching the end of a code range within a function call is an
7712 * error.
7713 *
7714 * - After executing one single opcode, if the flag `Instruction_Trap'
7715 * is set to TRUE (returns TRUE).
7716 *
7717 * On exit with TRUE, test IP < CodeSize to know whether it comes from
7718 * an instruction trap or a normal termination.
7719 *
7720 *
7721 * Note: The documented DEBUG opcode pops a value from the stack. This
7722 * behaviour is unsupported; here a DEBUG opcode is always an
7723 * error.
7724 *
7725 *
7726 * THIS IS THE INTERPRETER'S MAIN LOOP.
7727 *
7728 */
7729
7730
7731 /* documentation is in ttinterp.h */
7732
7733 FT_EXPORT_DEF( FT_Error )
7734 TT_RunIns( TT_ExecContext exc )
7735 {
7736 FT_ULong ins_counter = 0; /* executed instructions counter */
7737 FT_ULong num_twilight_points;
7738 FT_UShort i;
7739
7740 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
7741 FT_Byte opcode_pattern[1][2] = {
7742 /* #8 TypeMan Talk Align */
7743 {
7744 0x06, /* SPVTL */
7745 0x7D, /* RDTG */
7746 },
7747 };
7748 FT_UShort opcode_patterns = 1;
7850 exc->func_move_cvt = Move_CVT;
7851 }
7852
7853 Compute_Funcs( exc );
7854 Compute_Round( exc, (FT_Byte)exc->GS.round_state );
7855
7856 do
7857 {
7858 exc->opcode = exc->code[exc->IP];
7859
7860 #ifdef FT_DEBUG_LEVEL_TRACE
7861 {
7862 FT_Long cnt = FT_MIN( 8, exc->top );
7863 FT_Long n;
7864
7865
7866 /* if tracing level is 7, show current code position */
7867 /* and the first few stack elements also */
7868 FT_TRACE6(( " " ));
7869 FT_TRACE7(( "%06d ", exc->IP ));
7870 FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 ));
7871 FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'
7872 ? 2
7873 : 12 - ( *opcode_name[exc->opcode] - '0' ),
7874 "#" ));
7875 for ( n = 1; n <= cnt; n++ )
7876 FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
7877 FT_TRACE6(( "\n" ));
7878 }
7879 #endif /* FT_DEBUG_LEVEL_TRACE */
7880
7881 if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
7882 {
7883 if ( exc->IP + 1 >= exc->codeSize )
7884 goto LErrorCodeOverflow_;
7885
7886 exc->length = 2 - exc->length * exc->code[exc->IP + 1];
7887 }
7888
7889 if ( exc->IP + exc->length > exc->codeSize )
7890 goto LErrorCodeOverflow_;
|