Synchronize with FreeType.
[ttfautohint.git] / lib / taglobal.c
blob1e92bc8323a7a8608f4ddc456a4b7dc9a36f5163
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011-2013 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"
24 /* get writing system specific header files */
25 #undef WRITING_SYSTEM
26 #define WRITING_SYSTEM(ws, WS) /* empty */
27 #include "tawrtsys.h"
30 #undef WRITING_SYSTEM
31 #define WRITING_SYSTEM(ws, WS) \
32 &ta_ ## ws ## _writing_system_class,
34 TA_WritingSystemClass const ta_writing_system_classes[] =
37 #include "tawrtsys.h"
39 NULL /* do not remove */
43 #undef SCRIPT
44 #define SCRIPT(s, S, d) \
45 &ta_ ## s ## _script_class,
47 TA_ScriptClass const ta_script_classes[] =
50 #include "tascript.h"
52 NULL /* do not remove */
56 #ifdef TA_DEBUG
58 #undef SCRIPT
59 #define SCRIPT(s, S, d) #s,
61 const char* ta_script_names[] =
64 #include "tascript.h"
68 #endif /* TA_DEBUG */
71 /* Compute the script index of each glyph within a given face. */
73 static FT_Error
74 ta_face_globals_compute_script_coverage(TA_FaceGlobals globals)
76 FT_Error error;
77 FT_Face face = globals->face;
78 FT_CharMap old_charmap = face->charmap;
79 FT_Byte* gscripts = globals->glyph_scripts;
80 FT_UInt ss;
81 FT_UInt i;
84 /* the value TA_SCRIPT_NONE means `uncovered glyph' */
85 memset(globals->glyph_scripts, TA_SCRIPT_NONE, globals->glyph_count);
87 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
88 if (error)
90 /* ignore this error; we simply use the fallback script */
91 /* XXX: Shouldn't we rather disable hinting? */
92 error = FT_Err_Ok;
93 goto Exit;
96 /* scan each script in a Unicode charmap */
97 for (ss = 0; ta_script_classes[ss]; ss++)
99 TA_ScriptClass script_class = ta_script_classes[ss];
100 TA_Script_UniRange range;
103 if (script_class->script_uni_ranges == NULL)
104 continue;
106 /* scan all Unicode points in the range and */
107 /* set the corresponding glyph script index */
108 for (range = script_class->script_uni_ranges; range->first != 0; range++)
110 FT_ULong charcode = range->first;
111 FT_UInt gindex;
114 gindex = FT_Get_Char_Index(face, charcode);
116 if (gindex != 0
117 && gindex < (FT_ULong)globals->glyph_count
118 && gscripts[gindex] == TA_SCRIPT_NONE)
119 gscripts[gindex] = (FT_Byte)ss;
121 for (;;)
123 charcode = FT_Get_Next_Char(face, charcode, &gindex);
125 if (gindex == 0 || charcode > range->last)
126 break;
128 if (gindex < (FT_ULong)globals->glyph_count
129 && gscripts[gindex] == TA_SCRIPT_NONE)
130 gscripts[gindex] = (FT_Byte)ss;
135 /* mark ASCII digits */
136 for (i = 0x30; i <= 0x39; i++)
138 FT_UInt gindex = FT_Get_Char_Index(face, i);
141 if (gindex != 0
142 && gindex < (FT_ULong)globals->glyph_count)
143 gscripts[gindex] |= TA_DIGIT;
146 Exit:
147 /* by default, all uncovered glyphs are set to the fallback script */
148 /* XXX: Shouldn't we disable hinting or do something similar? */
149 if (globals->font->fallback_script != TA_SCRIPT_NONE)
151 FT_Long nn;
154 for (nn = 0; nn < globals->glyph_count; nn++)
156 if ((gscripts[nn] & ~TA_DIGIT) == TA_SCRIPT_NONE)
158 gscripts[nn] &= ~TA_SCRIPT_NONE;
159 gscripts[nn] |= globals->font->fallback_script;
164 FT_Set_Charmap(face, old_charmap);
165 return error;
169 FT_Error
170 ta_face_globals_new(FT_Face face,
171 TA_FaceGlobals *aglobals,
172 FONT* font)
174 FT_Error error;
175 TA_FaceGlobals globals;
178 globals = (TA_FaceGlobals)calloc(1, sizeof (TA_FaceGlobalsRec) +
179 face->num_glyphs * sizeof (FT_Byte));
180 if (!globals)
182 error = FT_Err_Out_Of_Memory;
183 goto Err;
186 globals->face = face;
187 globals->glyph_count = face->num_glyphs;
188 globals->glyph_scripts = (FT_Byte*)(globals + 1);
189 globals->font = font;
191 error = ta_face_globals_compute_script_coverage(globals);
192 if (error)
194 ta_face_globals_free(globals);
195 globals = NULL;
198 globals->increase_x_height = TA_PROP_INCREASE_X_HEIGHT_MAX;
200 Err:
201 *aglobals = globals;
202 return error;
206 void
207 ta_face_globals_free(TA_FaceGlobals globals)
209 if (globals)
211 FT_UInt nn;
214 for (nn = 0; nn < TA_SCRIPT_MAX; nn++)
216 if (globals->metrics[nn])
218 TA_ScriptClass script_class =
219 ta_script_classes[nn];
220 TA_WritingSystemClass writing_system_class =
221 ta_writing_system_classes[script_class->writing_system];
224 if (writing_system_class->script_metrics_done)
225 writing_system_class->script_metrics_done(globals->metrics[nn]);
227 free(globals->metrics[nn]);
228 globals->metrics[nn] = NULL;
232 globals->glyph_count = 0;
233 globals->glyph_scripts = NULL; /* no need to free this one! */
234 globals->face = NULL;
236 free(globals);
237 globals = NULL;
242 FT_Error
243 ta_face_globals_get_metrics(TA_FaceGlobals globals,
244 FT_UInt gindex,
245 FT_UInt options,
246 TA_ScriptMetrics *ametrics)
248 TA_ScriptMetrics metrics = NULL;
249 TA_Script script = (TA_Script)(options & 15);
250 TA_ScriptClass script_class;
251 TA_WritingSystemClass writing_system_class;
252 FT_Error error = FT_Err_Ok;
255 if (gindex >= (FT_ULong)globals->glyph_count)
257 error = FT_Err_Invalid_Argument;
258 goto Exit;
261 /* if we have a forced script (via `options'), use it, */
262 /* otherwise look into `glyph_scripts' array */
263 if (script == TA_SCRIPT_DFLT || script + 1 >= TA_SCRIPT_MAX)
264 script = (TA_Script)(globals->glyph_scripts[gindex] & TA_SCRIPT_NONE);
266 script_class =
267 ta_script_classes[script];
268 writing_system_class =
269 ta_writing_system_classes[script_class->writing_system];
271 metrics = globals->metrics[script];
272 if (metrics == NULL)
274 /* create the global metrics object if necessary */
275 metrics = (TA_ScriptMetrics)
276 calloc(1, writing_system_class->script_metrics_size);
277 if (!metrics)
279 error = FT_Err_Out_Of_Memory;
280 goto Exit;
283 metrics->script_class = script_class;
284 metrics->globals = globals;
286 if (writing_system_class->script_metrics_init)
288 error = writing_system_class->script_metrics_init(metrics,
289 globals->face);
290 if (error)
292 if (writing_system_class->script_metrics_done)
293 writing_system_class->script_metrics_done(metrics);
295 free(metrics);
296 metrics = NULL;
297 goto Exit;
301 globals->metrics[script] = metrics;
304 Exit:
305 *ametrics = metrics;
307 return error;
311 FT_Bool
312 ta_face_globals_is_digit(TA_FaceGlobals globals,
313 FT_UInt gindex)
315 if (gindex < (FT_ULong)globals->glyph_count)
316 return (FT_Bool)(globals->glyph_scripts[gindex] & TA_DIGIT);
318 return (FT_Bool)0;
321 /* end of taglobal.c */