Make ttfautohint reject fonts already processed with ttfautohint.
[ttfautohint.git] / lib / ttfautohint.c
blob2a3e8bfa25f8e60b9c6b7168373274cfc6eb57d0
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;
52 FT_Long hinting_limit = -1;
54 TA_Progress_Func progress;
55 void* progress_data;
57 FT_Bool ignore_permissions = 0;
58 FT_Bool pre_hinting = 0;
59 FT_Bool increase_x_height = 0;
60 FT_UInt fallback_script = 0;
62 const char* op;
65 if (!options || !*options)
67 error = FT_Err_Invalid_Argument;
68 goto Err1;
71 /* XXX */
72 va_start(ap, options);
74 op = options;
76 for(;;)
78 const char* start;
79 size_t len;
82 start = op;
84 /* search comma */
85 while (*op && *op != ',')
86 op++;
88 /* remove leading whitespace */
89 while (isspace(*start))
90 start++;
92 /* check for empty option */
93 if (start == op)
94 goto End;
96 len = op - start;
98 /* the `COMPARE' macro uses `len' and `start' */
100 /* handle option */
101 if (COMPARE("error-string"))
102 error_stringp = va_arg(ap, const unsigned char**);
103 else if (COMPARE("fallback-script"))
104 fallback_script = va_arg(ap, FT_UInt);
105 else if (COMPARE("hinting-limit"))
106 hinting_limit = (FT_Long)va_arg(ap, FT_UInt);
107 else if (COMPARE("hinting-range-max"))
108 hinting_range_max = (FT_Long)va_arg(ap, FT_UInt);
109 else if (COMPARE("hinting-range-min"))
110 hinting_range_min = (FT_Long)va_arg(ap, FT_UInt);
111 else if (COMPARE("ignore-permissions"))
112 ignore_permissions = (FT_Bool)va_arg(ap, FT_Int);
113 else if (COMPARE("in-buffer"))
115 in_file = NULL;
116 in_buf = va_arg(ap, const char*);
118 else if (COMPARE("in-buffer-len"))
120 in_file = NULL;
121 in_len = va_arg(ap, size_t);
123 else if (COMPARE("in-file"))
125 in_file = va_arg(ap, FILE*);
126 in_buf = NULL;
127 in_len = 0;
129 else if (COMPARE("increase-x-height"))
130 increase_x_height = (FT_Bool)va_arg(ap, FT_Int);
131 else if (COMPARE("out-buffer"))
133 out_file = NULL;
134 out_bufp = va_arg(ap, char**);
136 else if (COMPARE("out-buffer-len"))
138 out_file = NULL;
139 out_lenp = va_arg(ap, size_t*);
141 else if (COMPARE("out-file"))
143 out_file = va_arg(ap, FILE*);
144 out_bufp = NULL;
145 out_lenp = NULL;
147 else if (COMPARE("pre-hinting"))
148 pre_hinting = (FT_Bool)va_arg(ap, FT_Int);
149 else if (COMPARE("progress-callback"))
150 progress = va_arg(ap, TA_Progress_Func);
151 else if (COMPARE("progress-callback-data"))
152 progress_data = va_arg(ap, void*);
155 x-height-snapping-exceptions
158 End:
159 if (!*op)
160 break;
161 op++;
164 va_end(ap);
166 /* check options */
168 if (!(in_file
169 || (in_buf && in_len)))
171 error = FT_Err_Invalid_Argument;
172 goto Err1;
175 if (!(out_file
176 || (out_bufp && out_lenp)))
178 error = FT_Err_Invalid_Argument;
179 goto Err1;
182 font = (FONT*)calloc(1, sizeof (FONT));
183 if (!font)
185 error = FT_Err_Out_Of_Memory;
186 goto Err1;
189 if (hinting_range_min >= 0 && hinting_range_min < 2)
191 error = FT_Err_Invalid_Argument;
192 goto Err1;
194 if (hinting_range_min < 0)
195 hinting_range_min = TA_HINTING_RANGE_MIN;
197 if (hinting_range_max >= 0 && hinting_range_max < hinting_range_min)
199 error = FT_Err_Invalid_Argument;
200 goto Err1;
202 if (hinting_range_max < 0)
203 hinting_range_max = TA_HINTING_RANGE_MAX;
205 /* value 0 is valid */
206 if (hinting_limit > 0 && hinting_limit < hinting_range_max)
208 error = FT_Err_Invalid_Argument;
209 goto Err1;
211 if (hinting_limit < 0)
212 hinting_limit = TA_HINTING_LIMIT;
214 font->hinting_range_min = (FT_UInt)hinting_range_min;
215 font->hinting_range_max = (FT_UInt)hinting_range_max;
216 font->hinting_limit = (FT_UInt)hinting_limit;
218 font->progress = progress;
219 font->progress_data = progress_data;
221 font->ignore_permissions = ignore_permissions;
222 font->pre_hinting = pre_hinting;
223 font->increase_x_height = increase_x_height;
224 /* restrict value to two bits */
225 font->fallback_script = fallback_script & 3;
227 /* now start with processing the data */
229 if (in_file)
231 error = TA_font_file_read(font, in_file);
232 if (error)
233 goto Err;
235 else
237 /* a valid TTF can never be that small */
238 if (in_len < 100)
240 error = FT_Err_Invalid_Argument;
241 goto Err1;
243 font->in_buf = (FT_Byte*)in_buf;
244 font->in_len = in_len;
247 error = TA_font_init(font);
248 if (error)
249 goto Err;
251 /* loop over subfonts */
252 for (i = 0; i < font->num_sfnts; i++)
254 SFNT* sfnt = &font->sfnts[i];
255 FT_UInt idx;
258 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
259 i, &sfnt->face);
261 /* assure that the font hasn't been already processed by ttfautohint */
262 idx = FT_Get_Name_Index(sfnt->face, TTFAUTOHINT_GLYPH);
263 if (idx)
265 error = TA_Err_Already_Processed;
266 goto Err;
269 if (error)
270 goto Err;
272 error = TA_sfnt_split_into_SFNT_tables(sfnt, font);
273 if (error)
274 goto Err;
276 if (font->pre_hinting)
277 error = TA_sfnt_create_glyf_data(sfnt, font);
278 else
279 error = TA_sfnt_split_glyf_table(sfnt, font);
280 if (error)
281 goto Err;
283 /* check permission */
284 if (sfnt->OS2_idx != MISSING)
286 SFNT_Table* OS2_table = &font->tables[sfnt->OS2_idx];
289 /* check lower byte of the `fsType' field */
290 if (OS2_table->buf[OS2_FSTYPE_OFFSET + 1] == 0x02
291 && !font->ignore_permissions)
293 error = TA_Err_Missing_Legal_Permission;
294 goto Err;
299 /* build `gasp' table */
300 error = TA_sfnt_build_gasp_table(&font->sfnts[0], font);
301 if (error)
302 goto Err;
304 /* XXX handle subfonts for bytecode tables */
306 /* build `cvt ' table */
307 error = TA_sfnt_build_cvt_table(&font->sfnts[0], font);
308 if (error)
309 goto Err;
311 /* build `fpgm' table */
312 error = TA_sfnt_build_fpgm_table(&font->sfnts[0], font);
313 if (error)
314 goto Err;
316 /* build `prep' table */
317 error = TA_sfnt_build_prep_table(&font->sfnts[0], font);
318 if (error)
319 goto Err;
321 /* hint the glyphs and build bytecode */
322 error = TA_sfnt_build_glyf_hints(&font->sfnts[0], font);
323 if (error)
324 goto Err;
326 /* loop again over subfonts */
327 for (i = 0; i < font->num_sfnts; i++)
329 SFNT* sfnt = &font->sfnts[i];
332 error = TA_sfnt_build_glyf_table(sfnt, font);
333 if (error)
334 goto Err;
335 error = TA_sfnt_build_loca_table(sfnt, font);
336 if (error)
337 goto Err;
338 error = TA_sfnt_update_maxp_table(sfnt, font);
339 if (error)
340 goto Err;
342 /* we add one glyph for composites */
343 if (sfnt->max_components && !font->pre_hinting)
345 error = TA_sfnt_update_hmtx_table(sfnt, font);
346 if (error)
347 goto Err;
348 error = TA_sfnt_update_post_table(sfnt, font);
349 if (error)
350 goto Err;
351 error = TA_sfnt_update_GPOS_table(sfnt, font);
352 if (error)
353 goto Err;
357 if (font->num_sfnts == 1)
358 error = TA_font_build_TTF(font);
359 else
360 error = TA_font_build_TTC(font);
361 if (error)
362 goto Err;
364 if (out_file)
366 error = TA_font_file_write(font, out_file);
367 if (error)
368 goto Err;
370 else
372 *out_bufp = (char*)font->out_buf;
373 *out_lenp = font->out_len;
376 error = TA_Err_Ok;
378 Err:
379 TA_font_unload(font, in_buf, out_bufp);
381 Err1:
382 if (error_stringp)
383 *error_stringp = (const unsigned char*)TA_get_error_message(error);
385 return error;
388 /* end of ttfautohint.c */