Generalize concept of `ins_extra_{buf,len}'.
[ttfautohint.git] / frontend / main.cpp
blobc8bf5dc326e78e005f40664a55dd2a816b60af07
1 // main.cpp
3 // Copyright (C) 2011-2015 by Werner Lemberg.
4 //
5 // This file is part of the ttfautohint library, and may only be used,
6 // modified, and distributed under the terms given in `COPYING'. By
7 // continuing to use, modify, or distribute this file you indicate that you
8 // have read `COPYING' and understand and accept it fully.
9 //
10 // The file `COPYING' mentioned in the previous paragraph is distributed
11 // with the ttfautohint library.
14 // This program is a wrapper for `TTF_autohint'.
16 #ifdef BUILD_GUI
17 # ifndef _WIN32
18 # define CONSOLE_OUTPUT
19 # endif
20 #else
21 # define CONSOLE_OUTPUT
22 #endif
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <getopt.h>
31 #include <limits.h>
32 #include <unistd.h>
33 #include <locale.h>
35 #include <vector>
36 #include <string>
38 #if BUILD_GUI
39 # include <QApplication>
40 # include "maingui.h"
41 #else
42 # include "info.h"
43 #endif
45 #include <ttfautohint.h>
46 #include <numberset.h>
49 #ifdef _WIN32
50 # include <fcntl.h>
51 # define SET_BINARY(f) do { \
52 if (!isatty(fileno(f))) \
53 setmode(fileno(f), O_BINARY); \
54 } while (0)
55 #endif
57 #ifndef SET_BINARY
58 # define SET_BINARY(f) do {} while (0)
59 #endif
62 using namespace std;
65 typedef struct Tag_Names_
67 const char* tag;
68 const char* description;
69 } Tag_Names;
72 // the available script tags and its descriptions are directly extracted
73 // from `ttfautohint-scripts.h'
74 #undef SCRIPT
75 #define SCRIPT(s, S, d, h, sc1, sc2, sc3) \
76 {#s, d},
78 const Tag_Names script_names[] =
80 #include <ttfautohint-scripts.h>
81 {NULL, NULL}
85 // the available feature tags and its descriptions are directly extracted
86 // from `ttfautohint-coverages.h'
87 #undef COVERAGE
88 #define COVERAGE(n, N, d, t, t1, t2, t3, t4) \
89 {#t, d},
91 const Tag_Names feature_names[] =
93 #include <ttfautohint-coverages.h>
94 {NULL, NULL}
98 #ifndef BUILD_GUI
99 extern "C" {
101 typedef struct Progress_Data_
103 long last_sfnt;
104 bool begin;
105 int last_percent;
106 } Progress_Data;
109 static int
110 progress(long curr_idx,
111 long num_glyphs,
112 long curr_sfnt,
113 long num_sfnts,
114 void* user)
116 Progress_Data* data = (Progress_Data*)user;
118 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
120 fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts);
121 data->last_sfnt = curr_sfnt;
122 data->last_percent = 0;
123 data->begin = true;
126 if (data->begin)
128 fprintf(stderr, " %ld glyphs\n"
129 " ", num_glyphs);
130 data->begin = false;
133 // print progress approx. every 10%
134 int curr_percent = curr_idx * 100 / num_glyphs;
135 int curr_diff = curr_percent - data->last_percent;
137 if (curr_diff >= 10)
139 fprintf(stderr, " %d%%", curr_percent);
140 data->last_percent = curr_percent - curr_percent % 10;
143 if (curr_idx + 1 == num_glyphs)
144 fprintf(stderr, "\n");
146 return 0;
150 typedef struct Error_Data_
152 const char* control_name;
153 } Error_Data;
156 static void
157 err(TA_Error error,
158 const char* error_string,
159 unsigned int errlinenum,
160 const char* errline,
161 const char* errpos,
162 void* user)
164 Error_Data* data = static_cast<Error_Data*>(user);
166 if (!error)
167 return;
169 // We replace some terse error strings with more user-friendly versions.
170 if (error == TA_Err_Invalid_FreeType_Version)
171 fprintf(stderr,
172 "FreeType version 2.4.5 or higher is needed.\n"
173 "Perhaps using a wrong FreeType DLL?\n");
174 else if (error == TA_Err_Invalid_Font_Type)
175 fprintf(stderr,
176 "This font is not a valid font"
177 " in SFNT format with TrueType outlines.\n"
178 "In particular, CFF outlines are not supported.\n");
179 else if (error == TA_Err_Already_Processed)
180 fprintf(stderr,
181 "This font has already been processed with ttfautohint.\n");
182 else if (error == TA_Err_Missing_Legal_Permission)
183 fprintf(stderr,
184 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
185 "This font must not be modified"
186 " without permission of the legal owner.\n"
187 "Use command line option `-i' to continue"
188 " if you have such a permission.\n");
189 else if (error == TA_Err_Missing_Unicode_CMap)
190 fprintf(stderr,
191 "No Unicode character map.\n");
192 else if (error == TA_Err_Missing_Symbol_CMap)
193 fprintf(stderr,
194 "No symbol character map.\n");
195 else if (error == TA_Err_Missing_Glyph)
196 fprintf(stderr,
197 "No glyph for a standard character"
198 " to derive standard width and height.\n"
199 "Please check the documentation for a list of"
200 " script-specific standard characters,\n"
201 "or use option `--symbol'.\n");
202 else
204 if (error < 0x100)
205 fprintf(stderr, "An error with code 0x%02x occurred"
206 " while autohinting fonts\n",
207 error);
208 else if (error >= 0x100 && error < 0x200)
210 fprintf(stderr, "An error with code 0x%03x occurred"
211 " while parsing the argument of option `-X'",
212 error);
213 fprintf(stderr, errline ? ":\n" : ".\n");
215 if (errline)
216 fprintf(stderr, " %s\n", errline);
217 if (errpos && errline)
218 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
220 else if (error >= 0x200 && error < 0x300)
222 fprintf(stderr, "%s:", data->control_name);
223 if (errlinenum)
224 fprintf(stderr, "%d:", errlinenum);
225 if (errpos && errline)
226 fprintf(stderr, "%d:", int(errpos - errline + 1));
227 if (error_string)
228 fprintf(stderr, " %s", error_string);
229 fprintf(stderr, " (0x%02X)\n", error);
230 if (errline)
231 fprintf(stderr, " %s\n", errline);
232 if (errpos && errline)
233 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
239 } // extern "C"
240 #endif // !BUILD_GUI
243 #ifdef CONSOLE_OUTPUT
244 static void
245 show_help(bool
246 #ifdef BUILD_GUI
248 #endif
250 bool is_error)
252 FILE* handle = is_error ? stderr : stdout;
254 fprintf(handle,
255 #ifdef BUILD_GUI
256 "Usage: ttfautohintGUI [OPTION]...\n"
257 "A GUI application to replace hints in a TrueType font.\n"
258 #else
259 "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n"
260 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
261 "If OUT-FILE is missing, standard output is used instead;\n"
262 "if IN-FILE is missing also, standard input and output are used.\n"
263 #endif
264 "\n"
265 "The new hints are based on FreeType's auto-hinter.\n"
266 "\n"
267 "This program is a simple front-end to the `ttfautohint' library.\n"
268 "\n");
270 fprintf(handle,
271 "Long options can be given with one or two dashes,\n"
272 "and with and without equal sign between option and argument.\n"
273 "This means that the following forms are acceptable:\n"
274 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
275 "\n"
276 "Mandatory arguments to long options are mandatory for short options too.\n"
277 #ifdef BUILD_GUI
278 "Options not related to Qt or X11 set default values.\n"
279 #endif
280 "\n"
283 fprintf(handle,
284 "Options:\n"
285 #ifndef BUILD_GUI
286 " --debug print debugging information\n"
287 #endif
288 " -c, --composites hint glyph composites also\n"
289 " -d, --dehint remove all hints\n"
290 " -D, --default-script=S set default OpenType script (default: latn)\n"
291 " -f, --fallback-script=S set fallback script (default: none)\n"
292 " -F, --family-suffix=S append suffix to the family name string(s)\n"
293 " in the `name' table\n"
294 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
295 " (default: %d); value 0 means no limit\n"
296 " -h, --help display this help and exit\n"
297 " -H, --fallback-stem-width=N\n"
298 " set fallback stem width\n"
299 " (default: 50 font units at 2048 UPEM)\n"
300 #ifdef BUILD_GUI
301 " --help-all show Qt and X11 specific options also\n"
302 #endif
303 " -i, --ignore-restrictions override font license restrictions\n"
304 " -I, --detailed-info add detailed ttfautohint info\n"
305 " to the version string(s) in the `name' table\n"
306 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
307 " (default: %d)\n"
308 #ifndef BUILD_GUI
309 " -m, --control-file=FILE get control instructions from FILE\n"
310 #endif
311 " -n, --no-info don't add ttfautohint info\n"
312 " to the version string(s) in the `name' table\n"
313 " -p, --adjust-subglyphs handle subglyph adjustments in exotic fonts\n",
314 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
315 fprintf(handle,
316 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
317 " (default: %d)\n"
318 " -s, --symbol input is symbol font\n"
319 " -t, --ttfa-table add TTFA information table\n"
320 " -v, --verbose show progress information\n"
321 " -V, --version print version information and exit\n"
322 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
323 " where S is a string of up to three letters\n"
324 " with possible values `g' for grayscale,\n"
325 " `G' for GDI ClearType, and `D' for\n"
326 " DirectWrite ClearType (default: G)\n"
327 " -W, --windows-compatibility\n"
328 " add blue zones for `usWinAscent' and\n"
329 " `usWinDescent' to avoid clipping\n"
330 " -x, --increase-x-height=N increase x height for sizes in the range\n"
331 " 6<=PPEM<=N; value 0 switches off this feature\n"
332 " (default: %d)\n"
333 " -X, --x-height-snapping-exceptions=STRING\n"
334 " specify a comma-separated list of\n"
335 " x-height snapping exceptions, for example\n"
336 " \"-9, 13-17, 19\" (default: \"\")\n"
337 "\n",
338 TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT);
340 #ifdef BUILD_GUI
341 if (all)
343 fprintf(handle,
344 "Qt Options:\n"
345 " --graphicssystem=SYSTEM\n"
346 " select a different graphics system backend\n"
347 " instead of the default one\n"
348 " (possible values: `raster', `opengl')\n"
349 " --reverse set layout direction to right-to-left\n");
350 fprintf(handle,
351 " --session=ID restore the application for the given ID\n"
352 " --style=STYLE set application GUI style\n"
353 " (possible values: motif, windows, platinum)\n"
354 " --stylesheet=SHEET apply the given Qt stylesheet\n"
355 " to the application widgets\n"
356 "\n");
358 fprintf(handle,
359 "X11 options:\n"
360 " --background=COLOR set the default background color\n"
361 " and an application palette\n"
362 " (light and dark shades are calculated)\n"
363 " --bg=COLOR same as --background\n"
364 " --btn=COLOR set the default button color\n"
365 " --button=COLOR same as --btn\n"
366 " --cmap use a private color map on an 8-bit display\n"
367 " --display=NAME use the given X-server display\n");
368 fprintf(handle,
369 " --fg=COLOR set the default foreground color\n"
370 " --fn=FONTNAME set the application font\n"
371 " --font=FONTNAME same as --fn\n"
372 " --foreground=COLOR same as --fg\n"
373 " --geometry=GEOMETRY set the client geometry of first window\n"
374 " --im=SERVER set the X Input Method (XIM) server\n"
375 " --inputstyle=STYLE set X Input Method input style\n"
376 " (possible values: onthespot, overthespot,\n"
377 " offthespot, root)\n");
378 fprintf(handle,
379 " --name=NAME set the application name\n"
380 " --ncols=COUNT limit the number of colors allocated\n"
381 " in the color cube on an 8-bit display,\n"
382 " if the application is using the\n"
383 " QApplication::ManyColor color specification\n"
384 " --title=TITLE set the application title (caption)\n"
385 " --visual=VISUAL force the application\n"
386 " to use the given visual on an 8-bit display\n"
387 " (only possible value: TrueColor)\n"
388 "\n");
390 #endif // BUILD_GUI
392 fprintf(handle,
393 "The program accepts both TTF and TTC files as input.\n"
394 "Use option -i only if you have a legal permission to modify the font.\n"
395 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
396 "With option -s, use default values for standard stem width and height,\n"
397 "otherwise they are derived from script-specific characters\n"
398 "resembling the shape of character `o'.\n"
399 "\n");
400 fprintf(handle,
401 "A hint set contains the optimal hinting for a certain PPEM value;\n"
402 "the larger the hint set range (as given by options -l and -r),\n"
403 "the more hint sets get computed, usually increasing the output font size.\n"
404 "The `gasp' table of the output file always enables grayscale hinting\n"
405 "for all sizes (limited by option -G, which is handled in the bytecode).\n"
406 "Increasing the value of -G does not increase the output font size.\n"
407 "\n");
408 fprintf(handle,
409 "Options -f and -D take a four-letter string that identifies a script.\n"
410 "Option -f sets the script used as a fallback for glyphs that have\n"
411 "character codes outside of known script ranges. Option -D sets the\n"
412 "default script for handling OpenType features. Possible values are\n"
413 "\n");
414 const Tag_Names* sn = script_names;
415 for(;;)
417 fprintf(handle, " %s (%s)",
418 sn->tag, sn->description);
419 sn++;
420 if (sn->tag)
421 fprintf(handle, ",\n");
422 else
424 fprintf(handle, ".\n");
425 break;
428 fprintf(handle,
429 #ifndef BUILD_GUI
430 "\n"
431 "A control instructions file contains entries of the form\n"
432 "\n"
433 " [<font idx>] <script> <feature> @ <glyph ids>\n"
434 "\n"
435 " [<font idx>] <glyph id> l|r <points> [(<left offset>,<right offset>)]\n"
436 "\n"
437 " [<font idx>] <glyph id> n <points>\n"
438 "\n"
439 " [<font idx>] <glyph id> t|p <points> [x <shift>] [y <shift>] @ <ppems>\n"
440 "\n"
441 "<font idx> is the current subfont, <glyph id> is a glyph name or index,\n"
442 "<glyph ids> is a set of <glyph id>s, <shift> is a real number in px,\n"
443 "<points> and <ppems> are integer ranges as with option `-X'.\n"
444 "\n"
445 "<script> and <feature> are four-letter tags that define a style\n"
446 "the <glyph ids> are assigned to; possible values for <script> are the same\n"
447 "as with option -D, possible values for <feature> are\n"
448 "\n");
449 const Tag_Names* fn = feature_names;
450 for(;;)
452 fprintf(handle, " %s (%s)",
453 fn->tag, fn->description);
454 fn++;
455 if (fn->tag)
456 fprintf(handle, ",\n");
457 else
459 fprintf(handle, ".\n");
460 break;
463 fprintf(handle,
464 "\n"
465 "`l' (`r') creates one-point segments with direction left (right).\n"
466 "<left offset> and <right offset> specify offsets (in font units)\n"
467 "relative to the corresponding points to give the segments a length.\n"
468 "`n' removes points from horizontal segments, making them `weak' points.\n"
469 "`t' (`p') applies delta exceptions to the given points before (after) IUP.\n"
470 "\n"
471 "`#' starts a line comment, which gets ignored.\n"
472 "Empty lines are ignored, too.\n"
473 "\n"
474 "Key letters `l', `r', `n', `p', `t', `x', and `y' have the verbose aliases\n"
475 "`left', `right', `nodir', `point', `touch', `xshift', and `yshift'.\n"
476 #endif
477 "\n"
478 #ifdef BUILD_GUI
479 "A command-line version of this program is called `ttfautohint'.\n"
480 #else
481 "A GUI version of this program is called `ttfautohintGUI'.\n"
482 #endif
483 "\n"
484 "Report bugs to: freetype-devel@nongnu.org\n"
485 "\n"
486 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
488 if (is_error)
489 exit(EXIT_FAILURE);
490 else
491 exit(EXIT_SUCCESS);
495 static void
496 show_version()
498 fprintf(stdout,
499 #ifdef BUILD_GUI
500 "ttfautohintGUI " VERSION "\n"
501 #else
502 "ttfautohint " VERSION "\n"
503 #endif
504 "Copyright (C) 2011-2015 Werner Lemberg <wl@gnu.org>.\n"
505 "License: FreeType License (FTL) or GNU GPLv2.\n"
506 "This is free software: you are free to change and redistribute it.\n"
507 "There is NO WARRANTY, to the extent permitted by law.\n");
509 exit(EXIT_SUCCESS);
511 #endif // CONSOLE_OUTPUT
515 main(int argc,
516 char** argv)
518 int hinting_range_min = 0;
519 int hinting_range_max = 0;
520 int hinting_limit = 0;
521 int increase_x_height = 0;
522 int fallback_stem_width = 0;
524 bool have_hinting_range_min = false;
525 bool have_hinting_range_max = false;
526 bool have_hinting_limit = false;
527 bool have_increase_x_height = false;
528 bool have_fallback_stem_width = false;
530 bool gray_strong_stem_width = false;
531 bool gdi_cleartype_strong_stem_width = true;
532 bool dw_cleartype_strong_stem_width = false;
534 bool ignore_restrictions = false;
535 bool windows_compatibility = false;
536 bool adjust_subglyphs = false;
537 bool hint_composites = false;
538 bool no_info = false;
539 bool detailed_info = false;
540 bool TTFA_info = false;
541 bool symbol = false;
543 const char* default_script = NULL;
544 bool have_default_script = false;
545 const char* fallback_script = NULL;
546 bool have_fallback_script = false;
547 const char* x_height_snapping_exceptions_string = NULL;
548 bool have_x_height_snapping_exceptions_string = false;
549 const char* family_suffix = NULL;
550 bool have_family_suffix = false;
552 bool dehint = false;
554 #ifndef BUILD_GUI
555 bool debug = false;
557 TA_Progress_Func progress_func = NULL;
558 TA_Error_Func err_func = err;
559 TA_Info_Func info_func = info;
560 TA_Info_Post_Func info_post_func = info_post;
562 const char* control_name = NULL;
563 #endif
565 // For real numbers (both parsing and displaying) we only use `.' as the
566 // decimal separator; similarly, we don't want localized formats like a
567 // thousands separator for any number.
568 setlocale(LC_NUMERIC, "C");
570 // make GNU, Qt, and X11 command line options look the same;
571 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
572 // and short options specific to ttfautohint
574 // set up a new argument string
575 vector<string> new_arg_string;
576 new_arg_string.push_back(argv[0]);
578 while (1)
580 // use pseudo short options for long-only options
581 enum
583 PASS_THROUGH = CHAR_MAX + 1,
584 HELP_ALL_OPTION,
585 DEBUG_OPTION
588 static struct option long_options[] =
590 {"help", no_argument, NULL, 'h'},
591 #ifdef BUILD_GUI
592 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
593 #endif
595 // ttfautohint options
596 {"adjust-subglyphs", no_argument, NULL, 'p'},
597 {"composites", no_argument, NULL, 'c'},
598 #ifndef BUILD_GUI
599 {"control-file", required_argument, NULL, 'm'},
600 {"debug", no_argument, NULL, DEBUG_OPTION},
601 #endif
602 {"default-script", required_argument, NULL, 'D'},
603 {"dehint", no_argument, NULL, 'd'},
604 {"detailed-info", no_argument, NULL, 'I'},
605 {"fallback-script", required_argument, NULL, 'f'},
606 {"fallback-stem-width", required_argument, NULL, 'H'},
607 {"family-suffix", required_argument, NULL, 'F'},
608 {"hinting-limit", required_argument, NULL, 'G'},
609 {"hinting-range-max", required_argument, NULL, 'r'},
610 {"hinting-range-min", required_argument, NULL, 'l'},
611 {"ignore-restrictions", no_argument, NULL, 'i'},
612 {"increase-x-height", required_argument, NULL, 'x'},
613 {"no-info", no_argument, NULL, 'n'},
614 {"pre-hinting", no_argument, NULL, 'p'},
615 {"strong-stem-width", required_argument, NULL, 'w'},
616 {"symbol", no_argument, NULL, 's'},
617 {"ttfa-table", no_argument, NULL, 't'},
618 {"verbose", no_argument, NULL, 'v'},
619 {"version", no_argument, NULL, 'V'},
620 {"windows-compatibility", no_argument, NULL, 'W'},
621 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
623 // Qt options
624 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
625 {"reverse", no_argument, NULL, PASS_THROUGH},
626 {"session", required_argument, NULL, PASS_THROUGH},
627 {"style", required_argument, NULL, PASS_THROUGH},
628 {"stylesheet", required_argument, NULL, PASS_THROUGH},
630 // X11 options
631 {"background", required_argument, NULL, PASS_THROUGH},
632 {"bg", required_argument, NULL, PASS_THROUGH},
633 {"btn", required_argument, NULL, PASS_THROUGH},
634 {"button", required_argument, NULL, PASS_THROUGH},
635 {"cmap", no_argument, NULL, PASS_THROUGH},
636 {"display", required_argument, NULL, PASS_THROUGH},
637 {"fg", required_argument, NULL, PASS_THROUGH},
638 {"fn", required_argument, NULL, PASS_THROUGH},
639 {"font", required_argument, NULL, PASS_THROUGH},
640 {"foreground", required_argument, NULL, PASS_THROUGH},
641 {"geometry", required_argument, NULL, PASS_THROUGH},
642 {"im", required_argument, NULL, PASS_THROUGH},
643 {"inputstyle", required_argument, NULL, PASS_THROUGH},
644 {"name", required_argument, NULL, PASS_THROUGH},
645 {"ncols", required_argument, NULL, PASS_THROUGH},
646 {"title", required_argument, NULL, PASS_THROUGH},
647 {"visual", required_argument, NULL, PASS_THROUGH},
649 {NULL, 0, NULL, 0}
652 int option_index;
653 int c = getopt_long_only(argc, argv,
654 #ifdef BUILD_GUI
655 "cdD:f:F:G:hH:iIl:npr:stVvw:Wx:X:",
656 #else
657 "cdD:f:F:G:hH:iIl:m:npr:stVvw:Wx:X:",
658 #endif
659 long_options, &option_index);
660 if (c == -1)
661 break;
663 switch (c)
665 case 'c':
666 hint_composites = true;
667 break;
669 case 'd':
670 dehint = true;
671 break;
673 case 'D':
674 default_script = optarg;
675 have_default_script = true;
676 break;
678 case 'f':
679 fallback_script = optarg;
680 have_fallback_script = true;
681 break;
683 case 'F':
684 family_suffix = optarg;
685 have_family_suffix = true;
686 break;
688 case 'G':
689 hinting_limit = atoi(optarg);
690 have_hinting_limit = true;
691 break;
693 case 'h':
694 #ifdef CONSOLE_OUTPUT
695 show_help(false, false);
696 #endif
697 break;
699 case 'H':
700 fallback_stem_width = atoi(optarg);
701 have_fallback_stem_width = true;
702 break;
704 case 'i':
705 ignore_restrictions = true;
706 break;
708 case 'I':
709 detailed_info = true;
710 no_info = false;
711 break;
713 case 'l':
714 hinting_range_min = atoi(optarg);
715 have_hinting_range_min = true;
716 break;
718 #ifndef BUILD_GUI
719 case 'm':
720 control_name = optarg;
721 break;
722 #endif
724 case 'n':
725 no_info = true;
726 detailed_info = false;
727 break;
729 case 'p':
730 adjust_subglyphs = true;
731 break;
733 case 'r':
734 hinting_range_max = atoi(optarg);
735 have_hinting_range_max = true;
736 break;
738 case 's':
739 symbol = true;
740 break;
742 case 't':
743 TTFA_info = true;
744 break;
746 case 'v':
747 #ifndef BUILD_GUI
748 progress_func = progress;
749 #endif
750 break;
752 case 'V':
753 #ifdef CONSOLE_OUTPUT
754 show_version();
755 #endif
756 break;
758 case 'w':
759 gray_strong_stem_width = strchr(optarg, 'g') ? true : false;
760 gdi_cleartype_strong_stem_width = strchr(optarg, 'G') ? true : false;
761 dw_cleartype_strong_stem_width = strchr(optarg, 'D') ? true : false;
762 break;
764 case 'W':
765 windows_compatibility = true;
766 break;
768 case 'x':
769 increase_x_height = atoi(optarg);
770 have_increase_x_height = true;
771 break;
773 case 'X':
774 x_height_snapping_exceptions_string = optarg;
775 have_x_height_snapping_exceptions_string = true;
776 break;
778 #ifndef BUILD_GUI
779 case DEBUG_OPTION:
780 debug = true;
781 break;
782 #endif
784 #ifdef BUILD_GUI
785 case HELP_ALL_OPTION:
786 #ifdef CONSOLE_OUTPUT
787 show_help(true, false);
788 #endif
789 break;
790 #endif
792 case PASS_THROUGH:
794 // append argument with proper syntax for Qt
795 string arg;
796 arg += '-';
797 arg += long_options[option_index].name;
799 new_arg_string.push_back(arg);
800 if (optarg)
801 new_arg_string.push_back(optarg);
802 break;
805 default:
806 exit(EXIT_FAILURE);
810 if (dehint)
812 // -d makes ttfautohint ignore all other hinting options
813 have_default_script = false;
814 have_fallback_script = false;
815 have_fallback_stem_width = false;
816 have_hinting_range_max = false;
817 have_hinting_range_min = false;
818 have_hinting_limit = false;
819 have_increase_x_height = false;
820 have_x_height_snapping_exceptions_string = false;
823 if (!have_default_script)
824 default_script = "latn";
825 if (!have_fallback_script)
826 fallback_script = "none";
827 if (!have_hinting_range_min)
828 hinting_range_min = TA_HINTING_RANGE_MIN;
829 if (!have_hinting_range_max)
830 hinting_range_max = TA_HINTING_RANGE_MAX;
831 if (!have_hinting_limit)
832 hinting_limit = TA_HINTING_LIMIT;
833 if (!have_increase_x_height)
834 increase_x_height = TA_INCREASE_X_HEIGHT;
835 if (!have_x_height_snapping_exceptions_string)
836 x_height_snapping_exceptions_string = "";
837 if (!have_fallback_stem_width)
838 fallback_stem_width = 0; /* redundant, but avoids a compiler warning */
839 if (!have_family_suffix)
840 family_suffix = "";
842 #ifndef BUILD_GUI
844 if (!isatty(fileno(stderr)) && !debug)
845 setvbuf(stderr, (char*)NULL, _IONBF, BUFSIZ);
847 if (hinting_range_min < 2)
849 fprintf(stderr, "The hinting range minimum must be at least 2\n");
850 exit(EXIT_FAILURE);
852 if (hinting_range_max < hinting_range_min)
854 fprintf(stderr, "The hinting range maximum must not be smaller"
855 " than the minimum (%d)\n",
856 hinting_range_min);
857 exit(EXIT_FAILURE);
859 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
861 fprintf(stderr, "A non-zero hinting limit must not be smaller"
862 " than the hinting range maximum (%d)\n",
863 hinting_range_max);
864 exit(EXIT_FAILURE);
866 if (increase_x_height != 0 && increase_x_height < 6)
868 fprintf(stderr, "A non-zero x height increase limit"
869 " must be larger than or equal to 6\n");
870 exit(EXIT_FAILURE);
872 if (have_fallback_stem_width && fallback_stem_width <= 0)
874 fprintf(stderr, "The fallback stem width"
875 " must be a positive integer\n");
876 exit(EXIT_FAILURE);
879 if (have_default_script)
881 const Tag_Names* sn;
883 for (sn = script_names; sn->tag; sn++)
884 if (!strcmp(default_script, sn->tag))
885 break;
886 if (!sn->tag)
888 fprintf(stderr, "Unknown script tag `%s'\n", default_script);
889 exit(EXIT_FAILURE);
893 if (have_fallback_script)
895 const Tag_Names* sn;
897 for (sn = script_names; sn->tag; sn++)
898 if (!strcmp(fallback_script, sn->tag))
899 break;
900 if (!sn->tag)
902 fprintf(stderr, "Unknown script tag `%s'\n", fallback_script);
903 exit(EXIT_FAILURE);
907 if (symbol
908 && have_fallback_stem_width
909 && !strcmp(fallback_script, "none"))
910 fprintf(stderr,
911 "Warning: Setting a fallback stem width for a symbol font\n"
912 " without setting a fallback script has no effect\n");
914 if (const char* pos = check_family_suffix(family_suffix))
916 fprintf(stderr,
917 "Invalid character in family suffix:\n"
918 " %s\n"
919 " %*s\n",
920 family_suffix,
921 int(pos - family_suffix + 1), "^");
922 exit(EXIT_FAILURE);
925 int num_args = argc - optind;
927 if (num_args > 2)
928 show_help(false, true);
930 FILE* in;
931 if (num_args > 0)
933 in = fopen(argv[optind], "rb");
934 if (!in)
936 fprintf(stderr,
937 "The following error occurred while opening font `%s':\n"
938 "\n"
939 " %s\n",
940 argv[optind], strerror(errno));
941 exit(EXIT_FAILURE);
944 else
946 if (isatty(fileno(stdin)))
947 show_help(false, true);
948 in = stdin;
951 FILE* out;
952 if (num_args > 1)
954 if (!strcmp(argv[optind], argv[optind + 1]))
956 fprintf(stderr, "Input and output file names must not be identical\n");
957 exit(EXIT_FAILURE);
960 out = fopen(argv[optind + 1], "wb");
961 if (!out)
963 fprintf(stderr,
964 "The following error occurred while opening font `%s':\n"
965 "\n"
966 " %s\n",
967 argv[optind + 1], strerror(errno));
968 exit(EXIT_FAILURE);
971 else
973 if (isatty(fileno(stdout)))
974 show_help(false, true);
975 out = stdout;
978 FILE* control = NULL;
979 if (control_name)
981 control = fopen(control_name, "r");
982 if (!control)
984 fprintf(stderr,
985 "The following error occurred while open control file `%s':\n"
986 "\n"
987 " %s\n",
988 control_name, strerror(errno));
989 exit(EXIT_FAILURE);
992 else
993 control = NULL;
995 Progress_Data progress_data = {-1, 1, 0};
996 Error_Data error_data = {control_name};
997 Info_Data info_data;
999 if (!*family_suffix)
1000 info_post_func = NULL;
1002 info_data.no_info = no_info;
1003 info_data.detailed_info = detailed_info;
1004 info_data.info_string = NULL; // must be deallocated after use
1005 info_data.info_string_wide = NULL; // must be deallocated after use
1006 info_data.info_string_len = 0;
1007 info_data.info_string_wide_len = 0;
1009 info_data.control_name = control_name;
1011 info_data.hinting_range_min = hinting_range_min;
1012 info_data.hinting_range_max = hinting_range_max;
1013 info_data.hinting_limit = hinting_limit;
1015 info_data.gray_strong_stem_width = gray_strong_stem_width;
1016 info_data.gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
1017 info_data.dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
1019 info_data.windows_compatibility = windows_compatibility;
1020 info_data.adjust_subglyphs = adjust_subglyphs;
1021 info_data.hint_composites = hint_composites;
1022 info_data.increase_x_height = increase_x_height;
1023 info_data.x_height_snapping_exceptions_string = x_height_snapping_exceptions_string;
1024 info_data.family_suffix = family_suffix;
1025 info_data.family_data_head = NULL;
1026 info_data.fallback_stem_width = fallback_stem_width;
1027 info_data.symbol = symbol;
1028 info_data.TTFA_info = TTFA_info;
1030 strncpy(info_data.default_script,
1031 default_script,
1032 sizeof (info_data.default_script));
1033 strncpy(info_data.fallback_script,
1034 fallback_script,
1035 sizeof (info_data.fallback_script));
1037 info_data.dehint = dehint;
1039 if (!no_info)
1041 int ret = build_version_string(&info_data);
1042 if (ret == 1)
1043 fprintf(stderr, "Warning: Can't allocate memory"
1044 " for ttfautohint options string in `name' table\n");
1045 else if (ret == 2)
1046 fprintf(stderr, "Warning: ttfautohint options string"
1047 " in `name' table too long\n");
1050 if (in == stdin)
1051 SET_BINARY(stdin);
1052 if (out == stdout)
1053 SET_BINARY(stdout);
1055 TA_Error error =
1056 TTF_autohint("in-file, out-file, control-file,"
1057 "hinting-range-min, hinting-range-max, hinting-limit,"
1058 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
1059 "dw-cleartype-strong-stem-width,"
1060 "progress-callback, progress-callback-data,"
1061 "error-callback, error-callback-data,"
1062 "info-callback, info-post-callback, info-callback-data,"
1063 "ignore-restrictions, windows-compatibility,"
1064 "adjust-subglyphs, hint-composites,"
1065 "increase-x-height, x-height-snapping-exceptions,"
1066 "fallback-stem-width, default-script, fallback-script,"
1067 "symbol, dehint, debug, TTFA-info",
1068 in, out, control,
1069 hinting_range_min, hinting_range_max, hinting_limit,
1070 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1071 dw_cleartype_strong_stem_width,
1072 progress_func, &progress_data,
1073 err_func, &error_data,
1074 info_func, info_post_func, &info_data,
1075 ignore_restrictions, windows_compatibility,
1076 adjust_subglyphs, hint_composites,
1077 increase_x_height, x_height_snapping_exceptions_string,
1078 fallback_stem_width, default_script, fallback_script,
1079 symbol, dehint, debug, TTFA_info);
1081 if (!no_info)
1083 free(info_data.info_string);
1084 free(info_data.info_string_wide);
1087 if (in != stdin)
1088 fclose(in);
1089 if (out != stdout)
1090 fclose(out);
1091 if (control)
1092 fclose(control);
1094 exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
1096 return 0; // never reached
1098 #else // BUILD_GUI
1100 int new_argc = (int)new_arg_string.size();
1101 char** new_argv = new char*[new_argc];
1103 // construct new argc and argv variables from collected data
1104 for (int i = 0; i < new_argc; i++)
1105 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
1107 QApplication app(new_argc, new_argv);
1108 app.setApplicationName("TTFautohint");
1109 app.setApplicationVersion(VERSION);
1110 app.setOrganizationName("FreeType");
1111 app.setOrganizationDomain("freetype.org");
1113 bool alternative_layout = false;
1115 // Display the window off the screen -- to get proper window dimensions
1116 // including the frame, the window manager must have a chance to
1117 // decorate it.
1119 // We don't want to change the default window positioning algorithm of
1120 // the platform's window manager, so we create the main GUI window
1121 // twice.
1123 // The original idea, however, was to simply move the off-screen window
1124 // back to the screen with
1126 // gui.move(100, 100);
1127 // gui.setAttribute(Qt::WA_Moved, false);
1128 // gui.show();
1130 // (unsetting the `WA_Moved' attribute makes the window manager handle
1131 // the previous call to `move' as a position suggestion instead of a
1132 // request). Unfortuntely, there seems to be a bug in Qt 4.8.4 which
1133 // prevents any effect of unsetting `WA_Moved' if `show' has already
1134 // been called.
1136 Main_GUI dummy(alternative_layout,
1137 hinting_range_min, hinting_range_max, hinting_limit,
1138 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1139 dw_cleartype_strong_stem_width, increase_x_height,
1140 x_height_snapping_exceptions_string, fallback_stem_width,
1141 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1142 hint_composites, no_info, detailed_info,
1143 default_script, fallback_script, family_suffix,
1144 symbol, dehint, TTFA_info);
1146 dummy.move(-50000, -50000);
1147 dummy.show();
1149 // if the vertical size of our window is too large,
1150 // select a horizontal layout
1151 QRect screen(QApplication::desktop()->availableGeometry());
1152 if (dummy.frameGeometry().height() > screen.height())
1153 alternative_layout = true;
1156 Main_GUI gui(alternative_layout,
1157 hinting_range_min, hinting_range_max, hinting_limit,
1158 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1159 dw_cleartype_strong_stem_width, increase_x_height,
1160 x_height_snapping_exceptions_string, fallback_stem_width,
1161 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1162 hint_composites, no_info, detailed_info,
1163 default_script, fallback_script, family_suffix,
1164 symbol, dehint, TTFA_info);
1165 gui.show();
1167 return app.exec();
1169 #endif // BUILD_GUI
1172 // end of main.cpp