Synchronize with FreeType.
[ttfautohint.git] / lib / taglobal.c
blobdc6fff58be26f8ca59db741db42b892bf99fd968
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 /* Compute the style index of each glyph within a given face. */
115 static FT_Error
116 ta_face_globals_compute_style_coverage(TA_FaceGlobals globals)
118 FT_Error error;
119 FT_Face face = globals->face;
120 FT_CharMap old_charmap = face->charmap;
121 FT_Byte* gstyles = globals->glyph_styles;
122 FT_UInt ss;
123 FT_UInt i;
124 FT_UInt dflt = -1;
127 /* the value TA_STYLE_UNASSIGNED means `uncovered glyph' */
128 memset(globals->glyph_styles, TA_STYLE_UNASSIGNED, globals->glyph_count);
130 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
131 if (error)
133 /* ignore this error; we simply use the fallback style */
134 /* XXX: Shouldn't we rather disable hinting? */
135 error = FT_Err_Ok;
136 goto Exit;
139 /* scan each style in a Unicode charmap */
140 for (ss = 0; ta_style_classes[ss]; ss++)
142 TA_StyleClass style_class = ta_style_classes[ss];
143 TA_ScriptClass script_class = ta_script_classes[style_class->script];
144 TA_Script_UniRange range;
147 if (script_class->script_uni_ranges == NULL)
148 continue;
150 /* scan all Unicode points in the range and */
151 /* set the corresponding glyph style index */
152 if (style_class->coverage == TA_COVERAGE_DEFAULT)
154 if (style_class->script == globals->font->default_script)
155 dflt = ss;
157 for (range = script_class->script_uni_ranges; range->first != 0; range++)
159 FT_ULong charcode = range->first;
160 FT_UInt gindex;
163 gindex = FT_Get_Char_Index(face, charcode);
165 if (gindex != 0
166 && gindex < (FT_ULong)globals->glyph_count
167 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
168 gstyles[gindex] = (FT_Byte)ss;
170 for (;;)
172 charcode = FT_Get_Next_Char(face, charcode, &gindex);
174 if (gindex == 0 || charcode > range->last)
175 break;
177 if (gindex < (FT_ULong)globals->glyph_count
178 && gstyles[gindex] == TA_STYLE_UNASSIGNED)
179 gstyles[gindex] = (FT_Byte)ss;
183 else
185 /* get glyphs not directly addressable by cmap */
186 ta_get_coverage(globals, style_class, gstyles);
190 /* handle the default OpenType features of the default script ... */
191 ta_get_coverage(globals, ta_style_classes[dflt], gstyles);
193 /* ... and the remaining default OpenType features */
194 for (ss = 0; ta_style_classes[ss]; ss++)
196 TA_StyleClass style_class = ta_style_classes[ss];
199 if (ss != dflt && style_class->coverage == TA_COVERAGE_DEFAULT)
200 ta_get_coverage(globals, style_class, gstyles);
203 /* mark ASCII digits */
204 for (i = 0x30; i <= 0x39; i++)
206 FT_UInt gindex = FT_Get_Char_Index(face, i);
209 if (gindex != 0
210 && gindex < (FT_ULong)globals->glyph_count)
211 gstyles[gindex] |= TA_DIGIT;
214 Exit:
215 /* by default, all uncovered glyphs are set to the fallback style */
216 /* XXX: Shouldn't we disable hinting or do something similar? */
217 if (globals->font->fallback_style != TA_STYLE_UNASSIGNED)
219 FT_Long nn;
222 for (nn = 0; nn < globals->glyph_count; nn++)
224 if ((gstyles[nn] & ~TA_DIGIT) == TA_STYLE_UNASSIGNED)
226 gstyles[nn] &= ~TA_STYLE_UNASSIGNED;
227 gstyles[nn] |= globals->font->fallback_style;
232 #ifdef TA_DEBUG
234 TA_LOG_GLOBAL(("\n"
235 "style coverage\n"
236 "==============\n"
237 "\n"));
239 for (ss = 0; ta_style_classes[ss]; ss++)
241 TA_StyleClass style_class = ta_style_classes[ss];
242 FT_UInt count = 0;
243 FT_Long idx;
246 TA_LOG_GLOBAL(("%s:\n", ta_style_names[style_class->style]));
248 for (idx = 0; idx < globals->glyph_count; idx++)
250 if ((gstyles[idx] & ~TA_DIGIT) == style_class->style)
252 if (!(count % 10))
253 TA_LOG_GLOBAL((" "));
255 TA_LOG_GLOBAL((" %d", idx));
256 count++;
258 if (!(count % 10))
259 TA_LOG_GLOBAL(("\n"));
263 if (!count)
264 TA_LOG_GLOBAL((" (none)\n"));
265 if (count % 10)
266 TA_LOG_GLOBAL(("\n"));
269 #endif /* TA_DEBUG */
271 FT_Set_Charmap(face, old_charmap);
272 return error;
276 FT_Error
277 ta_face_globals_new(FT_Face face,
278 TA_FaceGlobals *aglobals,
279 FONT* font)
281 FT_Error error;
282 TA_FaceGlobals globals;
285 globals = (TA_FaceGlobals)calloc(1, sizeof (TA_FaceGlobalsRec) +
286 face->num_glyphs * sizeof (FT_Byte));
287 if (!globals)
289 error = FT_Err_Out_Of_Memory;
290 goto Err;
293 globals->face = face;
294 globals->glyph_count = face->num_glyphs;
295 globals->glyph_styles = (FT_Byte*)(globals + 1);
296 globals->font = font;
297 globals->hb_font = hb_ft_font_create(face, NULL);
299 error = ta_face_globals_compute_style_coverage(globals);
300 if (error)
302 ta_face_globals_free(globals);
303 globals = NULL;
305 else
306 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
308 Err:
309 *aglobals = globals;
310 return error;
314 void
315 ta_face_globals_free(TA_FaceGlobals globals)
317 if (globals)
319 FT_UInt nn;
322 for (nn = 0; nn < TA_STYLE_MAX; nn++)
324 if (globals->metrics[nn])
326 TA_StyleClass style_class =
327 ta_style_classes[nn];
328 TA_WritingSystemClass writing_system_class =
329 ta_writing_system_classes[style_class->writing_system];
332 if (writing_system_class->style_metrics_done)
333 writing_system_class->style_metrics_done(globals->metrics[nn]);
335 free(globals->metrics[nn]);
336 globals->metrics[nn] = NULL;
340 hb_font_destroy(globals->hb_font);
342 globals->hb_font = NULL;
343 globals->glyph_count = 0;
344 globals->glyph_styles = NULL; /* no need to free this one! */
345 globals->face = NULL;
347 free(globals);
348 globals = NULL;
353 FT_Error
354 ta_face_globals_get_metrics(TA_FaceGlobals globals,
355 FT_UInt gindex,
356 FT_UInt options,
357 TA_StyleMetrics *ametrics)
359 TA_StyleMetrics metrics = NULL;
360 TA_Style style = (TA_Style)options;
361 TA_WritingSystemClass writing_system_class;
362 TA_StyleClass style_class;
363 FT_Error error = FT_Err_Ok;
366 if (gindex >= (FT_ULong)globals->glyph_count)
368 error = FT_Err_Invalid_Argument;
369 goto Exit;
372 /* if we have a forced style (via `options'), use it, */
373 /* otherwise look into `glyph_styles' array */
374 if (style == TA_STYLE_NONE_DFLT || style + 1 >= TA_STYLE_MAX)
375 style = (TA_Style)(globals->glyph_styles[gindex]
376 & TA_STYLE_UNASSIGNED);
378 style_class =
379 ta_style_classes[style];
380 writing_system_class =
381 ta_writing_system_classes[style_class->writing_system];
383 metrics = globals->metrics[style];
384 if (metrics == NULL)
386 /* create the global metrics object if necessary */
387 metrics = (TA_StyleMetrics)
388 calloc(1, writing_system_class->style_metrics_size);
389 if (!metrics)
391 error = FT_Err_Out_Of_Memory;
392 goto Exit;
395 metrics->style_class = style_class;
396 metrics->globals = globals;
398 if (writing_system_class->style_metrics_init)
400 error = writing_system_class->style_metrics_init(metrics,
401 globals->face);
402 if (error)
404 if (writing_system_class->style_metrics_done)
405 writing_system_class->style_metrics_done(metrics);
407 free(metrics);
408 metrics = NULL;
409 goto Exit;
413 globals->metrics[style] = metrics;
416 Exit:
417 *ametrics = metrics;
419 return error;
423 FT_Bool
424 ta_face_globals_is_digit(TA_FaceGlobals globals,
425 FT_UInt gindex)
427 if (gindex < (FT_ULong)globals->glyph_count)
428 return (FT_Bool)(globals->glyph_styles[gindex] & TA_DIGIT);
430 return (FT_Bool)0;
433 /* end of taglobal.c */