Fix thinko in coverage handling of TTCs.
[ttfautohint.git] / lib / ttfautohint.c
blob36b4bbd912a25d0668990a89d821017115801f64
1 /* ttfautohint.c */
3 /*
4 * Copyright (C) 2011-2014 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_Long i;
59 FT_Error error;
60 const char* error_string = NULL;
61 unsigned int linenum = 0;
62 const char* line = NULL;
63 const char* errpos = NULL;
65 FILE* in_file = NULL;
66 FILE* out_file = NULL;
68 const char* in_buf = NULL;
69 size_t in_len = 0;
70 char** out_bufp = NULL;
71 size_t* out_lenp = NULL;
73 const unsigned char** error_stringp = NULL;
75 FT_Long hinting_range_min = -1;
76 FT_Long hinting_range_max = -1;
77 FT_Long hinting_limit = -1;
78 FT_Long increase_x_height = -1;
80 const char* x_height_snapping_exceptions_string = NULL;
81 number_range* x_height_snapping_exceptions = NULL;
83 FT_Long fallback_stem_width = 0;
85 FT_Bool gray_strong_stem_width = 0;
86 FT_Bool gdi_cleartype_strong_stem_width = 1;
87 FT_Bool dw_cleartype_strong_stem_width = 0;
89 TA_Progress_Func progress = NULL;
90 void* progress_data = NULL;
91 TA_Error_Func err = NULL;
92 void* err_data = NULL;
93 TA_Info_Func info = NULL;
94 void* info_data = NULL;
96 FT_Bool windows_compatibility = 0;
97 FT_Bool ignore_restrictions = 0;
98 FT_Bool adjust_subglyphs = 0;
99 FT_Bool hint_composites = 0;
100 FT_Bool symbol = 0;
102 const char* fallback_script_string = NULL;
103 const char* default_script_string = NULL;
104 TA_Style fallback_style = TA_STYLE_NONE_DFLT;
105 TA_Script default_script = TA_SCRIPT_LATN;
107 FT_Bool dehint = 0;
108 FT_Bool debug = 0;
110 const char* op;
112 #undef SCRIPT
113 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) #s,
115 const char* script_names[] =
118 #include <ttfautohint-scripts.h>
123 if (!options || !*options)
125 error = FT_Err_Invalid_Argument;
126 goto Err1;
129 /* XXX */
130 va_start(ap, options);
132 op = options;
134 for(;;)
136 const char* start;
137 size_t len;
140 start = op;
142 /* search comma */
143 while (*op && *op != ',')
144 op++;
146 /* remove leading whitespace */
147 while (isspace(*start))
148 start++;
150 /* check for empty option */
151 if (start == op)
152 goto End;
154 len = op - start;
156 /* the `COMPARE' macro uses `len' and `start' */
158 /* handle options -- don't forget to update parameter dump below! */
159 if (COMPARE("adjust-subglyphs"))
160 adjust_subglyphs = (FT_Bool)va_arg(ap, FT_Int);
161 else if (COMPARE("debug"))
162 debug = (FT_Bool)va_arg(ap, FT_Int);
163 else if (COMPARE("default-script"))
164 default_script_string = va_arg(ap, const char*);
165 else if (COMPARE("dehint"))
166 dehint = (FT_Bool)va_arg(ap, FT_Int);
167 else if (COMPARE("dw-cleartype-strong-stem-width"))
168 dw_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
169 else if (COMPARE("error-callback"))
170 err = va_arg(ap, TA_Error_Func);
171 else if (COMPARE("error-callback-data"))
172 err_data = va_arg(ap, void*);
173 else if (COMPARE("error-string"))
174 error_stringp = va_arg(ap, const unsigned char**);
175 else if (COMPARE("fallback-script"))
176 fallback_script_string = va_arg(ap, const char*);
177 else if (COMPARE("fallback-stem-width"))
178 fallback_stem_width = (FT_Long)va_arg(ap, FT_UInt);
179 else if (COMPARE("gdi-cleartype-strong-stem-width"))
180 gdi_cleartype_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
181 else if (COMPARE("gray-strong-stem-width"))
182 gray_strong_stem_width = (FT_Bool)va_arg(ap, FT_Int);
183 else if (COMPARE("hinting-limit"))
184 hinting_limit = (FT_Long)va_arg(ap, FT_UInt);
185 else if (COMPARE("hinting-range-max"))
186 hinting_range_max = (FT_Long)va_arg(ap, FT_UInt);
187 else if (COMPARE("hinting-range-min"))
188 hinting_range_min = (FT_Long)va_arg(ap, FT_UInt);
189 else if (COMPARE("hint-composites"))
190 hint_composites = (FT_Bool)va_arg(ap, FT_Int);
191 else if (COMPARE("ignore-restrictions"))
192 ignore_restrictions = (FT_Bool)va_arg(ap, FT_Int);
193 else if (COMPARE("in-buffer"))
195 in_file = NULL;
196 in_buf = va_arg(ap, const char*);
198 else if (COMPARE("in-buffer-len"))
200 in_file = NULL;
201 in_len = va_arg(ap, size_t);
203 else if (COMPARE("in-file"))
205 in_file = va_arg(ap, FILE*);
206 in_buf = NULL;
207 in_len = 0;
209 else if (COMPARE("increase-x-height"))
210 increase_x_height = (FT_Long)va_arg(ap, FT_UInt);
211 else if (COMPARE("info-callback"))
212 info = va_arg(ap, TA_Info_Func);
213 else if (COMPARE("info-callback-data"))
214 info_data = va_arg(ap, void*);
215 else if (COMPARE("out-buffer"))
217 out_file = NULL;
218 out_bufp = va_arg(ap, char**);
220 else if (COMPARE("out-buffer-len"))
222 out_file = NULL;
223 out_lenp = va_arg(ap, size_t*);
225 else if (COMPARE("out-file"))
227 out_file = va_arg(ap, FILE*);
228 out_bufp = NULL;
229 out_lenp = NULL;
231 else if (COMPARE("pre-hinting"))
232 adjust_subglyphs = (FT_Bool)va_arg(ap, FT_Int);
233 else if (COMPARE("progress-callback"))
234 progress = va_arg(ap, TA_Progress_Func);
235 else if (COMPARE("progress-callback-data"))
236 progress_data = va_arg(ap, void*);
237 else if (COMPARE("symbol"))
238 symbol = (FT_Bool)va_arg(ap, FT_Int);
239 else if (COMPARE("windows-compatibility"))
240 windows_compatibility = (FT_Bool)va_arg(ap, FT_Int);
241 else if (COMPARE("x-height-snapping-exceptions"))
242 x_height_snapping_exceptions_string = va_arg(ap, const char*);
243 else
245 error = TA_Err_Unknown_Argument;
246 goto Err1;
249 End:
250 if (!*op)
251 break;
252 op++;
255 va_end(ap);
257 /* check options */
259 if (!(in_file
260 || (in_buf && in_len)))
262 error = FT_Err_Invalid_Argument;
263 goto Err1;
266 if (!(out_file
267 || (out_bufp && out_lenp)))
269 error = FT_Err_Invalid_Argument;
270 goto Err1;
273 font = (FONT*)calloc(1, sizeof (FONT));
274 if (!font)
276 error = FT_Err_Out_Of_Memory;
277 goto Err1;
280 if (dehint)
281 goto No_check;
283 if (hinting_range_min >= 0 && hinting_range_min < 2)
285 error = FT_Err_Invalid_Argument;
286 goto Err1;
288 if (hinting_range_min < 0)
289 hinting_range_min = TA_HINTING_RANGE_MIN;
291 if (hinting_range_max >= 0 && hinting_range_max < hinting_range_min)
293 error = FT_Err_Invalid_Argument;
294 goto Err1;
296 if (hinting_range_max < 0)
297 hinting_range_max = TA_HINTING_RANGE_MAX;
299 /* value 0 is valid */
300 if (hinting_limit > 0 && hinting_limit < hinting_range_max)
302 error = FT_Err_Invalid_Argument;
303 goto Err1;
305 if (hinting_limit < 0)
306 hinting_limit = TA_HINTING_LIMIT;
308 if (increase_x_height > 0
309 && increase_x_height < TA_PROP_INCREASE_X_HEIGHT_MIN)
311 error = FT_Err_Invalid_Argument;
312 goto Err1;
314 if (increase_x_height < 0)
315 increase_x_height = TA_INCREASE_X_HEIGHT;
317 if (fallback_script_string)
319 int i;
322 for (i = 0; i < TA_STYLE_MAX; i++)
324 TA_StyleClass style_class = ta_style_classes[i];
327 if (style_class->coverage == TA_COVERAGE_DEFAULT
328 && !strcmp(script_names[style_class->script],
329 fallback_script_string))
330 break;
332 if (i == TA_STYLE_MAX)
334 error = FT_Err_Invalid_Argument;
335 goto Err1;
338 fallback_style = (TA_Style)i;
341 if (default_script_string)
343 int i;
346 for (i = 0; i < TA_SCRIPT_MAX; i++)
348 if (!strcmp(script_names[i], default_script_string))
349 break;
351 if (i == TA_SCRIPT_MAX)
353 error = FT_Err_Invalid_Argument;
354 goto Err1;
357 default_script = (TA_Script)i;
360 if (x_height_snapping_exceptions_string)
362 const char* s = number_set_parse(x_height_snapping_exceptions_string,
363 &x_height_snapping_exceptions,
364 TA_PROP_INCREASE_X_HEIGHT_MIN,
365 0x7FFF);
366 if (*s)
368 /* we map numberset.h's error codes to values starting with 0x100 */
369 error = 0x100 - (FT_Error)x_height_snapping_exceptions;
370 line = x_height_snapping_exceptions_string;
371 linenum = 0;
372 errpos = s;
374 goto Err1;
378 font->hinting_range_min = (FT_UInt)hinting_range_min;
379 font->hinting_range_max = (FT_UInt)hinting_range_max;
380 font->hinting_limit = (FT_UInt)hinting_limit;
381 font->increase_x_height = increase_x_height;
382 font->x_height_snapping_exceptions = x_height_snapping_exceptions;
383 font->fallback_stem_width = (FT_UInt)fallback_stem_width;
385 font->gray_strong_stem_width = gray_strong_stem_width;
386 font->gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
387 font->dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
389 font->windows_compatibility = windows_compatibility;
390 font->ignore_restrictions = ignore_restrictions;
391 font->adjust_subglyphs = adjust_subglyphs;
392 font->hint_composites = hint_composites;
393 font->fallback_style = fallback_style;
394 font->default_script = default_script;
395 font->symbol = symbol;
397 No_check:
398 font->progress = progress;
399 font->progress_data = progress_data;
400 font->info = info;
401 font->info_data = info_data;
403 font->debug = debug;
404 font->dehint = dehint;
406 font->gasp_idx = MISSING;
408 /* dump parameters */
409 if (debug)
411 fprintf(stderr, "TTF_autohint parameters\n"
412 "=======================\n"
413 "\n");
415 if (dehint)
416 DUMPVAL("dehint",
417 font->dehint);
418 else
420 char *s;
423 DUMPSTR("default-script",
424 script_names[font->default_script]);
425 DUMPVAL("dw-cleartype-strong-stem-width",
426 font->dw_cleartype_strong_stem_width);
427 DUMPSTR("fallback-script",
428 script_names[ta_style_classes[font->fallback_style]->script]);
429 DUMPVAL("fallback-stem-width",
430 font->fallback_stem_width);
431 DUMPVAL("gdi-cleartype-strong-stem-width",
432 font->gdi_cleartype_strong_stem_width);
433 DUMPVAL("gray-strong-stem-width",
434 font->gray_strong_stem_width);
435 DUMPVAL("hinting-limit",
436 font->hinting_limit);
437 DUMPVAL("hinting-range-max",
438 font->hinting_range_max);
439 DUMPVAL("hinting-range-min",
440 font->hinting_range_min);
441 DUMPVAL("hint-composites",
442 font->hint_composites);
443 DUMPVAL("ignore-restrictions",
444 font->ignore_restrictions);
445 DUMPVAL("increase-x-height",
446 font->increase_x_height);
447 DUMPVAL("adjust-subglyphs",
448 font->adjust_subglyphs);
449 DUMPVAL("symbol",
450 font->symbol);
451 DUMPVAL("windows-compatibility",
452 font->windows_compatibility);
454 s = number_set_show(font->x_height_snapping_exceptions,
455 TA_PROP_INCREASE_X_HEIGHT_MIN, 0x7FFF);
456 DUMPSTR("x-height-snapping-exceptions", s);
457 free(s);
460 fprintf(stderr, "\n");
463 /* now start with processing the data */
465 if (in_file)
467 error = TA_font_file_read(font, in_file);
468 if (error)
469 goto Err;
471 else
473 /* a valid TTF can never be that small */
474 if (in_len < 100)
476 error = TA_Err_Invalid_Font_Type;
477 goto Err1;
479 font->in_buf = (FT_Byte*)in_buf;
480 font->in_len = in_len;
483 error = TA_font_init(font);
484 if (error)
485 goto Err;
487 if (font->debug)
489 _ta_debug = 1;
490 _ta_debug_global = 1;
493 /* we do some loops over all subfonts */
494 for (i = 0; i < font->num_sfnts; i++)
496 SFNT* sfnt = &font->sfnts[i];
497 FT_UInt idx;
500 error = FT_New_Memory_Face(font->lib, font->in_buf, font->in_len,
501 i, &sfnt->face);
503 /* assure that the font hasn't been already processed by ttfautohint; */
504 /* another, more thorough check is done in TA_glyph_parse_simple */
505 idx = FT_Get_Name_Index(sfnt->face, (FT_String*)TTFAUTOHINT_GLYPH);
506 if (idx)
508 error = TA_Err_Already_Processed;
509 goto Err;
512 if (error)
513 goto Err;
515 error = TA_sfnt_split_into_SFNT_tables(sfnt, font);
516 if (error)
517 goto Err;
519 /* check permission */
520 if (sfnt->OS2_idx != MISSING)
522 SFNT_Table* OS2_table = &font->tables[sfnt->OS2_idx];
525 /* check lower byte of the `fsType' field */
526 if (OS2_table->buf[OS2_FSTYPE_OFFSET + 1] == 0x02
527 && !font->ignore_restrictions)
529 error = TA_Err_Missing_Legal_Permission;
530 goto Err;
534 if (font->dehint)
536 error = TA_sfnt_split_glyf_table(sfnt, font);
537 if (error)
538 goto Err;
540 else
542 if (font->adjust_subglyphs)
543 error = TA_sfnt_create_glyf_data(sfnt, font);
544 else
545 error = TA_sfnt_split_glyf_table(sfnt, font);
546 if (error)
547 goto Err;
549 /* this call creates a `globals' object... */
550 error = TA_sfnt_handle_coverage(sfnt, font);
551 if (error)
552 goto Err;
554 /* ... so that we now can initialize its properties */
555 TA_sfnt_set_properties(sfnt, font);
559 if (!font->dehint)
561 for (i = 0; i < font->num_sfnts; i++)
563 SFNT* sfnt = &font->sfnts[i];
566 TA_sfnt_adjust_coverage(sfnt, font);
570 #if 0
571 /* this code is here for completeness -- */
572 /* right now, `glyf' tables get hinted only once, */
573 /* and referring subfonts simply reuse it, */
574 /* but this might change in the future */
576 if (!font->dehint)
578 for (i = 0; i < font->num_sfnts; i++)
580 SFNT* sfnt = &font->sfnts[i];
583 TA_sfnt_copy_master_coverage(sfnt, font);
586 #endif
588 /* loop again over subfonts */
589 for (i = 0; i < font->num_sfnts; i++)
591 SFNT* sfnt = &font->sfnts[i];
594 error = ta_loader_init(font);
595 if (error)
596 goto Err;
598 error = TA_sfnt_build_gasp_table(sfnt, font);
599 if (error)
600 goto Err;
601 if (!font->dehint)
603 error = TA_sfnt_build_cvt_table(sfnt, font);
604 if (error)
605 goto Err;
606 error = TA_sfnt_build_fpgm_table(sfnt, font);
607 if (error)
608 goto Err;
609 error = TA_sfnt_build_prep_table(sfnt, font);
610 if (error)
611 goto Err;
613 error = TA_sfnt_build_glyf_table(sfnt, font);
614 if (error)
615 goto Err;
616 error = TA_sfnt_build_loca_table(sfnt, font);
617 if (error)
618 goto Err;
620 if (font->loader)
621 ta_loader_done(font);
624 for (i = 0; i < font->num_sfnts; i++)
626 SFNT* sfnt = &font->sfnts[i];
629 error = TA_sfnt_update_maxp_table(sfnt, font);
630 if (error)
631 goto Err;
633 if (!font->dehint)
635 /* we add one glyph for composites */
636 if (sfnt->max_components
637 && !font->adjust_subglyphs
638 && font->hint_composites)
640 error = TA_sfnt_update_hmtx_table(sfnt, font);
641 if (error)
642 goto Err;
643 error = TA_sfnt_update_post_table(sfnt, font);
644 if (error)
645 goto Err;
646 error = TA_sfnt_update_GPOS_table(sfnt, font);
647 if (error)
648 goto Err;
652 if (font->info)
654 /* add info about ttfautohint to the version string */
655 error = TA_sfnt_update_name_table(sfnt, font);
656 if (error)
657 goto Err;
661 if (font->num_sfnts == 1)
662 error = TA_font_build_TTF(font);
663 else
664 error = TA_font_build_TTC(font);
665 if (error)
666 goto Err;
668 if (out_file)
670 error = TA_font_file_write(font, out_file);
671 if (error)
672 goto Err;
674 else
676 *out_bufp = (char*)font->out_buf;
677 *out_lenp = font->out_len;
680 error = TA_Err_Ok;
682 Err:
683 TA_font_unload(font, in_buf, out_bufp);
685 Err1:
686 error_string = TA_get_error_message(error);
688 if (error_stringp)
689 *error_stringp = (const unsigned char*)error_string;
691 if (err)
692 err(error,
693 error_string,
694 linenum,
695 line,
696 errpos,
697 err_data);
699 return error;
702 /* end of ttfautohint.c */