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