Fix thinko in coverage handling of TTCs.
[ttfautohint.git] / lib / taglobal.c
blob10cf521131935ddf54e1d0d1a8e470b71483d761
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011-2014 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"
24 #include "taharfbuzz.h"
27 #undef SCRIPT
28 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) \
29 const TA_ScriptClassRec ta_ ## s ## _script_class = \
30 { \
31 TA_SCRIPT_ ## S, \
32 ta_ ## s ## _uniranges, \
33 sc1, sc2, sc3 \
36 #include <ttfautohint-scripts.h>
39 #undef STYLE
40 #define STYLE(s, S, d, ws, sc, ss, c) \
41 const TA_StyleClassRec ta_ ## s ## _style_class = \
42 { \
43 TA_STYLE_ ## S, \
44 ws, \
45 sc, \
46 ss, \
47 c \
50 #include "tastyles.h"
53 /* get writing system specific header files */
54 #undef WRITING_SYSTEM
55 #define WRITING_SYSTEM(ws, WS) /* empty */
56 #include "tawrtsys.h"
59 #undef WRITING_SYSTEM
60 #define WRITING_SYSTEM(ws, WS) \
61 &ta_ ## ws ## _writing_system_class,
63 TA_WritingSystemClass const ta_writing_system_classes[] =
66 #include "tawrtsys.h"
68 NULL /* do not remove */
72 #undef SCRIPT
73 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) \
74 &ta_ ## s ## _script_class,
76 TA_ScriptClass const ta_script_classes[] =
79 #include <ttfautohint-scripts.h>
81 NULL /* do not remove */
85 #undef STYLE
86 #define STYLE(s, S, d, ws, sc, ss, c) \
87 &ta_ ## s ## _style_class,
89 TA_StyleClass const ta_style_classes[] =
92 #include "tastyles.h"
94 NULL /* do not remove */
98 #ifdef TA_DEBUG
100 #undef STYLE
101 #define STYLE(s, S, d, ws, sc, ss, c) #s,
103 const char* ta_style_names[] =
106 #include <tastyles.h>
110 #endif /* TA_DEBUG */
113 /* Recursively assign a style to all components of a composite glyph. */
115 static FT_Error
116 ta_face_globals_scan_composite(FT_Face face,
117 FT_Long gindex,
118 FT_Byte gstyle,
119 FT_Byte* gstyles,
120 FT_Int nesting_level)
122 FT_Error error;
123 FT_UInt i;
125 FT_GlyphSlot glyph;
127 FT_Int* subglyph_indices = NULL;
128 FT_UInt used_subglyphs;
130 FT_Int p_index;
131 FT_UInt p_flags;
132 FT_Int p_arg1;
133 FT_Int p_arg2;
134 FT_Matrix p_transform;
137 /* limit recursion arbitrarily */
138 if (nesting_level > 100)
139 return FT_Err_Invalid_Table;
141 error = FT_Load_Glyph(face, gindex, FT_LOAD_NO_RECURSE);
142 if (error)
143 return error;
145 glyph = face->glyph;
147 /* in FreeType < 2.5.4, FT_Get_SubGlyph_Info always returns an error */
148 /* due to a bug even if the call was successful; */
149 /* for this reason we do the argument checking by ourselves */
150 /* and ignore the returned error code of FT_Get_SubGlyph_Info */
151 if (!glyph->subglyphs
152 || glyph->format != FT_GLYPH_FORMAT_COMPOSITE)
153 return FT_Err_Ok;
155 /* since a call to FT_Load_Glyph changes `glyph', */
156 /* we have to first store the subglyph indices, then do the recursion */
157 subglyph_indices = (FT_Int*)malloc(sizeof (FT_Int) * glyph->num_subglyphs);
158 if (!subglyph_indices)
159 return FT_Err_Out_Of_Memory;
161 used_subglyphs = 0;
162 for (i = 0; i < glyph->num_subglyphs; i++)
164 (void)FT_Get_SubGlyph_Info(glyph,
166 &p_index,
167 &p_flags,
168 &p_arg1,
169 &p_arg2,
170 &p_transform);
172 if (p_index >= face->num_glyphs
173 || (gstyles[p_index] & ~TA_DIGIT) != TA_STYLE_UNASSIGNED)
174 continue;
176 /* only take subglyphs that are not shifted vertically; */
177 /* otherwise blue zones don't fit */
178 if (p_flags & ARGS_ARE_XY_VALUES
179 && p_arg2 == 0)
181 gstyles[p_index] = gstyle;
182 subglyph_indices[used_subglyphs++] = p_index;
186 /* recurse */
187 for (i = 0; i < used_subglyphs; i++)
189 error = ta_face_globals_scan_composite(face,
190 subglyph_indices[i],
191 gstyle,
192 gstyles,
193 nesting_level + 1);
194 if (error)
195 break;
198 free(subglyph_indices);
200 return error;
204 /* Compute the style index of each glyph within a given face. */
206 static FT_Error
207 ta_face_globals_compute_style_coverage(TA_FaceGlobals globals)
209 FT_Error error;
210 FT_Face face = globals->face;
211 FT_CharMap old_charmap = face->charmap;
212 FT_Byte* gstyles = globals->glyph_styles;
213 FT_UInt ss;
214 FT_UInt i;
215 FT_UInt dflt = -1;
218 /* the value TA_STYLE_UNASSIGNED means `uncovered glyph' */
219 memset(globals->glyph_styles, TA_STYLE_UNASSIGNED, globals->glyph_count);
221 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
222 if (error)
224 /* ignore this error; we simply use the fallback style */
225 /* XXX: Shouldn't we rather disable hinting? */
226 error = FT_Err_Ok;
227 goto Exit;
230 /* scan each style in a Unicode charmap */
231 for (ss = 0; ta_style_classes[ss]; ss++)
233 TA_StyleClass style_class = ta_style_classes[ss];
234 TA_ScriptClass script_class = ta_script_classes[style_class->script];
235 TA_Script_UniRange range;
238 if (script_class->script_uni_ranges == NULL)
239 continue;
241 /* scan all Unicode points in the range and */
242 /* set the corresponding glyph style index */
243 if (style_class->coverage == TA_COVERAGE_DEFAULT)
245 if (style_class->script == globals->font->default_script)
246 dflt = ss;
248 for (range = script_class->script_uni_ranges; range->first != 0; range++)
250 FT_ULong charcode = range->first;
251 FT_UInt gindex;
254 gindex = FT_Get_Char_Index(face, charcode);
256 if (gindex != 0
257 && gindex < (FT_ULong)globals->glyph_count
258 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
259 gstyles[gindex] = (FT_Byte)ss;
261 for (;;)
263 charcode = FT_Get_Next_Char(face, charcode, &gindex);
265 if (gindex == 0 || charcode > range->last)
266 break;
268 if (gindex < (FT_ULong)globals->glyph_count
269 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
270 gstyles[gindex] = (FT_Byte)ss;
274 else
276 /* get glyphs not directly addressable by cmap */
277 ta_get_coverage(globals, style_class, gstyles);
281 /* handle the default OpenType features of the default script ... */
282 ta_get_coverage(globals, ta_style_classes[dflt], gstyles);
284 /* ... and the remaining default OpenType features */
285 for (ss = 0; ta_style_classes[ss]; ss++)
287 TA_StyleClass style_class = ta_style_classes[ss];
290 if (ss != dflt && style_class->coverage == TA_COVERAGE_DEFAULT)
291 ta_get_coverage(globals, style_class, gstyles);
294 /* mark ASCII digits */
295 for (i = 0x30; i <= 0x39; i++)
297 FT_UInt gindex = FT_Get_Char_Index(face, i);
300 if (gindex != 0
301 && gindex < (FT_ULong)globals->glyph_count)
302 gstyles[gindex] |= TA_DIGIT;
305 /* now walk over all glyphs and check for composites: */
306 /* since subglyphs are hinted separately if option `hint-composites' */
307 /* isn't set, we have to tag them with style indices, too */
309 FT_Long nn;
312 for (nn = 0; nn < globals->glyph_count; nn++)
314 if ((gstyles[nn] & ~TA_DIGIT) == TA_STYLE_UNASSIGNED)
315 continue;
317 error = ta_face_globals_scan_composite(globals->face,
319 gstyles[nn],
320 gstyles,
322 if (error)
323 return error;
327 Exit:
328 /* by default, all uncovered glyphs are set to the fallback style */
329 /* XXX: Shouldn't we disable hinting or do something similar? */
330 if (globals->font->fallback_style != TA_STYLE_UNASSIGNED)
332 FT_Long nn;
335 for (nn = 0; nn < globals->glyph_count; nn++)
337 if ((gstyles[nn] & ~TA_DIGIT) == TA_STYLE_UNASSIGNED)
339 gstyles[nn] &= ~TA_STYLE_UNASSIGNED;
340 gstyles[nn] |= globals->font->fallback_style;
345 #ifdef TA_DEBUG
347 if (face->num_faces > 1)
348 TA_LOG_GLOBAL(("\n"
349 "style coverage (subfont %d, glyf table index %d)\n"
350 "================================================\n"
351 "\n",
352 face->face_index,
353 globals->font->sfnts[face->face_index].glyf_idx));
354 else
355 TA_LOG_GLOBAL(("\n"
356 "style coverage\n"
357 "==============\n"
358 "\n"));
360 for (ss = 0; ta_style_classes[ss]; ss++)
362 TA_StyleClass style_class = ta_style_classes[ss];
363 FT_UInt count = 0;
364 FT_Long idx;
367 TA_LOG_GLOBAL(("%s:\n", ta_style_names[style_class->style]));
369 for (idx = 0; idx < globals->glyph_count; idx++)
371 if ((gstyles[idx] & ~TA_DIGIT) == style_class->style)
373 if (!(count % 10))
374 TA_LOG_GLOBAL((" "));
376 TA_LOG_GLOBAL((" %d", idx));
377 count++;
379 if (!(count % 10))
380 TA_LOG_GLOBAL(("\n"));
384 if (!count)
385 TA_LOG_GLOBAL((" (none)\n"));
386 if (count % 10)
387 TA_LOG_GLOBAL(("\n"));
390 #endif /* TA_DEBUG */
392 FT_Set_Charmap(face, old_charmap);
393 return error;
397 FT_Error
398 ta_face_globals_new(FT_Face face,
399 TA_FaceGlobals *aglobals,
400 FONT* font)
402 FT_Error error;
403 TA_FaceGlobals globals;
406 globals = (TA_FaceGlobals)calloc(1, sizeof (TA_FaceGlobalsRec) +
407 face->num_glyphs * sizeof (FT_Byte));
408 if (!globals)
410 error = FT_Err_Out_Of_Memory;
411 goto Err;
414 globals->face = face;
415 globals->glyph_count = face->num_glyphs;
416 globals->glyph_styles = (FT_Byte*)(globals + 1);
417 globals->font = font;
418 globals->hb_font = hb_ft_font_create(face, NULL);
420 error = ta_face_globals_compute_style_coverage(globals);
421 if (error)
423 ta_face_globals_free(globals);
424 globals = NULL;
426 else
427 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
429 Err:
430 *aglobals = globals;
431 return error;
435 void
436 ta_face_globals_free(TA_FaceGlobals globals)
438 if (globals)
440 FT_UInt nn;
443 for (nn = 0; nn < TA_STYLE_MAX; nn++)
445 if (globals->metrics[nn])
447 TA_StyleClass style_class =
448 ta_style_classes[nn];
449 TA_WritingSystemClass writing_system_class =
450 ta_writing_system_classes[style_class->writing_system];
453 if (writing_system_class->style_metrics_done)
454 writing_system_class->style_metrics_done(globals->metrics[nn]);
456 free(globals->metrics[nn]);
457 globals->metrics[nn] = NULL;
461 hb_font_destroy(globals->hb_font);
463 globals->hb_font = NULL;
464 globals->glyph_count = 0;
465 globals->glyph_styles = NULL; /* no need to free this one! */
466 globals->face = NULL;
468 free(globals);
469 globals = NULL;
474 FT_Error
475 ta_face_globals_get_metrics(TA_FaceGlobals globals,
476 FT_UInt gindex,
477 FT_UInt options,
478 TA_StyleMetrics *ametrics)
480 TA_StyleMetrics metrics = NULL;
481 TA_Style style = (TA_Style)options;
482 TA_WritingSystemClass writing_system_class;
483 TA_StyleClass style_class;
484 FT_Error error = FT_Err_Ok;
487 if (gindex >= (FT_ULong)globals->glyph_count)
489 error = FT_Err_Invalid_Argument;
490 goto Exit;
493 /* if we have a forced style (via `options'), use it, */
494 /* otherwise look into `glyph_styles' array */
495 if (style == TA_STYLE_NONE_DFLT || style + 1 >= TA_STYLE_MAX)
496 style = (TA_Style)(globals->glyph_styles[gindex]
497 & TA_STYLE_UNASSIGNED);
499 style_class =
500 ta_style_classes[style];
501 writing_system_class =
502 ta_writing_system_classes[style_class->writing_system];
504 metrics = globals->metrics[style];
505 if (metrics == NULL)
507 /* create the global metrics object if necessary */
508 metrics = (TA_StyleMetrics)
509 calloc(1, writing_system_class->style_metrics_size);
510 if (!metrics)
512 error = FT_Err_Out_Of_Memory;
513 goto Exit;
516 metrics->style_class = style_class;
517 metrics->globals = globals;
519 if (writing_system_class->style_metrics_init)
521 error = writing_system_class->style_metrics_init(metrics,
522 globals->face);
523 if (error)
525 if (writing_system_class->style_metrics_done)
526 writing_system_class->style_metrics_done(metrics);
528 free(metrics);
529 metrics = NULL;
530 goto Exit;
534 globals->metrics[style] = metrics;
537 Exit:
538 *ametrics = metrics;
540 return error;
544 FT_Bool
545 ta_face_globals_is_digit(TA_FaceGlobals globals,
546 FT_UInt gindex)
548 if (gindex < (FT_ULong)globals->glyph_count)
549 return (FT_Bool)(globals->glyph_styles[gindex] & TA_DIGIT);
551 return (FT_Bool)0;
554 /* end of taglobal.c */