Some fixes found by cppcheck.
[ttfautohint.git] / lib / taglobal.c
blobafcc9c86ff04b57268dff8053de24110a13d2efe
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011-2019 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 /* originally file `afglobal.c' (2011-Mar-28) from FreeType */
18 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
20 #include <stdlib.h>
22 #include "taglobal.h"
23 #include "taranges.h"
26 #undef SCRIPT
27 #define SCRIPT(s, S, d, h, H, ss) \
28 const TA_ScriptClassRec ta_ ## s ## _script_class = \
29 { \
30 TA_SCRIPT_ ## S, \
31 ta_ ## s ## _uniranges, \
32 ta_ ## s ## _nonbase_uniranges, \
33 TA_ ## H, \
34 ss \
37 #include <ttfautohint-scripts.h>
40 #undef STYLE
41 #define STYLE(s, S, d, ws, sc, ss, c) \
42 const TA_StyleClassRec ta_ ## s ## _style_class = \
43 { \
44 TA_STYLE_ ## S, \
45 ws, \
46 sc, \
47 ss, \
48 c \
51 #include "tastyles.h"
54 /* get writing system specific header files */
55 #undef WRITING_SYSTEM
56 #define WRITING_SYSTEM(ws, WS) /* empty */
57 #include "tawrtsys.h"
60 #undef WRITING_SYSTEM
61 #define WRITING_SYSTEM(ws, WS) \
62 &ta_ ## ws ## _writing_system_class,
64 TA_WritingSystemClass const ta_writing_system_classes[] =
67 #include "tawrtsys.h"
69 NULL /* do not remove */
73 #undef SCRIPT
74 #define SCRIPT(s, S, d, h, H, ss) \
75 &ta_ ## s ## _script_class,
77 TA_ScriptClass const ta_script_classes[] =
80 #include <ttfautohint-scripts.h>
82 NULL /* do not remove */
86 #undef STYLE
87 #define STYLE(s, S, d, ws, sc, ss, c) \
88 &ta_ ## s ## _style_class,
90 TA_StyleClass const ta_style_classes[] =
93 #include "tastyles.h"
95 NULL /* do not remove */
99 #ifdef TA_DEBUG
101 #undef STYLE
102 #define STYLE(s, S, d, ws, sc, ss, c) #s,
104 const char* ta_style_names[] =
107 #include <tastyles.h>
111 #endif /* TA_DEBUG */
114 /* Recursively assign a style to all components of a composite glyph. */
116 static FT_Error
117 ta_face_globals_scan_composite(FT_Face face,
118 FT_Long gindex,
119 FT_UShort gstyle,
120 FT_UShort* gstyles,
121 FT_Int nesting_level)
123 FT_Error error;
124 FT_UInt i;
126 FT_GlyphSlot glyph;
128 FT_Int* subglyph_indices = NULL;
129 FT_UInt used_subglyphs;
131 FT_Int p_index;
132 FT_UInt p_flags;
133 FT_Int p_arg1;
134 FT_Int p_arg2;
135 FT_Matrix p_transform;
138 /* limit recursion arbitrarily */
139 if (nesting_level > 100)
140 return FT_Err_Invalid_Table;
142 error = FT_Load_Glyph(face, (FT_UInt)gindex, FT_LOAD_NO_RECURSE);
143 if (error)
144 return error;
146 glyph = face->glyph;
148 /* in FreeType < 2.5.4, FT_Get_SubGlyph_Info always returns an error */
149 /* due to a bug even if the call was successful; */
150 /* for this reason we do the argument checking by ourselves */
151 /* and ignore the returned error code of FT_Get_SubGlyph_Info */
152 if (!glyph->subglyphs
153 || glyph->format != FT_GLYPH_FORMAT_COMPOSITE)
154 return FT_Err_Ok;
156 /* since a call to FT_Load_Glyph changes `glyph', */
157 /* we have to first store the subglyph indices, then do the recursion */
158 subglyph_indices = (FT_Int*)malloc(sizeof (FT_Int) * glyph->num_subglyphs);
159 if (!subglyph_indices)
160 return FT_Err_Out_Of_Memory;
162 used_subglyphs = 0;
163 for (i = 0; i < glyph->num_subglyphs; i++)
165 (void)FT_Get_SubGlyph_Info(glyph,
167 &p_index,
168 &p_flags,
169 &p_arg1,
170 &p_arg2,
171 &p_transform);
173 if (p_index >= face->num_glyphs
174 || (gstyles[p_index] & TA_STYLE_MASK) != TA_STYLE_UNASSIGNED)
175 continue;
177 /* only take subglyphs that are not shifted vertically; */
178 /* otherwise blue zones don't fit */
179 if (p_flags & ARGS_ARE_XY_VALUES
180 && p_arg2 == 0)
182 gstyles[p_index] = gstyle;
183 subglyph_indices[used_subglyphs++] = p_index;
187 /* recurse */
188 for (i = 0; i < used_subglyphs; i++)
190 error = ta_face_globals_scan_composite(face,
191 subglyph_indices[i],
192 gstyle,
193 gstyles,
194 nesting_level + 1);
195 if (error)
196 break;
199 free(subglyph_indices);
201 return error;
205 /* Compute the style index of each glyph within a given face. */
207 static FT_Error
208 ta_face_globals_compute_style_coverage(TA_FaceGlobals globals)
210 FT_Error error;
211 FT_Face face = globals->face;
212 FT_CharMap old_charmap = face->charmap;
213 FT_UShort* gstyles = globals->glyph_styles;
214 FT_UInt ss;
215 FT_UInt i;
216 FT_UInt dflt = ~0U; /* a non-valid value */
219 /* the value TA_STYLE_UNASSIGNED means `uncovered glyph' */
220 for (i = 0; i < (unsigned int)globals->glyph_count; i++)
221 gstyles[i] = TA_STYLE_UNASSIGNED;
223 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
224 if (error)
226 /* ignore this error; we simply use the fallback style */
227 /* XXX: Shouldn't we rather disable hinting? */
228 error = FT_Err_Ok;
229 goto Exit;
232 /* scan each style in a Unicode charmap */
233 for (ss = 0; ta_style_classes[ss]; ss++)
235 TA_StyleClass style_class = ta_style_classes[ss];
236 FT_UInt* sample_glyph = &globals->sample_glyphs[ss];
237 TA_ScriptClass script_class = ta_script_classes[style_class->script];
238 TA_Script_UniRange range;
241 if (!script_class->script_uni_ranges->first)
242 continue;
244 /* scan all Unicode points in the range and */
245 /* set the corresponding glyph style index */
246 if (style_class->coverage == TA_COVERAGE_DEFAULT)
248 if ((FT_UInt)style_class->script == globals->font->default_script)
249 dflt = ss;
251 for (range = script_class->script_uni_ranges;
252 range->first != 0;
253 range++)
255 FT_ULong charcode = range->first;
256 FT_UInt gindex;
259 gindex = FT_Get_Char_Index(face, charcode);
261 if (gindex != 0
262 && gindex < (FT_ULong)globals->glyph_count
263 && (gstyles[gindex] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
265 gstyles[gindex] = (FT_UShort)ss;
266 if (!*sample_glyph)
267 *sample_glyph = gindex;
270 for (;;)
272 charcode = FT_Get_Next_Char(face, charcode, &gindex);
274 if (gindex == 0 || charcode > range->last)
275 break;
277 if (gindex < (FT_ULong)globals->glyph_count
278 && (gstyles[gindex] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
280 gstyles[gindex] = (FT_UShort)ss;
281 if (!*sample_glyph)
282 *sample_glyph = gindex;
287 /* do the same for the script's non-base characters */
288 for (range = script_class->script_uni_nonbase_ranges;
289 range->first != 0;
290 range++)
292 FT_ULong charcode = range->first;
293 FT_UInt gindex;
296 gindex = FT_Get_Char_Index(face, charcode);
298 if (gindex != 0
299 && gindex < (FT_ULong)globals->glyph_count
300 && (gstyles[gindex] & TA_STYLE_MASK) == (FT_UShort)ss)
302 gstyles[gindex] |= TA_NONBASE;
303 if (!*sample_glyph)
304 *sample_glyph = gindex;
307 for (;;)
309 charcode = FT_Get_Next_Char(face, charcode, &gindex);
311 if (gindex == 0 || charcode > range->last)
312 break;
314 if (gindex < (FT_ULong)globals->glyph_count
315 && (gstyles[gindex] & TA_STYLE_MASK) == (FT_UShort)ss)
317 gstyles[gindex] |= TA_NONBASE;
318 if (!*sample_glyph)
319 *sample_glyph = gindex;
324 else
326 /* get glyphs not directly addressable by cmap */
327 ta_shaper_get_coverage(globals,
328 style_class,
329 gstyles,
330 sample_glyph,
335 /* handle the remaining default OpenType features ... */
336 for (ss = 0; ta_style_classes[ss]; ss++)
338 TA_StyleClass style_class = ta_style_classes[ss];
339 FT_UInt* sample_glyph = &globals->sample_glyphs[ss];
342 if (style_class->coverage == TA_COVERAGE_DEFAULT)
343 ta_shaper_get_coverage(globals,
344 style_class,
345 gstyles,
346 sample_glyph,
350 /* ... and finally the default OpenType features of the default script */
351 ta_shaper_get_coverage(globals,
352 ta_style_classes[dflt],
353 gstyles,
354 &globals->sample_glyphs[dflt],
357 /* mark ASCII digits */
358 for (i = 0x30; i <= 0x39; i++)
360 FT_UInt gindex = FT_Get_Char_Index(face, i);
363 if (gindex != 0
364 && gindex < (FT_ULong)globals->glyph_count)
365 gstyles[gindex] |= TA_DIGIT;
368 /* now walk over all glyphs and check for composites: */
369 /* since subglyphs are hinted separately if option `hint-composites' */
370 /* isn't set, we have to tag them with style indices, too */
372 FT_Long nn;
375 /* no need for updating `sample_glyphs'; */
376 /* the composite itself is certainly a valid sample glyph */
378 for (nn = 0; nn < globals->glyph_count; nn++)
380 if ((gstyles[nn] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
381 continue;
383 error = ta_face_globals_scan_composite(globals->face,
385 gstyles[nn],
386 gstyles,
388 if (error)
389 return error;
393 Exit:
394 /* by default, all uncovered glyphs are set to the fallback style */
395 /* XXX: Shouldn't we disable hinting or do something similar? */
396 if (globals->font->fallback_style != (TA_Style)TA_STYLE_UNASSIGNED)
398 FT_Long nn;
401 for (nn = 0; nn < globals->glyph_count; nn++)
403 if ((gstyles[nn] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
405 gstyles[nn] &= ~TA_STYLE_MASK;
406 gstyles[nn] |= globals->font->fallback_style;
411 #ifdef TA_DEBUG
413 if (face->num_faces > 1)
414 TA_LOG_GLOBAL(("\n"
415 "style coverage (subfont %d, glyf table index %d)\n"
416 "================================================\n"
417 "\n",
418 face->face_index,
419 globals->font->sfnts[face->face_index].glyf_idx));
420 else
421 TA_LOG_GLOBAL(("\n"
422 "style coverage\n"
423 "==============\n"
424 "\n"));
426 for (ss = 0; ta_style_classes[ss]; ss++)
428 TA_StyleClass style_class = ta_style_classes[ss];
429 FT_UInt count = 0;
430 FT_Long idx;
433 TA_LOG_GLOBAL(("%s:\n", ta_style_names[style_class->style]));
435 for (idx = 0; idx < globals->glyph_count; idx++)
437 if ((gstyles[idx] & TA_STYLE_MASK) == style_class->style)
439 if (!(count % 10))
440 TA_LOG_GLOBAL((" "));
442 TA_LOG_GLOBAL((" %d", idx));
443 count++;
445 if (!(count % 10))
446 TA_LOG_GLOBAL(("\n"));
450 if (!count)
451 TA_LOG_GLOBAL((" (none)\n"));
452 if (count % 10)
453 TA_LOG_GLOBAL(("\n"));
456 #endif /* TA_DEBUG */
458 FT_Set_Charmap(face, old_charmap);
459 return error;
463 FT_Error
464 ta_face_globals_new(FT_Face face,
465 TA_FaceGlobals *aglobals,
466 FONT* font)
468 FT_Error error;
469 TA_FaceGlobals globals;
472 /* we allocate an TA_FaceGlobals structure together */
473 /* with the glyph_styles array */
474 globals = (TA_FaceGlobals)calloc(
475 1, sizeof (TA_FaceGlobalsRec) +
476 (FT_ULong)face->num_glyphs * sizeof (FT_UShort));
477 if (!globals)
479 error = FT_Err_Out_Of_Memory;
480 goto Err;
483 globals->face = face;
484 globals->glyph_count = face->num_glyphs;
485 /* right after the globals structure come the glyph styles */
486 globals->glyph_styles = (FT_UShort*)(globals + 1);
487 globals->font = font;
488 globals->hb_font = hb_ft_font_create(face, NULL);
489 globals->hb_buf = hb_buffer_create();
491 error = ta_face_globals_compute_style_coverage(globals);
492 if (error)
494 ta_face_globals_free(globals);
495 globals = NULL;
497 else
498 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
500 Err:
501 *aglobals = globals;
502 return error;
506 void
507 ta_face_globals_free(TA_FaceGlobals globals)
509 if (globals)
511 FT_UInt nn;
514 for (nn = 0; nn < TA_STYLE_MAX; nn++)
516 if (globals->metrics[nn])
518 TA_StyleClass style_class =
519 ta_style_classes[nn];
520 TA_WritingSystemClass writing_system_class =
521 ta_writing_system_classes[style_class->writing_system];
524 if (writing_system_class->style_metrics_done)
525 writing_system_class->style_metrics_done(globals->metrics[nn]);
527 free(globals->metrics[nn]);
531 hb_font_destroy(globals->hb_font);
532 hb_buffer_destroy(globals->hb_buf);
534 /* no need to free `globals->glyph_styles'; */
535 /* it is part of the `globals' array */
536 free(globals);
541 FT_Error
542 ta_face_globals_get_metrics(TA_FaceGlobals globals,
543 FT_UInt gindex,
544 FT_UInt options,
545 TA_StyleMetrics *ametrics)
547 TA_StyleMetrics metrics = NULL;
548 TA_Style style = (TA_Style)options;
549 TA_WritingSystemClass writing_system_class;
550 TA_StyleClass style_class;
551 FT_Error error = FT_Err_Ok;
554 if (gindex >= (FT_ULong)globals->glyph_count)
556 error = FT_Err_Invalid_Argument;
557 goto Exit;
560 /* if we have a forced style (via `options'), use it, */
561 /* otherwise look into `glyph_styles' array */
562 if (style == TA_STYLE_NONE_DFLT || style + 1 >= TA_STYLE_MAX)
563 style = (TA_Style)(globals->glyph_styles[gindex]
564 & TA_STYLE_UNASSIGNED);
566 style_class =
567 ta_style_classes[style];
568 writing_system_class =
569 ta_writing_system_classes[style_class->writing_system];
571 metrics = globals->metrics[style];
572 if (!metrics)
574 /* create the global metrics object if necessary */
575 metrics = (TA_StyleMetrics)
576 calloc(1, writing_system_class->style_metrics_size);
577 if (!metrics)
579 error = FT_Err_Out_Of_Memory;
580 goto Exit;
583 metrics->style_class = style_class;
584 metrics->globals = globals;
586 if (writing_system_class->style_metrics_init)
588 error = writing_system_class->style_metrics_init(
589 metrics,
590 globals->face,
591 globals->font->reference);
592 if (error)
594 if (writing_system_class->style_metrics_done)
595 writing_system_class->style_metrics_done(metrics);
597 free(metrics);
598 metrics = NULL;
599 goto Exit;
603 globals->metrics[style] = metrics;
606 Exit:
607 *ametrics = metrics;
609 return error;
613 FT_Bool
614 ta_face_globals_is_digit(TA_FaceGlobals globals,
615 FT_UInt gindex)
617 if (gindex < (FT_ULong)globals->glyph_count)
618 return (FT_Bool)(globals->glyph_styles[gindex] & TA_DIGIT);
620 return (FT_Bool)0;
623 /* end of taglobal.c */