dc827eadececf3c2cbbad91dd1b5a3a86566cb17
[ttfautohint.git] / lib / taglobal.c
blobdc827eadececf3c2cbbad91dd1b5a3a86566cb17
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011-2015 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, sc1, sc2, sc3) \
28 const TA_ScriptClassRec ta_ ## s ## _script_class = \
29 { \
30 TA_SCRIPT_ ## S, \
31 ta_ ## s ## _uniranges, \
32 sc1, sc2, sc3 \
35 #include <ttfautohint-scripts.h>
38 #undef STYLE
39 #define STYLE(s, S, d, ws, sc, ss, c) \
40 const TA_StyleClassRec ta_ ## s ## _style_class = \
41 { \
42 TA_STYLE_ ## S, \
43 ws, \
44 sc, \
45 ss, \
46 c \
49 #include "tastyles.h"
52 /* get writing system specific header files */
53 #undef WRITING_SYSTEM
54 #define WRITING_SYSTEM(ws, WS) /* empty */
55 #include "tawrtsys.h"
58 #undef WRITING_SYSTEM
59 #define WRITING_SYSTEM(ws, WS) \
60 &ta_ ## ws ## _writing_system_class,
62 TA_WritingSystemClass const ta_writing_system_classes[] =
65 #include "tawrtsys.h"
67 NULL /* do not remove */
71 #undef SCRIPT
72 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) \
73 &ta_ ## s ## _script_class,
75 TA_ScriptClass const ta_script_classes[] =
78 #include <ttfautohint-scripts.h>
80 NULL /* do not remove */
84 #undef STYLE
85 #define STYLE(s, S, d, ws, sc, ss, c) \
86 &ta_ ## s ## _style_class,
88 TA_StyleClass const ta_style_classes[] =
91 #include "tastyles.h"
93 NULL /* do not remove */
97 #ifdef TA_DEBUG
99 #undef STYLE
100 #define STYLE(s, S, d, ws, sc, ss, c) #s,
102 const char* ta_style_names[] =
105 #include <tastyles.h>
109 #endif /* TA_DEBUG */
112 /* Recursively assign a style to all components of a composite glyph. */
114 static FT_Error
115 ta_face_globals_scan_composite(FT_Face face,
116 FT_Long gindex,
117 FT_Byte gstyle,
118 FT_Byte* gstyles,
119 FT_Int nesting_level)
121 FT_Error error;
122 FT_UInt i;
124 FT_GlyphSlot glyph;
126 FT_Int* subglyph_indices = NULL;
127 FT_UInt used_subglyphs;
129 FT_Int p_index;
130 FT_UInt p_flags;
131 FT_Int p_arg1;
132 FT_Int p_arg2;
133 FT_Matrix p_transform;
136 /* limit recursion arbitrarily */
137 if (nesting_level > 100)
138 return FT_Err_Invalid_Table;
140 error = FT_Load_Glyph(face, (FT_UInt)gindex, FT_LOAD_NO_RECURSE);
141 if (error)
142 return error;
144 glyph = face->glyph;
146 /* in FreeType < 2.5.4, FT_Get_SubGlyph_Info always returns an error */
147 /* due to a bug even if the call was successful; */
148 /* for this reason we do the argument checking by ourselves */
149 /* and ignore the returned error code of FT_Get_SubGlyph_Info */
150 if (!glyph->subglyphs
151 || glyph->format != FT_GLYPH_FORMAT_COMPOSITE)
152 return FT_Err_Ok;
154 /* since a call to FT_Load_Glyph changes `glyph', */
155 /* we have to first store the subglyph indices, then do the recursion */
156 subglyph_indices = (FT_Int*)malloc(sizeof (FT_Int) * glyph->num_subglyphs);
157 if (!subglyph_indices)
158 return FT_Err_Out_Of_Memory;
160 used_subglyphs = 0;
161 for (i = 0; i < glyph->num_subglyphs; i++)
163 (void)FT_Get_SubGlyph_Info(glyph,
165 &p_index,
166 &p_flags,
167 &p_arg1,
168 &p_arg2,
169 &p_transform);
171 if (p_index >= face->num_glyphs
172 || (gstyles[p_index] & ~TA_DIGIT) != TA_STYLE_UNASSIGNED)
173 continue;
175 /* only take subglyphs that are not shifted vertically; */
176 /* otherwise blue zones don't fit */
177 if (p_flags & ARGS_ARE_XY_VALUES
178 && p_arg2 == 0)
180 gstyles[p_index] = gstyle;
181 subglyph_indices[used_subglyphs++] = p_index;
185 /* recurse */
186 for (i = 0; i < used_subglyphs; i++)
188 error = ta_face_globals_scan_composite(face,
189 subglyph_indices[i],
190 gstyle,
191 gstyles,
192 nesting_level + 1);
193 if (error)
194 break;
197 free(subglyph_indices);
199 return error;
203 /* Compute the style index of each glyph within a given face. */
205 static FT_Error
206 ta_face_globals_compute_style_coverage(TA_FaceGlobals globals)
208 FT_Error error;
209 FT_Face face = globals->face;
210 FT_CharMap old_charmap = face->charmap;
211 FT_Byte* gstyles = globals->glyph_styles;
212 FT_UInt ss;
213 FT_UInt i;
214 FT_UInt dflt = ~0U; /* a non-valid value */
217 /* the value TA_STYLE_UNASSIGNED means `uncovered glyph' */
218 memset(globals->glyph_styles,
219 TA_STYLE_UNASSIGNED,
220 (unsigned int)globals->glyph_count);
222 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
223 if (error)
225 /* ignore this error; we simply use the fallback style */
226 /* XXX: Shouldn't we rather disable hinting? */
227 error = FT_Err_Ok;
228 goto Exit;
231 /* scan each style in a Unicode charmap */
232 for (ss = 0; ta_style_classes[ss]; ss++)
234 TA_StyleClass style_class = ta_style_classes[ss];
235 TA_ScriptClass script_class = ta_script_classes[style_class->script];
236 TA_Script_UniRange range;
239 if (script_class->script_uni_ranges == NULL)
240 continue;
242 /* scan all Unicode points in the range and */
243 /* set the corresponding glyph style index */
244 if (style_class->coverage == TA_COVERAGE_DEFAULT)
246 if ((FT_UInt)style_class->script == globals->font->default_script)
247 dflt = ss;
249 for (range = script_class->script_uni_ranges; range->first != 0; range++)
251 FT_ULong charcode = range->first;
252 FT_UInt gindex;
255 gindex = FT_Get_Char_Index(face, charcode);
257 if (gindex != 0
258 && gindex < (FT_ULong)globals->glyph_count
259 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
260 gstyles[gindex] = (FT_Byte)ss;
262 for (;;)
264 charcode = FT_Get_Next_Char(face, charcode, &gindex);
266 if (gindex == 0 || charcode > range->last)
267 break;
269 if (gindex < (FT_ULong)globals->glyph_count
270 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
271 gstyles[gindex] = (FT_Byte)ss;
275 else
277 /* get glyphs not directly addressable by cmap */
278 ta_get_coverage(globals, style_class, gstyles);
282 /* handle the default OpenType features of the default script ... */
283 ta_get_coverage(globals, ta_style_classes[dflt], gstyles);
285 /* ... and the remaining default OpenType features */
286 for (ss = 0; ta_style_classes[ss]; ss++)
288 TA_StyleClass style_class = ta_style_classes[ss];
291 if (ss != dflt && style_class->coverage == TA_COVERAGE_DEFAULT)
292 ta_get_coverage(globals, style_class, gstyles);
295 /* mark ASCII digits */
296 for (i = 0x30; i <= 0x39; i++)
298 FT_UInt gindex = FT_Get_Char_Index(face, i);
301 if (gindex != 0
302 && gindex < (FT_ULong)globals->glyph_count)
303 gstyles[gindex] |= TA_DIGIT;
306 /* now walk over all glyphs and check for composites: */
307 /* since subglyphs are hinted separately if option `hint-composites' */
308 /* isn't set, we have to tag them with style indices, too */
310 FT_Long nn;
313 for (nn = 0; nn < globals->glyph_count; nn++)
315 if ((gstyles[nn] & ~TA_DIGIT) == TA_STYLE_UNASSIGNED)
316 continue;
318 error = ta_face_globals_scan_composite(globals->face,
320 gstyles[nn],
321 gstyles,
323 if (error)
324 return error;
328 Exit:
329 /* by default, all uncovered glyphs are set to the fallback style */
330 /* XXX: Shouldn't we disable hinting or do something similar? */
331 if (globals->font->fallback_style != (TA_Style)TA_STYLE_UNASSIGNED)
333 FT_Long nn;
336 for (nn = 0; nn < globals->glyph_count; nn++)
338 if ((gstyles[nn] & ~TA_DIGIT) == TA_STYLE_UNASSIGNED)
340 gstyles[nn] &= ~TA_STYLE_UNASSIGNED;
341 gstyles[nn] |= globals->font->fallback_style;
346 #ifdef TA_DEBUG
348 if (face->num_faces > 1)
349 TA_LOG_GLOBAL(("\n"
350 "style coverage (subfont %d, glyf table index %d)\n"
351 "================================================\n"
352 "\n",
353 face->face_index,
354 globals->font->sfnts[face->face_index].glyf_idx));
355 else
356 TA_LOG_GLOBAL(("\n"
357 "style coverage\n"
358 "==============\n"
359 "\n"));
361 for (ss = 0; ta_style_classes[ss]; ss++)
363 TA_StyleClass style_class = ta_style_classes[ss];
364 FT_UInt count = 0;
365 FT_Long idx;
368 TA_LOG_GLOBAL(("%s:\n", ta_style_names[style_class->style]));
370 for (idx = 0; idx < globals->glyph_count; idx++)
372 if ((gstyles[idx] & ~TA_DIGIT) == style_class->style)
374 if (!(count % 10))
375 TA_LOG_GLOBAL((" "));
377 TA_LOG_GLOBAL((" %d", idx));
378 count++;
380 if (!(count % 10))
381 TA_LOG_GLOBAL(("\n"));
385 if (!count)
386 TA_LOG_GLOBAL((" (none)\n"));
387 if (count % 10)
388 TA_LOG_GLOBAL(("\n"));
391 #endif /* TA_DEBUG */
393 FT_Set_Charmap(face, old_charmap);
394 return error;
398 FT_Error
399 ta_face_globals_new(FT_Face face,
400 TA_FaceGlobals *aglobals,
401 FONT* font)
403 FT_Error error;
404 TA_FaceGlobals globals;
407 globals = (TA_FaceGlobals)calloc(
408 1, sizeof (TA_FaceGlobalsRec) +
409 (FT_ULong)face->num_glyphs * sizeof (FT_Byte));
410 if (!globals)
412 error = FT_Err_Out_Of_Memory;
413 goto Err;
416 globals->face = face;
417 globals->glyph_count = face->num_glyphs;
418 globals->glyph_styles = (FT_Byte*)(globals + 1);
419 globals->font = font;
420 globals->hb_font = hb_ft_font_create(face, NULL);
422 error = ta_face_globals_compute_style_coverage(globals);
423 if (error)
425 ta_face_globals_free(globals);
426 globals = NULL;
428 else
429 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
431 Err:
432 *aglobals = globals;
433 return error;
437 void
438 ta_face_globals_free(TA_FaceGlobals globals)
440 if (globals)
442 FT_UInt nn;
445 for (nn = 0; nn < TA_STYLE_MAX; nn++)
447 if (globals->metrics[nn])
449 TA_StyleClass style_class =
450 ta_style_classes[nn];
451 TA_WritingSystemClass writing_system_class =
452 ta_writing_system_classes[style_class->writing_system];
455 if (writing_system_class->style_metrics_done)
456 writing_system_class->style_metrics_done(globals->metrics[nn]);
458 free(globals->metrics[nn]);
459 globals->metrics[nn] = NULL;
463 hb_font_destroy(globals->hb_font);
465 globals->hb_font = NULL;
466 globals->glyph_count = 0;
467 globals->glyph_styles = NULL; /* no need to free this one! */
468 globals->face = NULL;
470 free(globals);
475 FT_Error
476 ta_face_globals_get_metrics(TA_FaceGlobals globals,
477 FT_UInt gindex,
478 FT_UInt options,
479 TA_StyleMetrics *ametrics)
481 TA_StyleMetrics metrics = NULL;
482 TA_Style style = (TA_Style)options;
483 TA_WritingSystemClass writing_system_class;
484 TA_StyleClass style_class;
485 FT_Error error = FT_Err_Ok;
488 if (gindex >= (FT_ULong)globals->glyph_count)
490 error = FT_Err_Invalid_Argument;
491 goto Exit;
494 /* if we have a forced style (via `options'), use it, */
495 /* otherwise look into `glyph_styles' array */
496 if (style == TA_STYLE_NONE_DFLT || style + 1 >= TA_STYLE_MAX)
497 style = (TA_Style)(globals->glyph_styles[gindex]
498 & TA_STYLE_UNASSIGNED);
500 style_class =
501 ta_style_classes[style];
502 writing_system_class =
503 ta_writing_system_classes[style_class->writing_system];
505 metrics = globals->metrics[style];
506 if (metrics == NULL)
508 /* create the global metrics object if necessary */
509 metrics = (TA_StyleMetrics)
510 calloc(1, writing_system_class->style_metrics_size);
511 if (!metrics)
513 error = FT_Err_Out_Of_Memory;
514 goto Exit;
517 metrics->style_class = style_class;
518 metrics->globals = globals;
520 if (writing_system_class->style_metrics_init)
522 error = writing_system_class->style_metrics_init(metrics,
523 globals->face);
524 if (error)
526 if (writing_system_class->style_metrics_done)
527 writing_system_class->style_metrics_done(metrics);
529 free(metrics);
530 metrics = NULL;
531 goto Exit;
535 globals->metrics[style] = metrics;
538 Exit:
539 *ametrics = metrics;
541 return error;
545 FT_Bool
546 ta_face_globals_is_digit(TA_FaceGlobals globals,
547 FT_UInt gindex)
549 if (gindex < (FT_ULong)globals->glyph_count)
550 return (FT_Bool)(globals->glyph_styles[gindex] & TA_DIGIT);
552 return (FT_Bool)0;
555 /* end of taglobal.c */