1 | /***************************************************************************/ |
2 | /* */ |
3 | /* afglobal.c */ |
4 | /* */ |
5 | /* Auto-fitter routines to compute global hinting values (body). */ |
6 | /* */ |
7 | /* Copyright 2003-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 | #include "afglobal.h" |
20 | #include "afranges.h" |
21 | #include "afshaper.h" |
22 | #include FT_INTERNAL_DEBUG_H |
23 | |
24 | |
25 | /*************************************************************************/ |
26 | /* */ |
27 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
28 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
29 | /* messages during execution. */ |
30 | /* */ |
31 | #undef FT_COMPONENT |
32 | #define FT_COMPONENT trace_afglobal |
33 | |
34 | |
35 | /* get writing system specific header files */ |
36 | #undef WRITING_SYSTEM |
37 | #define WRITING_SYSTEM( ws, WS ) /* empty */ |
38 | #include "afwrtsys.h" |
39 | |
40 | #include "aferrors.h" |
41 | #include "afpic.h" |
42 | |
43 | |
44 | #undef SCRIPT |
45 | #define SCRIPT( s, S, d, h, H, ss ) \ |
46 | AF_DEFINE_SCRIPT_CLASS( \ |
47 | af_ ## s ## _script_class, \ |
48 | AF_SCRIPT_ ## S, \ |
49 | af_ ## s ## _uniranges, \ |
50 | af_ ## s ## _nonbase_uniranges, \ |
51 | AF_ ## H, \ |
52 | ss ) |
53 | |
54 | #include "afscript.h" |
55 | |
56 | |
57 | #undef STYLE |
58 | #define STYLE( s, S, d, ws, sc, ss, c ) \ |
59 | AF_DEFINE_STYLE_CLASS( \ |
60 | af_ ## s ## _style_class, \ |
61 | AF_STYLE_ ## S, \ |
62 | ws, \ |
63 | sc, \ |
64 | ss, \ |
65 | c ) |
66 | |
67 | #include "afstyles.h" |
68 | |
69 | |
70 | #ifndef FT_CONFIG_OPTION_PIC |
71 | |
72 | #undef WRITING_SYSTEM |
73 | #define WRITING_SYSTEM( ws, WS ) \ |
74 | &af_ ## ws ## _writing_system_class, |
75 | |
76 | FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) |
77 | af_writing_system_classes[] = |
78 | { |
79 | |
80 | #include "afwrtsys.h" |
81 | |
82 | NULL /* do not remove */ |
83 | }; |
84 | |
85 | |
86 | #undef SCRIPT |
87 | #define SCRIPT( s, S, d, h, H, ss ) \ |
88 | &af_ ## s ## _script_class, |
89 | |
90 | FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) |
91 | af_script_classes[] = |
92 | { |
93 | |
94 | #include "afscript.h" |
95 | |
96 | NULL /* do not remove */ |
97 | }; |
98 | |
99 | |
100 | #undef STYLE |
101 | #define STYLE( s, S, d, ws, sc, ss, c ) \ |
102 | &af_ ## s ## _style_class, |
103 | |
104 | FT_LOCAL_ARRAY_DEF( AF_StyleClass ) |
105 | af_style_classes[] = |
106 | { |
107 | |
108 | #include "afstyles.h" |
109 | |
110 | NULL /* do not remove */ |
111 | }; |
112 | |
113 | #endif /* !FT_CONFIG_OPTION_PIC */ |
114 | |
115 | |
116 | #ifdef FT_DEBUG_LEVEL_TRACE |
117 | |
118 | #undef STYLE |
119 | #define STYLE( s, S, d, ws, sc, ss, c ) #s, |
120 | |
121 | FT_LOCAL_ARRAY_DEF( char* ) |
122 | af_style_names[] = |
123 | { |
124 | |
125 | #include "afstyles.h" |
126 | |
127 | }; |
128 | |
129 | #endif /* FT_DEBUG_LEVEL_TRACE */ |
130 | |
131 | |
132 | /* Compute the style index of each glyph within a given face. */ |
133 | |
134 | static FT_Error |
135 | af_face_globals_compute_style_coverage( AF_FaceGlobals globals ) |
136 | { |
137 | FT_Error error; |
138 | FT_Face face = globals->face; |
139 | FT_CharMap old_charmap = face->charmap; |
140 | FT_UShort* gstyles = globals->glyph_styles; |
141 | FT_UInt ss; |
142 | FT_UInt i; |
143 | FT_UInt dflt = ~0U; /* a non-valid value */ |
144 | |
145 | |
146 | /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ |
147 | for ( i = 0; i < (FT_UInt)globals->glyph_count; i++ ) |
148 | gstyles[i] = AF_STYLE_UNASSIGNED; |
149 | |
150 | error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); |
151 | if ( error ) |
152 | { |
153 | /* |
154 | * Ignore this error; we simply use the fallback style. |
155 | * XXX: Shouldn't we rather disable hinting? |
156 | */ |
157 | error = FT_Err_Ok; |
158 | goto Exit; |
159 | } |
160 | |
161 | /* scan each style in a Unicode charmap */ |
162 | for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) |
163 | { |
164 | AF_StyleClass style_class = |
165 | AF_STYLE_CLASSES_GET[ss]; |
166 | AF_ScriptClass script_class = |
167 | AF_SCRIPT_CLASSES_GET[style_class->script]; |
168 | AF_Script_UniRange range; |
169 | |
170 | |
171 | if ( !script_class->script_uni_ranges ) |
172 | continue; |
173 | |
174 | /* |
175 | * Scan all Unicode points in the range and set the corresponding |
176 | * glyph style index. |
177 | */ |
178 | if ( style_class->coverage == AF_COVERAGE_DEFAULT ) |
179 | { |
180 | if ( (FT_UInt)style_class->script == |
181 | globals->module->default_script ) |
182 | dflt = ss; |
183 | |
184 | for ( range = script_class->script_uni_ranges; |
185 | range->first != 0; |
186 | range++ ) |
187 | { |
188 | FT_ULong charcode = range->first; |
189 | FT_UInt gindex; |
190 | |
191 | |
192 | gindex = FT_Get_Char_Index( face, charcode ); |
193 | |
194 | if ( gindex != 0 && |
195 | gindex < (FT_ULong)globals->glyph_count && |
196 | ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) |
197 | gstyles[gindex] = (FT_UShort)ss; |
198 | |
199 | for (;;) |
200 | { |
201 | charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
202 | |
203 | if ( gindex == 0 || charcode > range->last ) |
204 | break; |
205 | |
206 | if ( gindex < (FT_ULong)globals->glyph_count && |
207 | ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) |
208 | gstyles[gindex] = (FT_UShort)ss; |
209 | } |
210 | } |
211 | |
212 | /* do the same for the script's non-base characters */ |
213 | for ( range = script_class->script_uni_nonbase_ranges; |
214 | range->first != 0; |
215 | range++ ) |
216 | { |
217 | FT_ULong charcode = range->first; |
218 | FT_UInt gindex; |
219 | |
220 | |
221 | gindex = FT_Get_Char_Index( face, charcode ); |
222 | |
223 | if ( gindex != 0 && |
224 | gindex < (FT_ULong)globals->glyph_count && |
225 | ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss ) |
226 | gstyles[gindex] |= AF_NONBASE; |
227 | |
228 | for (;;) |
229 | { |
230 | charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
231 | |
232 | if ( gindex == 0 || charcode > range->last ) |
233 | break; |
234 | |
235 | if ( gindex < (FT_ULong)globals->glyph_count && |
236 | ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss ) |
237 | gstyles[gindex] |= AF_NONBASE; |
238 | } |
239 | } |
240 | } |
241 | else |
242 | { |
243 | /* get glyphs not directly addressable by cmap */ |
244 | af_shaper_get_coverage( globals, style_class, gstyles, 0 ); |
245 | } |
246 | } |
247 | |
248 | /* handle the remaining default OpenType features ... */ |
249 | for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) |
250 | { |
251 | AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; |
252 | |
253 | |
254 | if ( style_class->coverage == AF_COVERAGE_DEFAULT ) |
255 | af_shaper_get_coverage( globals, style_class, gstyles, 0 ); |
256 | } |
257 | |
258 | /* ... and finally the default OpenType features of the default script */ |
259 | af_shaper_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles, 1 ); |
260 | |
261 | /* mark ASCII digits */ |
262 | for ( i = 0x30; i <= 0x39; i++ ) |
263 | { |
264 | FT_UInt gindex = FT_Get_Char_Index( face, i ); |
265 | |
266 | |
267 | if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) |
268 | gstyles[gindex] |= AF_DIGIT; |
269 | } |
270 | |
271 | Exit: |
272 | /* |
273 | * By default, all uncovered glyphs are set to the fallback style. |
274 | * XXX: Shouldn't we disable hinting or do something similar? |
275 | */ |
276 | if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) |
277 | { |
278 | FT_Long nn; |
279 | |
280 | |
281 | for ( nn = 0; nn < globals->glyph_count; nn++ ) |
282 | { |
283 | if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) |
284 | { |
285 | gstyles[nn] &= ~AF_STYLE_MASK; |
286 | gstyles[nn] |= globals->module->fallback_style; |
287 | } |
288 | } |
289 | } |
290 | |
291 | #ifdef FT_DEBUG_LEVEL_TRACE |
292 | |
293 | FT_TRACE4(( "\n" |
294 | "style coverage\n" |
295 | "==============\n" |
296 | "\n" )); |
297 | |
298 | for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) |
299 | { |
300 | AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; |
301 | FT_UInt count = 0; |
302 | FT_Long idx; |
303 | |
304 | |
305 | FT_TRACE4(( "%s:\n" , af_style_names[style_class->style] )); |
306 | |
307 | for ( idx = 0; idx < globals->glyph_count; idx++ ) |
308 | { |
309 | if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style ) |
310 | { |
311 | if ( !( count % 10 ) ) |
312 | FT_TRACE4(( " " )); |
313 | |
314 | FT_TRACE4(( " %d" , idx )); |
315 | count++; |
316 | |
317 | if ( !( count % 10 ) ) |
318 | FT_TRACE4(( "\n" )); |
319 | } |
320 | } |
321 | |
322 | if ( !count ) |
323 | FT_TRACE4(( " (none)\n" )); |
324 | if ( count % 10 ) |
325 | FT_TRACE4(( "\n" )); |
326 | } |
327 | |
328 | #endif /* FT_DEBUG_LEVEL_TRACE */ |
329 | |
330 | FT_Set_Charmap( face, old_charmap ); |
331 | return error; |
332 | } |
333 | |
334 | |
335 | FT_LOCAL_DEF( FT_Error ) |
336 | af_face_globals_new( FT_Face face, |
337 | AF_FaceGlobals *aglobals, |
338 | AF_Module module ) |
339 | { |
340 | FT_Error error; |
341 | FT_Memory memory; |
342 | AF_FaceGlobals globals = NULL; |
343 | |
344 | |
345 | memory = face->memory; |
346 | |
347 | /* we allocate an AF_FaceGlobals structure together */ |
348 | /* with the glyph_styles array */ |
349 | if ( FT_ALLOC( globals, |
350 | sizeof ( *globals ) + |
351 | (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) |
352 | goto Exit; |
353 | |
354 | globals->face = face; |
355 | globals->glyph_count = face->num_glyphs; |
356 | /* right after the globals structure come the glyph styles */ |
357 | globals->glyph_styles = (FT_UShort*)( globals + 1 ); |
358 | globals->module = module; |
359 | globals->stem_darkening_for_ppem = 0; |
360 | globals->darken_x = 0; |
361 | globals->darken_y = 0; |
362 | globals->standard_vertical_width = 0; |
363 | globals->standard_horizontal_width = 0; |
364 | globals->scale_down_factor = 0; |
365 | |
366 | #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ |
367 | globals->hb_font = hb_ft_font_create( face, NULL ); |
368 | globals->hb_buf = hb_buffer_create(); |
369 | #endif |
370 | |
371 | error = af_face_globals_compute_style_coverage( globals ); |
372 | if ( error ) |
373 | { |
374 | af_face_globals_free( globals ); |
375 | globals = NULL; |
376 | } |
377 | else |
378 | globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; |
379 | |
380 | Exit: |
381 | *aglobals = globals; |
382 | return error; |
383 | } |
384 | |
385 | |
386 | FT_LOCAL_DEF( void ) |
387 | af_face_globals_free( AF_FaceGlobals globals ) |
388 | { |
389 | if ( globals ) |
390 | { |
391 | FT_Memory memory = globals->face->memory; |
392 | FT_UInt nn; |
393 | |
394 | |
395 | for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) |
396 | { |
397 | if ( globals->metrics[nn] ) |
398 | { |
399 | AF_StyleClass style_class = |
400 | AF_STYLE_CLASSES_GET[nn]; |
401 | AF_WritingSystemClass writing_system_class = |
402 | AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; |
403 | |
404 | |
405 | if ( writing_system_class->style_metrics_done ) |
406 | writing_system_class->style_metrics_done( globals->metrics[nn] ); |
407 | |
408 | FT_FREE( globals->metrics[nn] ); |
409 | } |
410 | } |
411 | |
412 | #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ |
413 | hb_font_destroy( globals->hb_font ); |
414 | hb_buffer_destroy( globals->hb_buf ); |
415 | #endif |
416 | |
417 | /* no need to free `globals->glyph_styles'; */ |
418 | /* it is part of the `globals' array */ |
419 | FT_FREE( globals ); |
420 | } |
421 | } |
422 | |
423 | |
424 | FT_LOCAL_DEF( FT_Error ) |
425 | af_face_globals_get_metrics( AF_FaceGlobals globals, |
426 | FT_UInt gindex, |
427 | FT_UInt options, |
428 | AF_StyleMetrics *ametrics ) |
429 | { |
430 | AF_StyleMetrics metrics = NULL; |
431 | |
432 | AF_Style style = (AF_Style)options; |
433 | AF_WritingSystemClass writing_system_class; |
434 | AF_StyleClass style_class; |
435 | |
436 | FT_Error error = FT_Err_Ok; |
437 | |
438 | |
439 | if ( gindex >= (FT_ULong)globals->glyph_count ) |
440 | { |
441 | error = FT_THROW( Invalid_Argument ); |
442 | goto Exit; |
443 | } |
444 | |
445 | /* if we have a forced style (via `options'), use it, */ |
446 | /* otherwise look into `glyph_styles' array */ |
447 | if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) |
448 | style = (AF_Style)( globals->glyph_styles[gindex] & |
449 | AF_STYLE_UNASSIGNED ); |
450 | |
451 | style_class = AF_STYLE_CLASSES_GET[style]; |
452 | writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET |
453 | [style_class->writing_system]; |
454 | |
455 | metrics = globals->metrics[style]; |
456 | if ( !metrics ) |
457 | { |
458 | /* create the global metrics object if necessary */ |
459 | FT_Memory memory = globals->face->memory; |
460 | |
461 | |
462 | if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) |
463 | goto Exit; |
464 | |
465 | metrics->style_class = style_class; |
466 | metrics->globals = globals; |
467 | |
468 | if ( writing_system_class->style_metrics_init ) |
469 | { |
470 | error = writing_system_class->style_metrics_init( metrics, |
471 | globals->face ); |
472 | if ( error ) |
473 | { |
474 | if ( writing_system_class->style_metrics_done ) |
475 | writing_system_class->style_metrics_done( metrics ); |
476 | |
477 | FT_FREE( metrics ); |
478 | goto Exit; |
479 | } |
480 | } |
481 | |
482 | globals->metrics[style] = metrics; |
483 | } |
484 | |
485 | Exit: |
486 | *ametrics = metrics; |
487 | |
488 | return error; |
489 | } |
490 | |
491 | |
492 | FT_LOCAL_DEF( FT_Bool ) |
493 | af_face_globals_is_digit( AF_FaceGlobals globals, |
494 | FT_UInt gindex ) |
495 | { |
496 | if ( gindex < (FT_ULong)globals->glyph_count ) |
497 | return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT ); |
498 | |
499 | return (FT_Bool)0; |
500 | } |
501 | |
502 | |
503 | /* END */ |
504 | |