`isatty' needs `unistd.h'.
[ttfautohint.git] / lib / ttfautohint.c
blobe4177d573a0d4b60911386f4ed89e0cc39c936ce
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) \
27 (len == (sizeof (str) - 1) \
28 && !strncmp(start, str, sizeof (str) - 1))
29 #define DUMP(str, arg) \
30 fprintf(stderr, "%33s = %ld\n", \
31 (str), \
32 (FT_Long)(arg))
35 TA_Error
36 TTF_autohint(const char* options,
37 ...)
39 va_list ap;
41 FONT* font;
42 FT_Error error;
43 FT_Long i;
45 FILE* in_file = NULL;
46 FILE* out_file = NULL;
48 const char* in_buf = NULL;
49 size_t in_len = 0;
50 char** out_bufp = NULL;
51 size_t* out_lenp = NULL;
53 const unsigned char** error_stringp = NULL;
55 FT_Long hinting_range_min = -1;
56 FT_Long hinting_range_max = -1;
57 FT_Long hinting_limit = -1;
58 FT_Long increase_x_height = -1;
60 FT_Bool gray_strong_stem_width = 0;
61 FT_Bool gdi_cleartype_strong_stem_width = 1;
62 FT_Bool dw_cleartype_strong_stem_width = 0;
64 TA_Progress_Func progress;
65 void* progress_data;
66 TA_Info_Func info;
67 void* info_data;
69 FT_Bool ignore_restrictions = 0;
70 FT_Bool pre_hinting = 0;
71 FT_Bool hint_with_components = 0;
72 FT_UInt fallback_script = TA_SCRIPT_FALLBACK;
73 FT_Bool symbol = 0;
75 FT_Bool debug = 0;
77 const char* op;
80 if (!options || !*options)
82 error = FT_Err_Invalid_Argument;
83 goto Err1;
86 /* XXX */
87 va_start(ap, options);
89 op = options;
91 for(;;)
93 const char* start;
94 size_t len;
97 start = op;
99 /* search comma */
100 while (*op && *op != ',')
101 op++;
103 /* remove leading whitespace */
104 while (isspace(*start))
105 start++;
107 /* check for empty option */
108 if (start == op)
109 goto End;
111 len = op - start;
113 /* the `COMPARE' macro uses `len' and `start' */
115 /* handle options -- don't forget to update parameter dump below! */
116 if (COMPARE("debug"))
117 debug = (FT_Bool)va_arg(ap, FT_Int);
118 else if (COMPARE("dw-cleartype-strong-stem-width"))
119 dw_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
120 else if (COMPARE("error-string"))
121 error_stringp = va_arg(ap, const unsigned char**);
122 else if (COMPARE("fallback-script"))
123 fallback_script = va_arg(ap, FT_UInt);
124 else if (COMPARE("gdi-cleartype-strong-stem-width"))
125 gdi_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
126 else if (COMPARE("gray-strong-stem-width"))
127 gray_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
128 else if (COMPARE("hinting-limit"))
129 hinting_limit = (FT_Long)va_arg(ap, FT_UInt);
130 else if (COMPARE("hinting-range-max"))
131 hinting_range_max = (FT_Long)va_arg(ap, FT_UInt);
132 else if (COMPARE("hinting-range-min"))
133 hinting_range_min = (FT_Long)va_arg(ap, FT_UInt);
134 else if (COMPARE("hint-with-components"))
135 hint_with_components = (FT_Bool)va_arg(ap, FT_Int);
136 else if (COMPARE("ignore-restrictions"))
137 ignore_restrictions = (FT_Bool)va_arg(ap, FT_Int);
138 else if (COMPARE("in-buffer"))
140 in_file = NULL;
141 in_buf = va_arg(ap, const char*);
143 else if (COMPARE("in-buffer-len"))
145 in_file = NULL;
146 in_len = va_arg(ap, size_t);
148 else if (COMPARE("in-file"))
150 in_file = va_arg(ap, FILE*);
151 in_buf = NULL;
152 in_len = 0;
154 else if (COMPARE("increase-x-height"))
155 increase_x_height = (FT_Long)va_arg(ap, FT_UInt);
156 else if (COMPARE("info-callback"))
157 info = va_arg(ap, TA_Info_Func);
158 else if (COMPARE("info-callback-data"))
159 info_data = va_arg(ap, void*);
160 else if (COMPARE("out-buffer"))
162 out_file = NULL;
163 out_bufp = va_arg(ap, char**);
165 else if (COMPARE("out-buffer-len"))
167 out_file = NULL;
168 out_lenp = va_arg(ap, size_t*);
170 else if (COMPARE("out-file"))
172 out_file = va_arg(ap, FILE*);
173 out_bufp = NULL;
174 out_lenp = NULL;
176 else if (COMPARE("pre-hinting"))
177 pre_hinting = (FT_Bool)va_arg(ap, FT_Int);
178 else if (COMPARE("progress-callback"))
179 progress = va_arg(ap, TA_Progress_Func);
180 else if (COMPARE("progress-callback-data"))
181 progress_data = va_arg(ap, void*);
182 else if (COMPARE("symbol"))
183 symbol = (FT_Bool)va_arg(ap, FT_Int);
184 else
186 error = TA_Err_Unknown_Argument;
187 goto Err1;
191 x-height-snapping-exceptions
194 End:
195 if (!*op)
196 break;
197 op++;
200 va_end(ap);
202 /* check options */
204 if (!(in_file
205 || (in_buf && in_len)))
207 error = FT_Err_Invalid_Argument;
208 goto Err1;
211 if (!(out_file
212 || (out_bufp && out_lenp)))
214 error = FT_Err_Invalid_Argument;
215 goto Err1;
218 font = (FONT*)calloc(1, sizeof (FONT));
219 if (!font)
221 error = FT_Err_Out_Of_Memory;
222 goto Err1;
225 if (hinting_range_min >= 0 && hinting_range_min < 2)
227 error = FT_Err_Invalid_Argument;
228 goto Err1;
230 if (hinting_range_min < 0)
231 hinting_range_min = TA_HINTING_RANGE_MIN;
233 if (hinting_range_max >= 0 && hinting_range_max < hinting_range_min)
235 error = FT_Err_Invalid_Argument;
236 goto Err1;
238 if (hinting_range_max < 0)
239 hinting_range_max = TA_HINTING_RANGE_MAX;
241 /* value 0 is valid */
242 if (hinting_limit > 0 && hinting_limit < hinting_range_max)
244 error = FT_Err_Invalid_Argument;
245 goto Err1;
247 if (hinting_limit < 0)
248 hinting_limit = TA_HINTING_LIMIT;
250 if (increase_x_height > 0 && increase_x_height < 6)
252 error = FT_Err_Invalid_Argument;
253 goto Err1;
255 if (increase_x_height < 0)
256 increase_x_height = TA_INCREASE_X_HEIGHT;
258 font->hinting_range_min = (FT_UInt)hinting_range_min;
259 font->hinting_range_max = (FT_UInt)hinting_range_max;
260 font->hinting_limit = (FT_UInt)hinting_limit;
261 font->increase_x_height = increase_x_height;
263 font->gray_strong_stem_width = gray_strong_stem_width;
264 font->gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
265 font->dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
267 font->progress = progress;
268 font->progress_data = progress_data;
269 font->info = info;
270 font->info_data = info_data;
272 font->ignore_restrictions = ignore_restrictions;
273 font->pre_hinting = pre_hinting;
274 font->hint_with_components = hint_with_components;
275 font->fallback_script = fallback_script;
276 font->symbol = symbol;
278 font->gasp_idx = MISSING;
280 font->debug = debug;
282 /* dump parameters */
283 if (debug)
285 fprintf(stderr, "TTF_autohint parameters\n"
286 "=======================\n\n");
288 DUMP("dw-cleartype-strong-stem-width",
289 font->dw_cleartype_strong_stem_width);
290 DUMP("fallback-script",
291 font->fallback_script);
292 DUMP("gdi-cleartype-strong-stem-width",
293 font->gdi_cleartype_strong_stem_width);
294 DUMP("gray-strong-stem-width",
295 font->gray_strong_stem_width);
296 DUMP("hinting-limit",
297 font->hinting_limit);
298 DUMP("hinting-range-max",
299 font->hinting_range_max);
300 DUMP("hinting-range-min",
301 font->hinting_range_min);
302 DUMP("hint-with-components",
303 font->hint_with_components);
304 DUMP("ignore-restrictions",
305 font->ignore_restrictions);
306 DUMP("increase-x-height",
307 font->increase_x_height);
308 DUMP("pre-hinting",
309 font->pre_hinting);
310 DUMP("symbol",
311 font->symbol);
313 fprintf(stderr, "\n");
316 /* now start with processing the data */
318 if (in_file)
320 error = TA_font_file_read(font, in_file);
321 if (error)
322 goto Err;
324 else
326 /* a valid TTF can never be that small */
327 if (in_len < 100)
329 error = TA_Err_Invalid_Font_Type;
330 goto Err1;
332 font->in_buf = (FT_Byte*)in_buf;
333 font->in_len = in_len;
336 error = TA_font_init(font);
337 if (error)
338 goto Err;
340 if (font->debug)
341 _ta_debug = 1;
343 /* we do some loops over all subfonts */
344 for (i = 0; i < font->num_sfnts; i++)
346 SFNT* sfnt = &font->sfnts[i];
347 FT_UInt idx;
350 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
351 i, &sfnt->face);
353 /* assure that the font hasn't been already processed by ttfautohint; */
354 /* another, more thorough check is done in TA_glyph_parse_simple */
355 idx = FT_Get_Name_Index(sfnt->face, TTFAUTOHINT_GLYPH);
356 if (idx)
358 error = TA_Err_Already_Processed;
359 goto Err;
362 if (error)
363 goto Err;
365 error = TA_sfnt_split_into_SFNT_tables(sfnt, font);
366 if (error)
367 goto Err;
369 if (font->pre_hinting)
370 error = TA_sfnt_create_glyf_data(sfnt, font);
371 else
372 error = TA_sfnt_split_glyf_table(sfnt, font);
373 if (error)
374 goto Err;
376 error = TA_sfnt_handle_coverage(sfnt, font);
377 if (error)
378 goto Err;
380 /* check permission */
381 if (sfnt->OS2_idx != MISSING)
383 SFNT_Table* OS2_table = &font->tables[sfnt->OS2_idx];
386 /* check lower byte of the `fsType' field */
387 if (OS2_table->buf[OS2_FSTYPE_OFFSET + 1] == 0x02
388 && !font->ignore_restrictions)
390 error = TA_Err_Missing_Legal_Permission;
391 goto Err;
396 for (i = 0; i < font->num_sfnts; i++)
398 SFNT* sfnt = &font->sfnts[i];
401 TA_sfnt_adjust_master_coverage(sfnt, font);
404 #if 0
405 /* this code is here for completeness -- */
406 /* right now, `glyf' tables get hinted only once, */
407 /* and referring subfonts simply reuse it, */
408 /* but this might change in the future */
410 for (i = 0; i < font->num_sfnts; i++)
412 SFNT* sfnt = &font->sfnts[i];
415 TA_sfnt_copy_master_coverage(sfnt, font);
417 #endif
419 /* loop again over subfonts */
420 for (i = 0; i < font->num_sfnts; i++)
422 SFNT* sfnt = &font->sfnts[i];
425 error = ta_loader_init(font);
426 if (error)
427 goto Err;
429 error = TA_sfnt_build_gasp_table(sfnt, font);
430 if (error)
431 goto Err;
432 error = TA_sfnt_build_cvt_table(sfnt, font);
433 if (error)
434 goto Err;
435 error = TA_sfnt_build_fpgm_table(sfnt, font);
436 if (error)
437 goto Err;
438 error = TA_sfnt_build_prep_table(sfnt, font);
439 if (error)
440 goto Err;
441 error = TA_sfnt_build_glyf_table(sfnt, font);
442 if (error)
443 goto Err;
444 error = TA_sfnt_build_loca_table(sfnt, font);
445 if (error)
446 goto Err;
448 if (font->loader)
449 ta_loader_done(font);
452 for (i = 0; i < font->num_sfnts; i++)
454 SFNT* sfnt = &font->sfnts[i];
457 error = TA_sfnt_update_maxp_table(sfnt, font);
458 if (error)
459 goto Err;
461 /* we add one glyph for composites */
462 if (sfnt->max_components
463 && !font->pre_hinting
464 && font->hint_with_components)
466 error = TA_sfnt_update_hmtx_table(sfnt, font);
467 if (error)
468 goto Err;
469 error = TA_sfnt_update_post_table(sfnt, font);
470 if (error)
471 goto Err;
472 error = TA_sfnt_update_GPOS_table(sfnt, font);
473 if (error)
474 goto Err;
477 if (font->info)
479 /* add info about ttfautohint to the version string */
480 error = TA_sfnt_update_name_table(sfnt, font);
481 if (error)
482 goto Err;
486 if (font->num_sfnts == 1)
487 error = TA_font_build_TTF(font);
488 else
489 error = TA_font_build_TTC(font);
490 if (error)
491 goto Err;
493 if (out_file)
495 error = TA_font_file_write(font, out_file);
496 if (error)
497 goto Err;
499 else
501 *out_bufp = (char*)font->out_buf;
502 *out_lenp = font->out_len;
505 error = TA_Err_Ok;
507 Err:
508 TA_font_unload(font, in_buf, out_bufp);
510 Err1:
511 if (error_stringp)
512 *error_stringp = (const unsigned char*)TA_get_error_message(error);
514 return error;
517 /* end of ttfautohint.c */