Add code to properly scale glyphs not handled by the autohinter.
[ttfautohint.git] / src / taglobal.c
blob50cef0ad7c390b39af0e92a6b3d72a610406f31a
1 /* taglobal.c */
3 /* originally file `afglobal.c' (2011-Mar-28) from FreeType */
5 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
7 #include <stdlib.h>
9 #include "taglobal.h"
11 #include "tadummy.h"
12 #include "talatin.h"
14 #if 0
15 #include "tacjk.h"
16 #include "taindic.h"
18 #ifdef FT_OPTION_AUTOFIT2
19 #include "talatin2.h"
20 #endif
21 #endif /* 0 */
23 /* populate this list when you add new scripts */
24 static TA_ScriptClass const ta_script_classes[] =
26 &ta_dummy_script_class,
27 #ifdef FT_OPTION_AUTOFIT2
28 &ta_latin2_script_class,
29 #endif
30 &ta_latin_script_class,
31 #if 0
32 &ta_cjk_script_class,
33 &ta_indic_script_class,
34 #endif
35 NULL /* do not remove */
39 /* XXX index of default script in `ta_script_classes' */
40 #define TA_SCRIPT_LIST_DEFAULT 0
41 /* a bit mask indicating an uncovered glyph */
42 #define TA_SCRIPT_LIST_NONE 0x7F
43 /* if this flag is set, we have an ASCII digit */
44 #define TA_DIGIT 0x80
47 /* note that glyph_scripts[] is used to map each glyph into */
48 /* an index into the `ta_script_classes' array. */
49 typedef struct TA_FaceGlobalsRec_
51 FT_Face face;
52 FT_Long glyph_count; /* same as face->num_glyphs */
53 FT_Byte* glyph_scripts;
55 TA_ScriptMetrics metrics[TA_SCRIPT_MAX];
56 } TA_FaceGlobalsRec;
59 /* Compute the script index of each glyph within a given face. */
61 static FT_Error
62 ta_face_globals_compute_script_coverage(TA_FaceGlobals globals)
64 FT_Error error = FT_Err_Ok;
65 FT_Face face = globals->face;
66 FT_CharMap old_charmap = face->charmap;
67 FT_Byte* gscripts = globals->glyph_scripts;
68 FT_UInt ss;
69 FT_UInt i;
72 /* the value TA_SCRIPT_LIST_NONE means `uncovered glyph' */
73 memset(globals->glyph_scripts, TA_SCRIPT_LIST_NONE, globals->glyph_count);
75 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
76 if (error)
78 /* ignore this error; we simply use the default script */
79 /* XXX: Shouldn't we rather disable hinting? */
80 error = FT_Err_Ok;
81 goto Exit;
84 /* scan each script in a Unicode charmap */
85 for (ss = 0; ta_script_classes[ss]; ss++)
87 TA_ScriptClass clazz = ta_script_classes[ss];
88 TA_Script_UniRange range;
91 if (clazz->script_uni_ranges == NULL)
92 continue;
94 /* scan all Unicode points in the range and */
95 /* set the corresponding glyph script index */
96 for (range = clazz->script_uni_ranges; range->first != 0; range++)
98 FT_ULong charcode = range->first;
99 FT_UInt gindex;
102 gindex = FT_Get_Char_Index(face, charcode);
104 if (gindex != 0
105 && gindex < (FT_ULong)globals->glyph_count
106 && gscripts[gindex] == TA_SCRIPT_LIST_NONE)
107 gscripts[gindex] = (FT_Byte)ss;
109 for (;;)
111 charcode = FT_Get_Next_Char(face, charcode, &gindex);
113 if (gindex == 0 || charcode > range->last)
114 break;
116 if (gindex < (FT_ULong)globals->glyph_count
117 && gscripts[gindex] == TA_SCRIPT_LIST_NONE)
118 gscripts[gindex] = (FT_Byte)ss;
123 /* mark ASCII digits */
124 for (i = 0x30; i <= 0x39; i++)
126 FT_UInt gindex = FT_Get_Char_Index(face, i);
129 if (gindex != 0
130 && gindex < (FT_ULong)globals->glyph_count)
131 gscripts[gindex] |= TA_DIGIT;
134 Exit:
135 /* by default, all uncovered glyphs are set to the latin script */
136 /* XXX: Shouldn't we disable hinting or do something similar? */
138 FT_Long nn;
141 for (nn = 0; nn < globals->glyph_count; nn++)
143 if ((gscripts[nn] & ~TA_DIGIT) == TA_SCRIPT_LIST_NONE)
145 gscripts[nn] &= ~TA_SCRIPT_LIST_NONE;
146 gscripts[nn] |= TA_SCRIPT_LIST_DEFAULT;
151 FT_Set_Charmap(face, old_charmap);
152 return error;
156 FT_Error
157 ta_face_globals_new(FT_Face face,
158 TA_FaceGlobals *aglobals)
160 FT_Error error;
161 TA_FaceGlobals globals;
164 globals = (TA_FaceGlobals)calloc(1, sizeof (TA_FaceGlobalsRec) +
165 face->num_glyphs * sizeof (FT_Byte));
166 if (!globals)
168 error = FT_Err_Out_Of_Memory;
169 goto Err;
172 globals->face = face;
173 globals->glyph_count = face->num_glyphs;
174 globals->glyph_scripts = (FT_Byte*)(globals + 1);
176 error = ta_face_globals_compute_script_coverage(globals);
177 if (error)
179 ta_face_globals_free(globals);
180 globals = NULL;
183 Err:
184 *aglobals = globals;
185 return error;
189 void
190 ta_face_globals_free(TA_FaceGlobals globals)
192 if (globals)
194 FT_UInt nn;
197 for (nn = 0; nn < TA_SCRIPT_MAX; nn++)
199 if (globals->metrics[nn])
201 TA_ScriptClass clazz = ta_script_classes[nn];
204 #if 0
205 FT_ASSERT(globals->metrics[nn]->clazz == clazz);
206 #endif
208 if (clazz->script_metrics_done)
209 clazz->script_metrics_done(globals->metrics[nn]);
211 free(globals->metrics[nn]);
212 globals->metrics[nn] = NULL;
216 globals->glyph_count = 0;
217 globals->glyph_scripts = NULL; /* no need to free this one! */
218 globals->face = NULL;
220 free(globals);
221 globals = NULL;
226 FT_Error
227 ta_face_globals_get_metrics(TA_FaceGlobals globals,
228 FT_UInt gindex,
229 FT_UInt options,
230 TA_ScriptMetrics *ametrics)
232 TA_ScriptMetrics metrics = NULL;
233 FT_UInt gidx;
234 TA_ScriptClass clazz;
235 FT_UInt script = options & 15;
236 const FT_Offset script_max = sizeof (ta_script_classes)
237 / sizeof (ta_script_classes[0]);
238 FT_Error error = FT_Err_Ok;
241 if (gindex >= (FT_ULong)globals->glyph_count)
243 error = FT_Err_Invalid_Argument;
244 goto Exit;
247 gidx = script;
248 if (gidx == 0
249 || gidx + 1 >= script_max)
250 gidx = globals->glyph_scripts[gindex] & TA_SCRIPT_LIST_NONE;
252 clazz = ta_script_classes[gidx];
253 if (script == 0)
254 script = clazz->script;
256 metrics = globals->metrics[clazz->script];
257 if (metrics == NULL)
259 /* create the global metrics object if necessary */
260 metrics = (TA_ScriptMetrics)calloc(1, clazz->script_metrics_size);
261 if (!metrics)
263 error = FT_Err_Out_Of_Memory;
264 goto Exit;
267 metrics->clazz = clazz;
269 if (clazz->script_metrics_init)
271 error = clazz->script_metrics_init(metrics, globals->face);
272 if (error)
274 if (clazz->script_metrics_done)
275 clazz->script_metrics_done(metrics);
277 free(metrics);
278 metrics = NULL;
279 goto Exit;
283 globals->metrics[clazz->script] = metrics;
286 Exit:
287 *ametrics = metrics;
289 return error;
293 FT_Bool
294 ta_face_globals_is_digit(TA_FaceGlobals globals,
295 FT_UInt gindex)
297 if (gindex < (FT_ULong)globals->glyph_count)
298 return (FT_Bool)(globals->glyph_scripts[gindex] & TA_DIGIT);
300 return (FT_Bool)0;
303 /* end of taglobal.c */