Synchronize with FreeType.
[ttfautohint.git] / lib / taglobal.c
blob84ef5887590edffb7f005b84a891e2deae98ab69
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011-2016 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 TA_ScriptClass script_class = ta_script_classes[style_class->script];
237 TA_Script_UniRange range;
240 if (script_class->script_uni_ranges->first == 0)
241 continue;
243 /* scan all Unicode points in the range and */
244 /* set the corresponding glyph style index */
245 if (style_class->coverage == TA_COVERAGE_DEFAULT)
247 if ((FT_UInt)style_class->script == globals->font->default_script)
248 dflt = ss;
250 for (range = script_class->script_uni_ranges;
251 range->first != 0;
252 range++)
254 FT_ULong charcode = range->first;
255 FT_UInt gindex;
258 gindex = FT_Get_Char_Index(face, charcode);
260 if (gindex != 0
261 && gindex < (FT_ULong)globals->glyph_count
262 && (gstyles[gindex] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
263 gstyles[gindex] = (FT_UShort)ss;
265 for (;;)
267 charcode = FT_Get_Next_Char(face, charcode, &gindex);
269 if (gindex == 0 || charcode > range->last)
270 break;
272 if (gindex < (FT_ULong)globals->glyph_count
273 && (gstyles[gindex] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
274 gstyles[gindex] = (FT_UShort)ss;
278 /* do the same for the script's non-base characters */
279 for (range = script_class->script_uni_nonbase_ranges;
280 range->first != 0;
281 range++)
283 FT_ULong charcode = range->first;
284 FT_UInt gindex;
287 gindex = FT_Get_Char_Index(face, charcode);
289 if (gindex != 0
290 && gindex < (FT_ULong)globals->glyph_count
291 && (gstyles[gindex] & TA_STYLE_MASK) == (FT_UShort)ss)
292 gstyles[gindex] |= TA_NONBASE;
294 for (;;)
296 charcode = FT_Get_Next_Char(face, charcode, &gindex);
298 if (gindex == 0 || charcode > range->last)
299 break;
301 if (gindex < (FT_ULong)globals->glyph_count
302 && (gstyles[gindex] & TA_STYLE_MASK) == (FT_UShort)ss)
303 gstyles[gindex] |= TA_NONBASE;
307 else
309 /* get glyphs not directly addressable by cmap */
310 ta_shaper_get_coverage(globals, style_class, gstyles, 0);
314 /* handle the remaining default OpenType features ... */
315 for (ss = 0; ta_style_classes[ss]; ss++)
317 TA_StyleClass style_class = ta_style_classes[ss];
320 if (style_class->coverage == TA_COVERAGE_DEFAULT)
321 ta_shaper_get_coverage(globals, style_class, gstyles, 0);
324 /* ... and finally the default OpenType features of the default script */
325 ta_shaper_get_coverage(globals, ta_style_classes[dflt], gstyles, 1);
327 /* mark ASCII digits */
328 for (i = 0x30; i <= 0x39; i++)
330 FT_UInt gindex = FT_Get_Char_Index(face, i);
333 if (gindex != 0
334 && gindex < (FT_ULong)globals->glyph_count)
335 gstyles[gindex] |= TA_DIGIT;
338 /* now walk over all glyphs and check for composites: */
339 /* since subglyphs are hinted separately if option `hint-composites' */
340 /* isn't set, we have to tag them with style indices, too */
342 FT_Long nn;
345 for (nn = 0; nn < globals->glyph_count; nn++)
347 if ((gstyles[nn] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
348 continue;
350 error = ta_face_globals_scan_composite(globals->face,
352 gstyles[nn],
353 gstyles,
355 if (error)
356 return error;
360 Exit:
361 /* by default, all uncovered glyphs are set to the fallback style */
362 /* XXX: Shouldn't we disable hinting or do something similar? */
363 if (globals->font->fallback_style != (TA_Style)TA_STYLE_UNASSIGNED)
365 FT_Long nn;
368 for (nn = 0; nn < globals->glyph_count; nn++)
370 if ((gstyles[nn] & TA_STYLE_MASK) == TA_STYLE_UNASSIGNED)
372 gstyles[nn] &= ~TA_STYLE_MASK;
373 gstyles[nn] |= globals->font->fallback_style;
378 #ifdef TA_DEBUG
380 if (face->num_faces > 1)
381 TA_LOG_GLOBAL(("\n"
382 "style coverage (subfont %d, glyf table index %d)\n"
383 "================================================\n"
384 "\n",
385 face->face_index,
386 globals->font->sfnts[face->face_index].glyf_idx));
387 else
388 TA_LOG_GLOBAL(("\n"
389 "style coverage\n"
390 "==============\n"
391 "\n"));
393 for (ss = 0; ta_style_classes[ss]; ss++)
395 TA_StyleClass style_class = ta_style_classes[ss];
396 FT_UInt count = 0;
397 FT_Long idx;
400 TA_LOG_GLOBAL(("%s:\n", ta_style_names[style_class->style]));
402 for (idx = 0; idx < globals->glyph_count; idx++)
404 if ((gstyles[idx] & TA_STYLE_MASK) == style_class->style)
406 if (!(count % 10))
407 TA_LOG_GLOBAL((" "));
409 TA_LOG_GLOBAL((" %d", idx));
410 count++;
412 if (!(count % 10))
413 TA_LOG_GLOBAL(("\n"));
417 if (!count)
418 TA_LOG_GLOBAL((" (none)\n"));
419 if (count % 10)
420 TA_LOG_GLOBAL(("\n"));
423 #endif /* TA_DEBUG */
425 FT_Set_Charmap(face, old_charmap);
426 return error;
430 FT_Error
431 ta_face_globals_new(FT_Face face,
432 TA_FaceGlobals *aglobals,
433 FONT* font)
435 FT_Error error;
436 TA_FaceGlobals globals;
439 /* we allocate an TA_FaceGlobals structure together */
440 /* with the glyph_styles array */
441 globals = (TA_FaceGlobals)calloc(
442 1, sizeof (TA_FaceGlobalsRec) +
443 (FT_ULong)face->num_glyphs * sizeof (FT_UShort));
444 if (!globals)
446 error = FT_Err_Out_Of_Memory;
447 goto Err;
450 globals->face = face;
451 globals->glyph_count = face->num_glyphs;
452 /* right after the globals structure come the glyph styles */
453 globals->glyph_styles = (FT_UShort*)(globals + 1);
454 globals->font = font;
455 globals->hb_font = hb_ft_font_create(face, NULL);
456 globals->hb_buf = hb_buffer_create();
458 error = ta_face_globals_compute_style_coverage(globals);
459 if (error)
461 ta_face_globals_free(globals);
462 globals = NULL;
464 else
465 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
467 Err:
468 *aglobals = globals;
469 return error;
473 void
474 ta_face_globals_free(TA_FaceGlobals globals)
476 if (globals)
478 FT_UInt nn;
481 for (nn = 0; nn < TA_STYLE_MAX; nn++)
483 if (globals->metrics[nn])
485 TA_StyleClass style_class =
486 ta_style_classes[nn];
487 TA_WritingSystemClass writing_system_class =
488 ta_writing_system_classes[style_class->writing_system];
491 if (writing_system_class->style_metrics_done)
492 writing_system_class->style_metrics_done(globals->metrics[nn]);
494 free(globals->metrics[nn]);
495 globals->metrics[nn] = NULL;
499 hb_font_destroy(globals->hb_font);
500 globals->hb_font = NULL;
502 hb_buffer_destroy(globals->hb_buf);
503 globals->hb_buf = NULL;
505 globals->glyph_count = 0;
506 globals->glyph_styles = NULL; /* no need to free this one! */
507 globals->face = NULL;
509 free(globals);
514 FT_Error
515 ta_face_globals_get_metrics(TA_FaceGlobals globals,
516 FT_UInt gindex,
517 FT_UInt options,
518 TA_StyleMetrics *ametrics)
520 TA_StyleMetrics metrics = NULL;
521 TA_Style style = (TA_Style)options;
522 TA_WritingSystemClass writing_system_class;
523 TA_StyleClass style_class;
524 FT_Error error = FT_Err_Ok;
527 if (gindex >= (FT_ULong)globals->glyph_count)
529 error = FT_Err_Invalid_Argument;
530 goto Exit;
533 /* if we have a forced style (via `options'), use it, */
534 /* otherwise look into `glyph_styles' array */
535 if (style == TA_STYLE_NONE_DFLT || style + 1 >= TA_STYLE_MAX)
536 style = (TA_Style)(globals->glyph_styles[gindex]
537 & TA_STYLE_UNASSIGNED);
539 style_class =
540 ta_style_classes[style];
541 writing_system_class =
542 ta_writing_system_classes[style_class->writing_system];
544 metrics = globals->metrics[style];
545 if (metrics == NULL)
547 /* create the global metrics object if necessary */
548 metrics = (TA_StyleMetrics)
549 calloc(1, writing_system_class->style_metrics_size);
550 if (!metrics)
552 error = FT_Err_Out_Of_Memory;
553 goto Exit;
556 metrics->style_class = style_class;
557 metrics->globals = globals;
559 if (writing_system_class->style_metrics_init)
561 error = writing_system_class->style_metrics_init(metrics,
562 globals->face);
563 if (error)
565 if (writing_system_class->style_metrics_done)
566 writing_system_class->style_metrics_done(metrics);
568 free(metrics);
569 metrics = NULL;
570 goto Exit;
574 globals->metrics[style] = metrics;
577 Exit:
578 *ametrics = metrics;
580 return error;
584 FT_Bool
585 ta_face_globals_is_digit(TA_FaceGlobals globals,
586 FT_UInt gindex)
588 if (gindex < (FT_ULong)globals->glyph_count)
589 return (FT_Bool)(globals->glyph_styles[gindex] & TA_DIGIT);
591 return (FT_Bool)0;
594 /* end of taglobal.c */