Version 0.6.1.
[ttfautohint.git] / src / ttfautohint.c
blob8a1ab8eceef553e0f683e2710e9ff18d9965cd11
1 /* ttfautohint.c */
3 /*
4 * Copyright (C) 2011-2012 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 /* This file needs FreeType 2.4.5 or newer. */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
23 #include "ta.h"
26 #define COMPARE(str) (len == (sizeof (str) - 1) \
27 && !strncmp(start, str, sizeof (str) - 1))
30 TA_Error
31 TTF_autohint(const char* options,
32 ...)
34 va_list ap;
36 FONT* font;
37 FT_Error error;
38 FT_Long i;
40 FILE* in_file = NULL;
41 FILE* out_file = NULL;
43 const char* in_buf = NULL;
44 size_t in_len = 0;
45 char** out_bufp = NULL;
46 size_t* out_lenp = NULL;
48 const unsigned char** error_stringp = NULL;
50 FT_Long hinting_range_min = -1;
51 FT_Long hinting_range_max = -1;
53 TA_Progress_Func progress;
54 void* progress_data;
56 FT_Bool ignore_permissions = 0;
57 FT_Bool pre_hinting = 0;
58 FT_UInt fallback_script = 0;
60 const char *op;
63 if (!options || !*options)
65 error = FT_Err_Invalid_Argument;
66 goto Err1;
69 /* XXX */
70 va_start(ap, options);
72 op = options;
74 for(;;)
76 const char* start;
77 size_t len;
80 start = op;
82 /* search comma */
83 while (*op && *op != ',')
84 op++;
86 /* remove leading whitespace */
87 while (isspace(*start))
88 start++;
90 /* check for empty option */
91 if (start == op)
92 goto End;
94 len = op - start;
96 /* the `COMPARE' macro uses `len' and `start' */
98 /* handle option */
99 if (COMPARE("error-string"))
100 error_stringp = va_arg(ap, const unsigned char**);
101 else if (COMPARE("fallback-script"))
102 fallback_script = va_arg(ap, FT_UInt);
103 else if (COMPARE("hinting-range-max"))
104 hinting_range_max = (FT_Long)va_arg(ap, FT_UInt);
105 else if (COMPARE("hinting-range-min"))
106 hinting_range_min = (FT_Long)va_arg(ap, FT_UInt);
107 else if (COMPARE("ignore-permissions"))
108 ignore_permissions = (FT_Bool)va_arg(ap, FT_Int);
109 else if (COMPARE("in-buffer"))
111 in_file = NULL;
112 in_buf = va_arg(ap, const char*);
114 else if (COMPARE("in-buffer-len"))
116 in_file = NULL;
117 in_len = va_arg(ap, size_t);
119 else if (COMPARE("in-file"))
121 in_file = va_arg(ap, FILE*);
122 in_buf = NULL;
123 in_len = 0;
125 else if (COMPARE("out-buffer"))
127 out_file = NULL;
128 out_bufp = va_arg(ap, char**);
130 else if (COMPARE("out-buffer-len"))
132 out_file = NULL;
133 out_lenp = va_arg(ap, size_t*);
135 else if (COMPARE("out-file"))
137 out_file = va_arg(ap, FILE*);
138 out_bufp = NULL;
139 out_lenp = NULL;
141 else if (COMPARE("pre-hinting"))
142 pre_hinting = (FT_Bool)va_arg(ap, FT_Int);
143 else if (COMPARE("progress-callback"))
144 progress = va_arg(ap, TA_Progress_Func);
145 else if (COMPARE("progress-callback-data"))
146 progress_data = va_arg(ap, void*);
149 x-height-snapping-exceptions
152 End:
153 if (!*op)
154 break;
155 op++;
158 va_end(ap);
160 /* check options */
162 if (!(in_file
163 || (in_buf && in_len)))
165 error = FT_Err_Invalid_Argument;
166 goto Err1;
169 if (!(out_file
170 || (out_bufp && out_lenp)))
172 error = FT_Err_Invalid_Argument;
173 goto Err1;
176 font = (FONT*)calloc(1, sizeof (FONT));
177 if (!font)
179 error = FT_Err_Out_Of_Memory;
180 goto Err1;
183 if (hinting_range_min >= 0 && hinting_range_min < 2)
185 error = FT_Err_Invalid_Argument;
186 goto Err1;
188 if (hinting_range_min < 0)
189 hinting_range_min = 8;
191 if (hinting_range_max >= 0 && hinting_range_max < hinting_range_min)
193 error = FT_Err_Invalid_Argument;
194 goto Err1;
196 if (hinting_range_max < 0)
197 hinting_range_max = 1000;
199 font->hinting_range_min = (FT_UInt)hinting_range_min;
200 font->hinting_range_max = (FT_UInt)hinting_range_max;
202 font->progress = progress;
203 font->progress_data = progress_data;
205 font->ignore_permissions = ignore_permissions;
206 font->pre_hinting = pre_hinting;
207 /* restrict value to two bits */
208 font->fallback_script = fallback_script & 3;
210 /* now start with processing the data */
212 if (in_file)
214 error = TA_font_file_read(font, in_file);
215 if (error)
216 goto Err;
218 else
220 /* a valid TTF can never be that small */
221 if (in_len < 100)
223 error = FT_Err_Invalid_Argument;
224 goto Err1;
226 font->in_buf = (FT_Byte*)in_buf;
227 font->in_len = in_len;
230 error = TA_font_init(font);
231 if (error)
232 goto Err;
234 /* loop over subfonts */
235 for (i = 0; i < font->num_sfnts; i++)
237 SFNT* sfnt = &font->sfnts[i];
240 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
241 i, &sfnt->face);
242 if (error)
243 goto Err;
245 error = TA_sfnt_split_into_SFNT_tables(sfnt, font);
246 if (error)
247 goto Err;
249 if (font->pre_hinting)
250 error = TA_sfnt_create_glyf_data(sfnt, font);
251 else
252 error = TA_sfnt_split_glyf_table(sfnt, font);
253 if (error)
254 goto Err;
256 /* check permission */
257 if (sfnt->OS2_idx != MISSING)
259 SFNT_Table* OS2_table = &font->tables[sfnt->OS2_idx];
262 /* check lower byte of the `fsType' field */
263 if (OS2_table->buf[OS2_FSTYPE_OFFSET + 1] == 0x02
264 && !font->ignore_permissions)
266 error = TA_Err_Missing_Legal_Permission;
267 goto Err;
272 /* build `gasp' table */
273 error = TA_sfnt_build_gasp_table(&font->sfnts[0], font);
274 if (error)
275 goto Err;
277 /* XXX handle subfonts for bytecode tables */
279 /* build `cvt ' table */
280 error = TA_sfnt_build_cvt_table(&font->sfnts[0], font);
281 if (error)
282 goto Err;
284 /* build `fpgm' table */
285 error = TA_sfnt_build_fpgm_table(&font->sfnts[0], font);
286 if (error)
287 goto Err;
289 /* build `prep' table */
290 error = TA_sfnt_build_prep_table(&font->sfnts[0], font);
291 if (error)
292 goto Err;
294 /* hint the glyphs and build bytecode */
295 error = TA_sfnt_build_glyf_hints(&font->sfnts[0], font);
296 if (error)
297 goto Err;
299 /* loop again over subfonts */
300 for (i = 0; i < font->num_sfnts; i++)
302 SFNT* sfnt = &font->sfnts[i];
305 error = TA_sfnt_build_glyf_table(sfnt, font);
306 if (error)
307 goto Err;
308 error = TA_sfnt_build_loca_table(sfnt, font);
309 if (error)
310 goto Err;
311 error = TA_sfnt_update_maxp_table(sfnt, font);
312 if (error)
313 goto Err;
315 /* we add one glyph for composites */
316 if (sfnt->max_components && !font->pre_hinting)
318 error = TA_sfnt_update_hmtx_table(sfnt, font);
319 if (error)
320 goto Err;
321 error = TA_sfnt_update_post_table(sfnt, font);
322 if (error)
323 goto Err;
324 error = TA_sfnt_update_GPOS_table(sfnt, font);
325 if (error)
326 goto Err;
330 if (font->num_sfnts == 1)
331 error = TA_font_build_TTF(font);
332 else
333 error = TA_font_build_TTC(font);
334 if (error)
335 goto Err;
337 if (out_file)
339 error = TA_font_file_write(font, out_file);
340 if (error)
341 goto Err;
343 else
345 *out_bufp = (char*)font->out_buf;
346 *out_lenp = font->out_len;
349 error = TA_Err_Ok;
351 Err:
352 TA_font_unload(font, in_buf, out_bufp);
354 Err1:
355 if (error_stringp)
356 *error_stringp = (const unsigned char*)TA_get_error_message(error);
358 return error;
361 /* end of ttfautohint.c */