1 | /**************************************************************************** |
2 | * |
3 | * ttinterp.h |
4 | * |
5 | * TrueType bytecode interpreter (specification). |
6 | * |
7 | * Copyright (C) 1996-2023 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 | * |
10 | * This file is part of the FreeType project, and may only be used, |
11 | * modified, and distributed under the terms of the FreeType project |
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 | * this file you indicate that you have read the license and |
14 | * understand and accept it fully. |
15 | * |
16 | */ |
17 | |
18 | |
19 | #ifndef TTINTERP_H_ |
20 | #define TTINTERP_H_ |
21 | |
22 | #include "ttobjs.h" |
23 | |
24 | |
25 | FT_BEGIN_HEADER |
26 | |
27 | |
28 | /************************************************************************** |
29 | * |
30 | * Rounding mode constants. |
31 | */ |
32 | #define TT_Round_Off 5 |
33 | #define TT_Round_To_Half_Grid 0 |
34 | #define TT_Round_To_Grid 1 |
35 | #define TT_Round_To_Double_Grid 2 |
36 | #define TT_Round_Up_To_Grid 4 |
37 | #define TT_Round_Down_To_Grid 3 |
38 | #define TT_Round_Super 6 |
39 | #define TT_Round_Super_45 7 |
40 | |
41 | |
42 | /************************************************************************** |
43 | * |
44 | * Function types used by the interpreter, depending on various modes |
45 | * (e.g. the rounding mode, whether to render a vertical or horizontal |
46 | * line etc). |
47 | * |
48 | */ |
49 | |
50 | /* Rounding function */ |
51 | typedef FT_F26Dot6 |
52 | (*TT_Round_Func)( TT_ExecContext exc, |
53 | FT_F26Dot6 distance, |
54 | FT_Int color ); |
55 | |
56 | /* Point displacement along the freedom vector routine */ |
57 | typedef void |
58 | (*TT_Move_Func)( TT_ExecContext exc, |
59 | TT_GlyphZone zone, |
60 | FT_UShort point, |
61 | FT_F26Dot6 distance ); |
62 | |
63 | /* Distance projection along one of the projection vectors */ |
64 | typedef FT_F26Dot6 |
65 | (*TT_Project_Func)( TT_ExecContext exc, |
66 | FT_Pos dx, |
67 | FT_Pos dy ); |
68 | |
69 | /* getting current ppem. Take care of non-square pixels if necessary */ |
70 | typedef FT_Long |
71 | (*TT_Cur_Ppem_Func)( TT_ExecContext exc ); |
72 | |
73 | /* reading a cvt value. Take care of non-square pixels if necessary */ |
74 | typedef FT_F26Dot6 |
75 | (*TT_Get_CVT_Func)( TT_ExecContext exc, |
76 | FT_ULong idx ); |
77 | |
78 | /* setting or moving a cvt value. Take care of non-square pixels */ |
79 | /* if necessary */ |
80 | typedef void |
81 | (*TT_Set_CVT_Func)( TT_ExecContext exc, |
82 | FT_ULong idx, |
83 | FT_F26Dot6 value ); |
84 | |
85 | |
86 | /************************************************************************** |
87 | * |
88 | * This structure defines a call record, used to manage function calls. |
89 | */ |
90 | typedef struct TT_CallRec_ |
91 | { |
92 | FT_Int Caller_Range; |
93 | FT_Long Caller_IP; |
94 | FT_Long Cur_Count; |
95 | |
96 | TT_DefRecord *Def; /* either FDEF or IDEF */ |
97 | |
98 | } TT_CallRec, *TT_CallStack; |
99 | |
100 | |
101 | /************************************************************************** |
102 | * |
103 | * The main structure for the interpreter which collects all necessary |
104 | * variables and states. |
105 | * |
106 | * Members that are initialized by `TT_Load_Context` are marked with '!'. |
107 | * Members that are initialized by `TT_Run_Context` are marked with '@'. |
108 | */ |
109 | typedef struct TT_ExecContextRec_ |
110 | { |
111 | TT_Face face; /* ! */ |
112 | TT_Size size; /* ! */ |
113 | FT_Memory memory; |
114 | |
115 | /* instructions state */ |
116 | |
117 | FT_Error error; /* last execution error */ |
118 | |
119 | FT_Long top; /* @ top of exec. stack */ |
120 | |
121 | FT_Long stackSize; /* ! size of exec. stack */ |
122 | FT_Long* stack; /* ! current exec. stack */ |
123 | |
124 | FT_Long args; |
125 | FT_Long new_top; /* new top after exec. */ |
126 | |
127 | TT_GlyphZoneRec zp0, /* @! zone records */ |
128 | zp1, /* @! */ |
129 | zp2, /* @! */ |
130 | pts, /* ! */ |
131 | twilight; /* ! */ |
132 | |
133 | FT_Long pointSize; /* ! in 26.6 format */ |
134 | FT_Size_Metrics metrics; /* ! */ |
135 | TT_Size_Metrics tt_metrics; /* ! size metrics */ |
136 | |
137 | TT_GraphicsState GS; /* !@ current graphics state */ |
138 | |
139 | FT_Int iniRange; /* initial code range number */ |
140 | FT_Int curRange; /* current code range number */ |
141 | FT_Byte* code; /* current code range */ |
142 | FT_Long IP; /* current instruction pointer */ |
143 | FT_Long codeSize; /* size of current range */ |
144 | |
145 | FT_Byte opcode; /* current opcode */ |
146 | FT_Int length; /* length of current opcode */ |
147 | |
148 | FT_Bool step_ins; /* true if the interpreter must */ |
149 | /* increment IP after ins. exec */ |
150 | FT_ULong cvtSize; /* ! */ |
151 | FT_Long* cvt; /* ! */ |
152 | FT_ULong glyfCvtSize; |
153 | FT_Long* glyfCvt; /* cvt working copy for glyph */ |
154 | |
155 | FT_UInt glyphSize; /* ! glyph instructions buffer size */ |
156 | FT_Byte* glyphIns; /* ! glyph instructions buffer */ |
157 | |
158 | FT_UInt numFDefs; /* ! number of function defs */ |
159 | FT_UInt maxFDefs; /* ! maximum number of function defs */ |
160 | TT_DefArray FDefs; /* table of FDefs entries */ |
161 | |
162 | FT_UInt numIDefs; /* ! number of instruction defs */ |
163 | FT_UInt maxIDefs; /* ! maximum number of ins defs */ |
164 | TT_DefArray IDefs; /* table of IDefs entries */ |
165 | |
166 | FT_UInt maxFunc; /* ! maximum function index */ |
167 | FT_UInt maxIns; /* ! maximum instruction index */ |
168 | |
169 | FT_Int callTop, /* @ top of call stack during execution */ |
170 | callSize; /* size of call stack */ |
171 | TT_CallStack callStack; /* call stack */ |
172 | |
173 | FT_UShort maxPoints; /* capacity of this context's `pts' */ |
174 | FT_Short maxContours; /* record, expressed in points and */ |
175 | /* contours. */ |
176 | |
177 | TT_CodeRangeTable codeRangeTable; /* ! table of valid code ranges */ |
178 | /* useful for the debugger */ |
179 | |
180 | FT_UShort storeSize; /* ! size of current storage */ |
181 | FT_Long* storage; /* ! storage area */ |
182 | FT_UShort glyfStoreSize; |
183 | FT_Long* glyfStorage; /* storage working copy for glyph */ |
184 | |
185 | FT_F26Dot6 period; /* values used for the */ |
186 | FT_F26Dot6 phase; /* `SuperRounding' */ |
187 | FT_F26Dot6 threshold; |
188 | |
189 | FT_Bool instruction_trap; /* ! If `True', the interpreter */ |
190 | /* exits after each instruction */ |
191 | |
192 | TT_GraphicsState default_GS; /* graphics state resulting from */ |
193 | /* the prep program */ |
194 | FT_Bool is_composite; /* true if the glyph is composite */ |
195 | FT_Bool pedantic_hinting; /* true if pedantic interpretation */ |
196 | |
197 | /* latest interpreter additions */ |
198 | |
199 | FT_Long F_dot_P; /* dot product of freedom and projection */ |
200 | /* vectors */ |
201 | TT_Round_Func func_round; /* current rounding function */ |
202 | |
203 | TT_Project_Func func_project, /* current projection function */ |
204 | func_dualproj, /* current dual proj. function */ |
205 | func_freeProj; /* current freedom proj. func */ |
206 | |
207 | TT_Move_Func func_move; /* current point move function */ |
208 | TT_Move_Func func_move_orig; /* move original position function */ |
209 | |
210 | TT_Cur_Ppem_Func func_cur_ppem; /* get current proj. ppem value */ |
211 | |
212 | TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ |
213 | TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ |
214 | TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ |
215 | |
216 | FT_Bool grayscale; /* bi-level hinting and */ |
217 | /* grayscale rendering */ |
218 | |
219 | #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL |
220 | /* |
221 | * FreeType supports ClearType-like hinting of TrueType fonts through |
222 | * the version 40 interpreter. This is achieved through several hacks |
223 | * in the base (v35) interpreter, as detailed below. |
224 | * |
225 | * ClearType is an umbrella term for several rendering techniques |
226 | * employed by Microsoft's various GUI and rendering toolkit |
227 | * implementations, most importantly: subpixel rendering for using the |
228 | * RGB subpixels of LCDs to approximately triple the perceived |
229 | * resolution on the x-axis and subpixel hinting for positioning stems |
230 | * on subpixel borders. TrueType programming is explicit, i.e., fonts |
231 | * must be programmed to take advantage of ClearType's possibilities. |
232 | * |
233 | * When ClearType was introduced, it seemed unlikely that all fonts |
234 | * would be reprogrammed, so Microsoft decided to implement a backward |
235 | * compatibility mode. It employs several simple to complicated |
236 | * assumptions and tricks, many of them font-dependent, that modify the |
237 | * interpretation of the bytecode contained in these fonts to retrofit |
238 | * them into a ClearType-y look. The quality of the results varies. |
239 | * Most (web)fonts that were released since then have come to rely on |
240 | * these hacks to render correctly, even some of Microsoft's flagship |
241 | * fonts (e.g., Calibri, Cambria, Segoe UI). |
242 | * |
243 | * FreeType's minimal subpixel hinting code (interpreter version 40) |
244 | * employs a small list of font-agnostic hacks loosely based on the |
245 | * public information available on Microsoft's compatibility mode[2]. |
246 | * The focus is on modern (web)fonts rather than legacy fonts that were |
247 | * made for monochrome rendering. It will not match ClearType rendering |
248 | * exactly. Unlike the `Infinality' code (interpreter version 38) that |
249 | * came before, it will not try to toggle hacks for specific fonts for |
250 | * performance and complexity reasons. It will fall back to version 35 |
251 | * behavior for tricky fonts[1] or when monochrome rendering is |
252 | * requested. |
253 | * |
254 | * Major hacks |
255 | * |
256 | * - Any point movement on the x axis is ignored (cf. `Direct_Move' and |
257 | * `Direct_Move_X'). This has the smallest code footprint and single |
258 | * biggest effect. The ClearType way to increase resolution is |
259 | * supersampling the x axis, the FreeType way is ignoring instructions |
260 | * on the x axis, which gives the same result in the majority of |
261 | * cases. |
262 | * |
263 | * - Points are not moved post-IUP (neither on the x nor on the y axis), |
264 | * except the x component of diagonal moves post-IUP (cf. |
265 | * `Direct_Move', `Direct_Move_Y', `Move_Zp2_Point'). Post-IUP |
266 | * changes are commonly used to `fix' pixel patterns which has little |
267 | * use outside monochrome rendering. |
268 | * |
269 | * - SHPIX and DELTAP don't execute unless moving a composite on the |
270 | * y axis or moving a previously y touched point. SHPIX additionally |
271 | * denies movement on the x axis (cf. `Ins_SHPIX' and `Ins_DELTAP'). |
272 | * Both instructions are commonly used to `fix' pixel patterns for |
273 | * monochrome or Windows's GDI rendering but make little sense for |
274 | * FreeType rendering. Both can distort the outline. See [2] for |
275 | * details. |
276 | * |
277 | * - The hdmx table and modifications to phantom points are ignored. |
278 | * Bearings and advance widths remain unchanged (except rounding them |
279 | * outside the interpreter!), cf. `compute_glyph_metrics' and |
280 | * `TT_Hint_Glyph'. Letting non-native-ClearType fonts modify spacing |
281 | * might mess up spacing. |
282 | * |
283 | * Minor hacks |
284 | * |
285 | * - FLIPRGON, FLIPRGOFF, and FLIPPT don't execute post-IUP. This |
286 | * prevents dents in e.g. Arial-Regular's `D' and `G' glyphs at |
287 | * various sizes. |
288 | * |
289 | * (Post-IUP is the state after both IUP[x] and IUP[y] have been |
290 | * executed.) |
291 | * |
292 | * The best results are achieved for fonts that were from the outset |
293 | * designed with ClearType in mind, meaning they leave the x axis mostly |
294 | * alone and don't mess with the `final' outline to produce more |
295 | * pleasing pixel patterns. The harder the designer tried to produce |
296 | * very specific patterns (`superhinting') for pre-ClearType-displays, |
297 | * the worse the results. |
298 | * |
299 | * Microsoft defines a way to turn off backward compatibility and |
300 | * interpret instructions as before (called `native ClearType')[2][3]. |
301 | * The font designer then regains full control and is responsible for |
302 | * making the font work correctly with ClearType without any |
303 | * hand-holding by the interpreter or rasterizer[4]. The v40 |
304 | * interpreter assumes backward compatibility by default, which can be |
305 | * turned off the same way by executing the following in the control |
306 | * program (cf. `Ins_INSTCTRL'). |
307 | * |
308 | * #PUSH 4,3 |
309 | * INSTCTRL[] |
310 | * |
311 | * [1] Tricky fonts as FreeType defines them rely on the bytecode |
312 | * interpreter to display correctly. Hacks can interfere with them, |
313 | * so they get treated like native ClearType fonts (v40 with |
314 | * backward compatibility turned off). Cf. `TT_RunIns'. |
315 | * |
316 | * [2] Proposed by Microsoft's Greg Hitchcock in |
317 | * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx |
318 | * |
319 | * [3] Beat Stamm describes it in more detail: |
320 | * http://rastertragedy.com/RTRCh4.htm#Sec12. |
321 | * |
322 | * [4] The list of `native ClearType' fonts is small at the time of this |
323 | * writing; I found the following on a Windows 10 Update 1511 |
324 | * installation: Constantia, Corbel, Sitka, Malgun Gothic, Microsoft |
325 | * JhengHei (Bold and UI Bold), Microsoft YaHei (Bold and UI Bold), |
326 | * SimSun, NSimSun, and Yu Gothic. |
327 | * |
328 | */ |
329 | |
330 | /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been |
331 | * requested. Used to detect interpreter */ |
332 | /* version switches. `_lean' to differentiate from the Infinality */ |
333 | /* `subpixel_hinting', which is managed differently. */ |
334 | FT_Bool subpixel_hinting_lean; |
335 | |
336 | /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ |
337 | /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ |
338 | /* is managed differently. */ |
339 | FT_Bool vertical_lcd_lean; |
340 | |
341 | /* Default to backward compatibility mode in v40 interpreter. If */ |
342 | /* this is false, it implies the interpreter is in v35 or in native */ |
343 | /* ClearType mode. */ |
344 | FT_Bool backward_compatibility; |
345 | |
346 | /* Useful for detecting and denying post-IUP trickery that is usually */ |
347 | /* used to fix pixel patterns (`superhinting'). */ |
348 | FT_Bool iupx_called; |
349 | FT_Bool iupy_called; |
350 | |
351 | /* ClearType hinting and grayscale rendering, as used by Universal */ |
352 | /* Windows Platform apps (Windows 8 and above). Like the standard */ |
353 | /* colorful ClearType mode, it utilizes a vastly increased virtual */ |
354 | /* resolution on the x axis. Different from bi-level hinting and */ |
355 | /* grayscale rendering, the old mode from Win9x days that roughly */ |
356 | /* adheres to the physical pixel grid on both axes. */ |
357 | FT_Bool grayscale_cleartype; |
358 | #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ |
359 | |
360 | /* We maintain two counters (in addition to the instruction counter) */ |
361 | /* that act as loop detectors for LOOPCALL and jump opcodes with */ |
362 | /* negative arguments. */ |
363 | FT_ULong loopcall_counter; |
364 | FT_ULong loopcall_counter_max; |
365 | FT_ULong neg_jump_counter; |
366 | FT_ULong neg_jump_counter_max; |
367 | |
368 | } TT_ExecContextRec; |
369 | |
370 | |
371 | extern const TT_GraphicsState tt_default_graphics_state; |
372 | |
373 | |
374 | #ifdef TT_USE_BYTECODE_INTERPRETER |
375 | FT_LOCAL( void ) |
376 | TT_Goto_CodeRange( TT_ExecContext exec, |
377 | FT_Int range, |
378 | FT_Long IP ); |
379 | |
380 | FT_LOCAL( void ) |
381 | TT_Set_CodeRange( TT_ExecContext exec, |
382 | FT_Int range, |
383 | void* base, |
384 | FT_Long length ); |
385 | |
386 | FT_LOCAL( void ) |
387 | TT_Clear_CodeRange( TT_ExecContext exec, |
388 | FT_Int range ); |
389 | #endif /* TT_USE_BYTECODE_INTERPRETER */ |
390 | |
391 | |
392 | /************************************************************************** |
393 | * |
394 | * @Function: |
395 | * TT_New_Context |
396 | * |
397 | * @Description: |
398 | * Create a `TT_ExecContext`. Note that there is now an execution |
399 | * context per `TT_Size` that is not shared among faces. |
400 | * |
401 | * @Input: |
402 | * driver :: |
403 | * A handle to the driver, used for memory allocation. |
404 | * |
405 | * @Return: |
406 | * A handle to a new empty execution context. |
407 | * |
408 | * @Note: |
409 | * Only the glyph loader and debugger should call this function. |
410 | * (And right now only the glyph loader uses it.) |
411 | */ |
412 | FT_EXPORT( TT_ExecContext ) |
413 | TT_New_Context( TT_Driver driver ); |
414 | |
415 | |
416 | #ifdef TT_USE_BYTECODE_INTERPRETER |
417 | FT_LOCAL( void ) |
418 | TT_Done_Context( TT_ExecContext exec ); |
419 | |
420 | FT_LOCAL( FT_Error ) |
421 | TT_Load_Context( TT_ExecContext exec, |
422 | TT_Face face, |
423 | TT_Size size ); |
424 | |
425 | FT_LOCAL( void ) |
426 | TT_Save_Context( TT_ExecContext exec, |
427 | TT_Size ins ); |
428 | |
429 | FT_LOCAL( FT_Error ) |
430 | TT_Run_Context( TT_ExecContext exec ); |
431 | #endif /* TT_USE_BYTECODE_INTERPRETER */ |
432 | |
433 | |
434 | /************************************************************************** |
435 | * |
436 | * @Function: |
437 | * TT_RunIns |
438 | * |
439 | * @Description: |
440 | * Executes one or more instruction in the execution context. This |
441 | * is the main function of the TrueType opcode interpreter. |
442 | * |
443 | * @Input: |
444 | * exec :: |
445 | * A handle to the target execution context. |
446 | * |
447 | * @Return: |
448 | * FreeType error code. 0 means success. |
449 | * |
450 | * @Note: |
451 | * Only the object manager and debugger should call this function. |
452 | * |
453 | * This function is publicly exported because it is directly |
454 | * invoked by the TrueType debugger. |
455 | */ |
456 | FT_EXPORT( FT_Error ) |
457 | TT_RunIns( void* exec ); |
458 | |
459 | |
460 | FT_END_HEADER |
461 | |
462 | #endif /* TTINTERP_H_ */ |
463 | |
464 | |
465 | /* END */ |
466 | |