Add x height snapping exceptions data to version string info.
[ttfautohint.git] / lib / ttfautohint.c
blob16917977d7d59a00d00d79874a4f7196019903bf
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 DUMPVAL(str, arg) \
30 fprintf(stderr, "%33s = %ld\n", \
31 (str), \
32 (FT_Long)(arg))
33 #define DUMPSTR(str, arg) \
34 fprintf(stderr, "%33s = %s\n", \
35 (str), \
36 (arg))
39 void
40 TA_sfnt_set_properties(SFNT* sfnt,
41 FONT* font)
43 TA_FaceGlobals globals = (TA_FaceGlobals)sfnt->face->autohint.data;
46 globals->increase_x_height = font->increase_x_height;
50 TA_Error
51 TTF_autohint(const char* options,
52 ...)
54 va_list ap;
56 FONT* font;
57 FT_Error error;
58 FT_Long i;
60 FILE* in_file = NULL;
61 FILE* out_file = NULL;
63 const char* in_buf = NULL;
64 size_t in_len = 0;
65 char** out_bufp = NULL;
66 size_t* out_lenp = NULL;
68 const unsigned char** error_stringp = NULL;
70 FT_Long hinting_range_min = -1;
71 FT_Long hinting_range_max = -1;
72 FT_Long hinting_limit = -1;
73 FT_Long increase_x_height = -1;
75 const char* x_height_snapping_exceptions_string = NULL;
76 number_range* x_height_snapping_exceptions = NULL;
78 FT_Bool gray_strong_stem_width = 0;
79 FT_Bool gdi_cleartype_strong_stem_width = 1;
80 FT_Bool dw_cleartype_strong_stem_width = 0;
82 TA_Progress_Func progress;
83 void* progress_data;
84 TA_Info_Func info;
85 void* info_data;
87 FT_Bool windows_compatibility = 0;
88 FT_Bool ignore_restrictions = 0;
89 FT_Bool pre_hinting = 0;
90 FT_Bool hint_with_components = 0;
91 FT_UInt fallback_script = TA_SCRIPT_FALLBACK;
92 FT_Bool symbol = 0;
94 FT_Bool debug = 0;
96 const char* op;
99 if (!options || !*options)
101 error = FT_Err_Invalid_Argument;
102 goto Err1;
105 /* XXX */
106 va_start(ap, options);
108 op = options;
110 for(;;)
112 const char* start;
113 size_t len;
116 start = op;
118 /* search comma */
119 while (*op && *op != ',')
120 op++;
122 /* remove leading whitespace */
123 while (isspace(*start))
124 start++;
126 /* check for empty option */
127 if (start == op)
128 goto End;
130 len = op - start;
132 /* the `COMPARE' macro uses `len' and `start' */
134 /* handle options -- don't forget to update parameter dump below! */
135 if (COMPARE("debug"))
136 debug = (FT_Bool)va_arg(ap, FT_Int);
137 else if (COMPARE("dw-cleartype-strong-stem-width"))
138 dw_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
139 else if (COMPARE("error-string"))
140 error_stringp = va_arg(ap, const unsigned char**);
141 else if (COMPARE("fallback-script"))
142 fallback_script = va_arg(ap, FT_UInt);
143 else if (COMPARE("gdi-cleartype-strong-stem-width"))
144 gdi_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
145 else if (COMPARE("gray-strong-stem-width"))
146 gray_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
147 else if (COMPARE("hinting-limit"))
148 hinting_limit = (FT_Long)va_arg(ap, FT_UInt);
149 else if (COMPARE("hinting-range-max"))
150 hinting_range_max = (FT_Long)va_arg(ap, FT_UInt);
151 else if (COMPARE("hinting-range-min"))
152 hinting_range_min = (FT_Long)va_arg(ap, FT_UInt);
153 else if (COMPARE("hint-with-components"))
154 hint_with_components = (FT_Bool)va_arg(ap, FT_Int);
155 else if (COMPARE("ignore-restrictions"))
156 ignore_restrictions = (FT_Bool)va_arg(ap, FT_Int);
157 else if (COMPARE("in-buffer"))
159 in_file = NULL;
160 in_buf = va_arg(ap, const char*);
162 else if (COMPARE("in-buffer-len"))
164 in_file = NULL;
165 in_len = va_arg(ap, size_t);
167 else if (COMPARE("in-file"))
169 in_file = va_arg(ap, FILE*);
170 in_buf = NULL;
171 in_len = 0;
173 else if (COMPARE("increase-x-height"))
174 increase_x_height = (FT_Long)va_arg(ap, FT_UInt);
175 else if (COMPARE("info-callback"))
176 info = va_arg(ap, TA_Info_Func);
177 else if (COMPARE("info-callback-data"))
178 info_data = va_arg(ap, void*);
179 else if (COMPARE("out-buffer"))
181 out_file = NULL;
182 out_bufp = va_arg(ap, char**);
184 else if (COMPARE("out-buffer-len"))
186 out_file = NULL;
187 out_lenp = va_arg(ap, size_t*);
189 else if (COMPARE("out-file"))
191 out_file = va_arg(ap, FILE*);
192 out_bufp = NULL;
193 out_lenp = NULL;
195 else if (COMPARE("pre-hinting"))
196 pre_hinting = (FT_Bool)va_arg(ap, FT_Int);
197 else if (COMPARE("progress-callback"))
198 progress = va_arg(ap, TA_Progress_Func);
199 else if (COMPARE("progress-callback-data"))
200 progress_data = va_arg(ap, void*);
201 else if (COMPARE("symbol"))
202 symbol = (FT_Bool)va_arg(ap, FT_Int);
203 else if (COMPARE("windows-compatibility"))
204 windows_compatibility = (FT_Bool)va_arg(ap, FT_Int);
205 else if (COMPARE("x-height-snapping-exceptions"))
206 x_height_snapping_exceptions_string = va_arg(ap, const char*);
207 else
209 error = TA_Err_Unknown_Argument;
210 goto Err1;
213 End:
214 if (!*op)
215 break;
216 op++;
219 va_end(ap);
221 /* check options */
223 if (!(in_file
224 || (in_buf && in_len)))
226 error = FT_Err_Invalid_Argument;
227 goto Err1;
230 if (!(out_file
231 || (out_bufp && out_lenp)))
233 error = FT_Err_Invalid_Argument;
234 goto Err1;
237 font = (FONT*)calloc(1, sizeof (FONT));
238 if (!font)
240 error = FT_Err_Out_Of_Memory;
241 goto Err1;
244 if (hinting_range_min >= 0 && hinting_range_min < 2)
246 error = FT_Err_Invalid_Argument;
247 goto Err1;
249 if (hinting_range_min < 0)
250 hinting_range_min = TA_HINTING_RANGE_MIN;
252 if (hinting_range_max >= 0 && hinting_range_max < hinting_range_min)
254 error = FT_Err_Invalid_Argument;
255 goto Err1;
257 if (hinting_range_max < 0)
258 hinting_range_max = TA_HINTING_RANGE_MAX;
260 /* value 0 is valid */
261 if (hinting_limit > 0 && hinting_limit < hinting_range_max)
263 error = FT_Err_Invalid_Argument;
264 goto Err1;
266 if (hinting_limit < 0)
267 hinting_limit = TA_HINTING_LIMIT;
269 if (increase_x_height > 0
270 && increase_x_height < TA_PROP_INCREASE_X_HEIGHT_MIN)
272 error = FT_Err_Invalid_Argument;
273 goto Err1;
275 if (increase_x_height < 0)
276 increase_x_height = TA_INCREASE_X_HEIGHT;
278 if (x_height_snapping_exceptions_string)
280 const char* s = number_set_parse(x_height_snapping_exceptions_string,
281 &x_height_snapping_exceptions,
282 TA_PROP_INCREASE_X_HEIGHT_MIN,
283 0x7FFF);
284 if (*s)
286 error = FT_Err_Invalid_Argument;
287 goto Err1;
291 font->hinting_range_min = (FT_UInt)hinting_range_min;
292 font->hinting_range_max = (FT_UInt)hinting_range_max;
293 font->hinting_limit = (FT_UInt)hinting_limit;
294 font->increase_x_height = increase_x_height;
295 font->x_height_snapping_exceptions = x_height_snapping_exceptions;
297 font->gray_strong_stem_width = gray_strong_stem_width;
298 font->gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
299 font->dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
301 font->progress = progress;
302 font->progress_data = progress_data;
303 font->info = info;
304 font->info_data = info_data;
306 font->windows_compatibility = windows_compatibility;
307 font->ignore_restrictions = ignore_restrictions;
308 font->pre_hinting = pre_hinting;
309 font->hint_with_components = hint_with_components;
310 font->fallback_script = fallback_script;
311 font->symbol = symbol;
313 font->gasp_idx = MISSING;
315 font->debug = debug;
317 /* dump parameters */
318 if (debug)
320 char *s;
323 fprintf(stderr, "TTF_autohint parameters\n"
324 "=======================\n\n");
326 DUMPVAL("dw-cleartype-strong-stem-width",
327 font->dw_cleartype_strong_stem_width);
328 DUMPVAL("fallback-script",
329 font->fallback_script);
330 DUMPVAL("gdi-cleartype-strong-stem-width",
331 font->gdi_cleartype_strong_stem_width);
332 DUMPVAL("gray-strong-stem-width",
333 font->gray_strong_stem_width);
334 DUMPVAL("hinting-limit",
335 font->hinting_limit);
336 DUMPVAL("hinting-range-max",
337 font->hinting_range_max);
338 DUMPVAL("hinting-range-min",
339 font->hinting_range_min);
340 DUMPVAL("hint-with-components",
341 font->hint_with_components);
342 DUMPVAL("ignore-restrictions",
343 font->ignore_restrictions);
344 DUMPVAL("increase-x-height",
345 font->increase_x_height);
346 DUMPVAL("pre-hinting",
347 font->pre_hinting);
348 DUMPVAL("symbol",
349 font->symbol);
350 DUMPVAL("windows-compatibility",
351 font->windows_compatibility);
353 s = number_set_show(font->x_height_snapping_exceptions,
354 TA_PROP_INCREASE_X_HEIGHT_MIN, 0x7FFF);
355 DUMPSTR("x-height-snapping-exceptions", s);
356 free(s);
358 fprintf(stderr, "\n");
361 /* now start with processing the data */
363 if (in_file)
365 error = TA_font_file_read(font, in_file);
366 if (error)
367 goto Err;
369 else
371 /* a valid TTF can never be that small */
372 if (in_len < 100)
374 error = TA_Err_Invalid_Font_Type;
375 goto Err1;
377 font->in_buf = (FT_Byte*)in_buf;
378 font->in_len = in_len;
381 error = TA_font_init(font);
382 if (error)
383 goto Err;
385 if (font->debug)
386 _ta_debug = 1;
388 /* we do some loops over all subfonts */
389 for (i = 0; i < font->num_sfnts; i++)
391 SFNT* sfnt = &font->sfnts[i];
392 FT_UInt idx;
395 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
396 i, &sfnt->face);
398 /* assure that the font hasn't been already processed by ttfautohint; */
399 /* another, more thorough check is done in TA_glyph_parse_simple */
400 idx = FT_Get_Name_Index(sfnt->face, TTFAUTOHINT_GLYPH);
401 if (idx)
403 error = TA_Err_Already_Processed;
404 goto Err;
407 if (error)
408 goto Err;
410 error = TA_sfnt_split_into_SFNT_tables(sfnt, font);
411 if (error)
412 goto Err;
414 if (font->pre_hinting)
415 error = TA_sfnt_create_glyf_data(sfnt, font);
416 else
417 error = TA_sfnt_split_glyf_table(sfnt, font);
418 if (error)
419 goto Err;
421 /* this call creates a `globals' object... */
422 error = TA_sfnt_handle_coverage(sfnt, font);
423 if (error)
424 goto Err;
426 /* ... so that we now can initialize its properties */
427 TA_sfnt_set_properties(sfnt, font);
429 /* check permission */
430 if (sfnt->OS2_idx != MISSING)
432 SFNT_Table* OS2_table = &font->tables[sfnt->OS2_idx];
435 /* check lower byte of the `fsType' field */
436 if (OS2_table->buf[OS2_FSTYPE_OFFSET + 1] == 0x02
437 && !font->ignore_restrictions)
439 error = TA_Err_Missing_Legal_Permission;
440 goto Err;
445 for (i = 0; i < font->num_sfnts; i++)
447 SFNT* sfnt = &font->sfnts[i];
450 TA_sfnt_adjust_master_coverage(sfnt, font);
453 #if 0
454 /* this code is here for completeness -- */
455 /* right now, `glyf' tables get hinted only once, */
456 /* and referring subfonts simply reuse it, */
457 /* but this might change in the future */
459 for (i = 0; i < font->num_sfnts; i++)
461 SFNT* sfnt = &font->sfnts[i];
464 TA_sfnt_copy_master_coverage(sfnt, font);
466 #endif
468 /* loop again over subfonts */
469 for (i = 0; i < font->num_sfnts; i++)
471 SFNT* sfnt = &font->sfnts[i];
474 error = ta_loader_init(font);
475 if (error)
476 goto Err;
478 error = TA_sfnt_build_gasp_table(sfnt, font);
479 if (error)
480 goto Err;
481 error = TA_sfnt_build_cvt_table(sfnt, font);
482 if (error)
483 goto Err;
484 error = TA_sfnt_build_fpgm_table(sfnt, font);
485 if (error)
486 goto Err;
487 error = TA_sfnt_build_prep_table(sfnt, font);
488 if (error)
489 goto Err;
490 error = TA_sfnt_build_glyf_table(sfnt, font);
491 if (error)
492 goto Err;
493 error = TA_sfnt_build_loca_table(sfnt, font);
494 if (error)
495 goto Err;
497 if (font->loader)
498 ta_loader_done(font);
501 for (i = 0; i < font->num_sfnts; i++)
503 SFNT* sfnt = &font->sfnts[i];
506 error = TA_sfnt_update_maxp_table(sfnt, font);
507 if (error)
508 goto Err;
510 /* we add one glyph for composites */
511 if (sfnt->max_components
512 && !font->pre_hinting
513 && font->hint_with_components)
515 error = TA_sfnt_update_hmtx_table(sfnt, font);
516 if (error)
517 goto Err;
518 error = TA_sfnt_update_post_table(sfnt, font);
519 if (error)
520 goto Err;
521 error = TA_sfnt_update_GPOS_table(sfnt, font);
522 if (error)
523 goto Err;
526 if (font->info)
528 /* add info about ttfautohint to the version string */
529 error = TA_sfnt_update_name_table(sfnt, font);
530 if (error)
531 goto Err;
535 if (font->num_sfnts == 1)
536 error = TA_font_build_TTF(font);
537 else
538 error = TA_font_build_TTC(font);
539 if (error)
540 goto Err;
542 if (out_file)
544 error = TA_font_file_write(font, out_file);
545 if (error)
546 goto Err;
548 else
550 *out_bufp = (char*)font->out_buf;
551 *out_lenp = font->out_len;
554 error = TA_Err_Ok;
556 Err:
557 TA_font_unload(font, in_buf, out_bufp);
559 Err1:
560 if (error_stringp)
561 *error_stringp = (const unsigned char*)TA_get_error_message(error);
563 return error;
566 /* end of ttfautohint.c */