Add code to adjust `hmtx' table.
[ttfautohint.git] / src / taglobal.c
blob878482ab7656ec05d4650829510ccb7367f10366
1 /* taglobal.c */
3 /*
4 * Copyright (C) 2011 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 #include "tadummy.h"
25 #include "talatin.h"
27 #if 0
28 #include "tacjk.h"
29 #include "taindic.h"
31 #ifdef FT_OPTION_AUTOFIT2
32 #include "talatin2.h"
33 #endif
34 #endif /* 0 */
36 /* populate this list when you add new scripts */
37 static TA_ScriptClass const ta_script_classes[] =
39 &ta_dummy_script_class,
40 #ifdef FT_OPTION_AUTOFIT2
41 &ta_latin2_script_class,
42 #endif
43 &ta_latin_script_class,
44 #if 0
45 &ta_cjk_script_class,
46 &ta_indic_script_class,
47 #endif
48 NULL /* do not remove */
52 /* a bit mask indicating an uncovered glyph */
53 #define TA_SCRIPT_LIST_NONE 0x7F
54 /* if this flag is set, we have an ASCII digit */
55 #define TA_DIGIT 0x80
58 /* note that glyph_scripts[] is used to map each glyph into */
59 /* an index into the `ta_script_classes' array. */
60 typedef struct TA_FaceGlobalsRec_
62 FT_Face face;
63 FT_Long glyph_count; /* same as face->num_glyphs */
64 FT_Byte* glyph_scripts;
66 TA_ScriptMetrics metrics[TA_SCRIPT_MAX];
67 } TA_FaceGlobalsRec;
70 /* Compute the script index of each glyph within a given face. */
72 static FT_Error
73 ta_face_globals_compute_script_coverage(TA_FaceGlobals globals,
74 FT_UInt fallback_script)
76 FT_Error error = FT_Err_Ok;
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_LIST_NONE means `uncovered glyph' */
85 memset(globals->glyph_scripts, TA_SCRIPT_LIST_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 clazz = ta_script_classes[ss];
100 TA_Script_UniRange range;
103 if (clazz->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 = clazz->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_LIST_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_LIST_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? */
150 FT_Long nn;
153 for (nn = 0; nn < globals->glyph_count; nn++)
155 if ((gscripts[nn] & ~TA_DIGIT) == TA_SCRIPT_LIST_NONE)
157 gscripts[nn] &= ~TA_SCRIPT_LIST_NONE;
158 gscripts[nn] |= fallback_script;
163 FT_Set_Charmap(face, old_charmap);
164 return error;
168 FT_Error
169 ta_face_globals_new(FT_Face face,
170 TA_FaceGlobals *aglobals,
171 FT_UInt fallback_script)
173 FT_Error error;
174 TA_FaceGlobals globals;
177 globals = (TA_FaceGlobals)calloc(1, sizeof (TA_FaceGlobalsRec) +
178 face->num_glyphs * sizeof (FT_Byte));
179 if (!globals)
181 error = FT_Err_Out_Of_Memory;
182 goto Err;
185 globals->face = face;
186 globals->glyph_count = face->num_glyphs;
187 globals->glyph_scripts = (FT_Byte*)(globals + 1);
189 error = ta_face_globals_compute_script_coverage(globals, fallback_script);
190 if (error)
192 ta_face_globals_free(globals);
193 globals = NULL;
196 Err:
197 *aglobals = globals;
198 return error;
202 void
203 ta_face_globals_free(TA_FaceGlobals globals)
205 if (globals)
207 FT_UInt nn;
210 for (nn = 0; nn < TA_SCRIPT_MAX; nn++)
212 if (globals->metrics[nn])
214 TA_ScriptClass clazz = ta_script_classes[nn];
217 #if 0
218 FT_ASSERT(globals->metrics[nn]->clazz == clazz);
219 #endif
221 if (clazz->script_metrics_done)
222 clazz->script_metrics_done(globals->metrics[nn]);
224 free(globals->metrics[nn]);
225 globals->metrics[nn] = NULL;
229 globals->glyph_count = 0;
230 globals->glyph_scripts = NULL; /* no need to free this one! */
231 globals->face = NULL;
233 free(globals);
234 globals = NULL;
239 FT_Error
240 ta_face_globals_get_metrics(TA_FaceGlobals globals,
241 FT_UInt gindex,
242 FT_UInt options,
243 TA_ScriptMetrics *ametrics)
245 TA_ScriptMetrics metrics = NULL;
246 FT_UInt gidx;
247 TA_ScriptClass clazz;
248 FT_UInt script = options & 15;
249 const FT_Offset script_max = sizeof (ta_script_classes)
250 / sizeof (ta_script_classes[0]);
251 FT_Error error = FT_Err_Ok;
254 if (gindex >= (FT_ULong)globals->glyph_count)
256 error = FT_Err_Invalid_Argument;
257 goto Exit;
260 gidx = script;
261 if (gidx == 0
262 || gidx + 1 >= script_max)
263 gidx = globals->glyph_scripts[gindex] & TA_SCRIPT_LIST_NONE;
265 clazz = ta_script_classes[gidx];
266 if (script == 0)
267 script = clazz->script;
269 metrics = globals->metrics[clazz->script];
270 if (metrics == NULL)
272 /* create the global metrics object if necessary */
273 metrics = (TA_ScriptMetrics)calloc(1, clazz->script_metrics_size);
274 if (!metrics)
276 error = FT_Err_Out_Of_Memory;
277 goto Exit;
280 metrics->clazz = clazz;
282 if (clazz->script_metrics_init)
284 error = clazz->script_metrics_init(metrics, globals->face);
285 if (error)
287 if (clazz->script_metrics_done)
288 clazz->script_metrics_done(metrics);
290 free(metrics);
291 metrics = NULL;
292 goto Exit;
296 globals->metrics[clazz->script] = metrics;
299 Exit:
300 *ametrics = metrics;
302 return error;
306 FT_Bool
307 ta_face_globals_is_digit(TA_FaceGlobals globals,
308 FT_UInt gindex)
310 if (gindex < (FT_ULong)globals->glyph_count)
311 return (FT_Bool)(globals->glyph_scripts[gindex] & TA_DIGIT);
313 return (FT_Bool)0;
316 /* end of taglobal.c */