Remove unused structure members.
[ttfautohint.git] / frontend / main.cpp
blob503d6448da0504d21a4f8a1f80b52b0a34f78c1f
1 // main.cpp
3 // Copyright (C) 2011-2016 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 <ft2build.h>
43 # include FT_FREETYPE_H
44 # include FT_TRUETYPE_TABLES_H // for option `-T'
45 # include "info.h"
46 #endif
48 #include <ttfautohint.h>
49 #include <numberset.h>
52 #ifdef _WIN32
53 # include <fcntl.h>
54 # define SET_BINARY(f) do { \
55 if (!isatty(fileno(f))) \
56 setmode(fileno(f), O_BINARY); \
57 } while (0)
58 #endif
60 #ifndef SET_BINARY
61 # define SET_BINARY(f) do {} while (0)
62 #endif
65 using namespace std;
68 typedef struct Tag_Names_
70 const char* tag;
71 const char* description;
72 } Tag_Names;
75 // the available script tags and its descriptions are directly extracted
76 // from `ttfautohint-scripts.h'
77 #undef SCRIPT
78 #define SCRIPT(s, S, d, h, H, ss) \
79 {#s, d},
81 const Tag_Names script_names[] =
83 #include <ttfautohint-scripts.h>
84 {NULL, NULL}
88 // the available feature tags and its descriptions are directly extracted
89 // from `ttfautohint-coverages.h'
90 #undef COVERAGE
91 #define COVERAGE(n, N, d, t, t1, t2, t3, t4) \
92 {#t, d},
94 const Tag_Names feature_names[] =
96 #include <ttfautohint-coverages.h>
97 {NULL, NULL}
101 #ifndef BUILD_GUI
102 extern "C" {
104 typedef struct Progress_Data_
106 long last_sfnt;
107 bool begin;
108 int last_percent;
109 } Progress_Data;
112 static int
113 progress(long curr_idx,
114 long num_glyphs,
115 long curr_sfnt,
116 long num_sfnts,
117 void* user)
119 Progress_Data* data = (Progress_Data*)user;
121 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
123 fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts);
124 data->last_sfnt = curr_sfnt;
125 data->last_percent = 0;
126 data->begin = true;
129 if (data->begin)
131 fprintf(stderr, " %ld glyphs\n"
132 " ", num_glyphs);
133 data->begin = false;
136 // print progress approx. every 10%
137 int curr_percent = curr_idx * 100 / num_glyphs;
138 int curr_diff = curr_percent - data->last_percent;
140 if (curr_diff >= 10)
142 fprintf(stderr, " %d%%", curr_percent);
143 data->last_percent = curr_percent - curr_percent % 10;
146 if (curr_idx + 1 == num_glyphs)
147 fprintf(stderr, "\n");
149 return 0;
153 typedef struct Error_Data_
155 const char* control_name;
156 } Error_Data;
159 static void
160 err(TA_Error error,
161 const char* error_string,
162 unsigned int errlinenum,
163 const char* errline,
164 const char* errpos,
165 void* user)
167 Error_Data* data = static_cast<Error_Data*>(user);
169 if (!error)
170 return;
172 // We replace some terse error strings with more user-friendly versions.
173 if (error == TA_Err_Invalid_FreeType_Version)
174 fprintf(stderr,
175 "FreeType version 2.4.5 or higher is needed.\n"
176 "Perhaps using a wrong FreeType DLL?\n");
177 else if (error == TA_Err_Invalid_Font_Type)
178 fprintf(stderr,
179 "This font is not a valid font"
180 " in SFNT format with TrueType outlines.\n"
181 "In particular, CFF outlines are not supported.\n");
182 else if (error == TA_Err_Already_Processed)
183 fprintf(stderr,
184 "This font has already been processed with ttfautohint.\n");
185 else if (error == TA_Err_Missing_Legal_Permission)
186 fprintf(stderr,
187 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
188 "This font must not be modified"
189 " without permission of the legal owner.\n"
190 "Use command line option `-i' to continue"
191 " if you have such a permission.\n");
192 else if (error == TA_Err_Missing_Unicode_CMap)
193 fprintf(stderr,
194 "No Unicode character map.\n");
195 else if (error == TA_Err_Missing_Symbol_CMap)
196 fprintf(stderr,
197 "No symbol character map.\n");
198 else if (error == TA_Err_Missing_Glyph)
199 fprintf(stderr,
200 "No glyph for a standard character"
201 " to derive standard width and height.\n"
202 "Please check the documentation for a list of"
203 " script-specific standard characters,\n"
204 "or use option `--symbol'.\n");
205 else
207 if (error < 0x100)
208 fprintf(stderr, "An error with code 0x%02x occurred"
209 " while autohinting fonts\n",
210 error);
211 else if (error >= 0x100 && error < 0x200)
213 fprintf(stderr, "An error with code 0x%03x occurred"
214 " while parsing the argument of option `-X'",
215 error);
216 fprintf(stderr, errline ? ":\n" : ".\n");
218 if (errline)
219 fprintf(stderr, " %s\n", errline);
220 if (errpos && errline)
221 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
223 else if (error >= 0x200 && error < 0x300)
225 fprintf(stderr, "%s:", data->control_name);
226 if (errlinenum)
227 fprintf(stderr, "%d:", errlinenum);
228 if (errpos && errline)
229 fprintf(stderr, "%d:", int(errpos - errline + 1));
230 if (error_string)
231 fprintf(stderr, " %s", error_string);
232 fprintf(stderr, " (0x%02X)\n", error);
233 if (errline)
234 fprintf(stderr, " %s\n", errline);
235 if (errpos && errline)
236 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
242 } // extern "C"
243 #endif // !BUILD_GUI
246 #ifdef CONSOLE_OUTPUT
247 static void
248 show_help(bool
249 #ifdef BUILD_GUI
251 #endif
253 bool is_error)
255 FILE* handle = is_error ? stderr : stdout;
257 fprintf(handle,
258 #ifdef BUILD_GUI
259 "Usage: ttfautohintGUI [OPTION]...\n"
260 "A GUI application to replace hints in a TrueType font.\n"
261 #else
262 "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n"
263 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
264 "If OUT-FILE is missing, standard output is used instead;\n"
265 "if IN-FILE is missing also, standard input and output are used.\n"
266 #endif
267 "\n"
268 "The new hints are based on FreeType's auto-hinter.\n"
269 "\n"
270 "This program is a simple front-end to the `ttfautohint' library.\n"
271 "\n");
273 fprintf(handle,
274 "Long options can be given with one or two dashes,\n"
275 "and with and without equal sign between option and argument.\n"
276 "This means that the following forms are acceptable:\n"
277 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
278 "\n"
279 "Mandatory arguments to long options are mandatory for short options too.\n"
280 #ifdef BUILD_GUI
281 "Options not related to Qt or X11 set default values.\n"
282 #endif
283 "\n"
286 fprintf(handle,
287 "Options:\n"
288 #ifndef BUILD_GUI
289 " --debug print debugging information\n"
290 #endif
291 " -c, --composites hint glyph composites also\n"
292 " -d, --dehint remove all hints\n"
293 " -D, --default-script=S set default OpenType script (default: latn)\n"
294 " -f, --fallback-script=S set fallback script (default: none)\n"
295 " -F, --family-suffix=S append suffix to the family name string(s)\n"
296 " in the `name' table\n"
297 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
298 " (default: %d); value 0 means no limit\n"
299 " -h, --help display this help and exit\n"
300 " -H, --fallback-stem-width=N\n"
301 " set fallback stem width\n"
302 " (default: 50 font units at 2048 UPEM)\n"
303 #ifdef BUILD_GUI
304 " --help-all show Qt and X11 specific options also\n"
305 #endif
306 " -i, --ignore-restrictions override font license restrictions\n"
307 " -I, --detailed-info add detailed ttfautohint info\n"
308 " to the version string(s) in the `name' table\n"
309 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
310 " (default: %d)\n"
311 #ifndef BUILD_GUI
312 " -m, --control-file=FILE get control instructions from FILE\n"
313 #endif
314 " -n, --no-info don't add ttfautohint info\n"
315 " to the version string(s) in the `name' table\n"
316 " -p, --adjust-subglyphs handle subglyph adjustments in exotic fonts\n",
317 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
318 fprintf(handle,
319 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
320 " (default: %d)\n"
321 " -s, --symbol input is symbol font\n"
322 " -S, --fallback-scaling use fallback scaling, not hinting\n"
323 " -t, --ttfa-table add TTFA information table\n"
324 #ifndef BUILD_GUI
325 " -T, --ttfa-info display TTFA table in IN-FILE and exit\n"
326 #endif
327 " -v, --verbose show progress information\n"
328 " -V, --version print version information and exit\n"
329 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
330 " where S is a string of up to three letters\n"
331 " with possible values `g' for grayscale,\n"
332 " `G' for GDI ClearType, and `D' for\n"
333 " DirectWrite ClearType (default: G)\n"
334 " -W, --windows-compatibility\n"
335 " add blue zones for `usWinAscent' and\n"
336 " `usWinDescent' to avoid clipping\n"
337 " -x, --increase-x-height=N increase x height for sizes in the range\n"
338 " 6<=PPEM<=N; value 0 switches off this feature\n"
339 " (default: %d)\n"
340 " -X, --x-height-snapping-exceptions=STRING\n"
341 " specify a comma-separated list of\n"
342 " x-height snapping exceptions, for example\n"
343 " \"-9, 13-17, 19\" (default: \"\")\n"
344 "\n",
345 TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT);
347 #ifdef BUILD_GUI
348 if (all)
350 fprintf(handle,
351 "Qt Options:\n"
352 " --graphicssystem=SYSTEM\n"
353 " select a different graphics system backend\n"
354 " instead of the default one\n"
355 " (possible values: `raster', `opengl')\n"
356 " --reverse set layout direction to right-to-left\n");
357 fprintf(handle,
358 " --session=ID restore the application for the given ID\n"
359 " --style=STYLE set application GUI style\n"
360 " (possible values: motif, windows, platinum)\n"
361 " --stylesheet=SHEET apply the given Qt stylesheet\n"
362 " to the application widgets\n"
363 "\n");
365 fprintf(handle,
366 "X11 options:\n"
367 " --background=COLOR set the default background color\n"
368 " and an application palette\n"
369 " (light and dark shades are calculated)\n"
370 " --bg=COLOR same as --background\n"
371 " --btn=COLOR set the default button color\n"
372 " --button=COLOR same as --btn\n"
373 " --cmap use a private color map on an 8-bit display\n"
374 " --display=NAME use the given X-server display\n");
375 fprintf(handle,
376 " --fg=COLOR set the default foreground color\n"
377 " --fn=FONTNAME set the application font\n"
378 " --font=FONTNAME same as --fn\n"
379 " --foreground=COLOR same as --fg\n"
380 " --geometry=GEOMETRY set the client geometry of first window\n"
381 " --im=SERVER set the X Input Method (XIM) server\n"
382 " --inputstyle=STYLE set X Input Method input style\n"
383 " (possible values: onthespot, overthespot,\n"
384 " offthespot, root)\n");
385 fprintf(handle,
386 " --name=NAME set the application name\n"
387 " --ncols=COUNT limit the number of colors allocated\n"
388 " in the color cube on an 8-bit display,\n"
389 " if the application is using the\n"
390 " QApplication::ManyColor color specification\n"
391 " --title=TITLE set the application title (caption)\n"
392 " --visual=VISUAL force the application\n"
393 " to use the given visual on an 8-bit display\n"
394 " (only possible value: TrueColor)\n"
395 "\n");
397 #endif // BUILD_GUI
399 fprintf(handle,
400 "The program accepts both TTF and TTC files as input.\n"
401 "Use option -i only if you have a legal permission to modify the font.\n"
402 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
403 "With option -s, use default values for standard stem width and height,\n"
404 "otherwise they are derived from script-specific characters\n"
405 "resembling the shape of character `o'.\n"
406 "\n");
407 fprintf(handle,
408 "A hint set contains the optimal hinting for a certain PPEM value;\n"
409 "the larger the hint set range (as given by options -l and -r),\n"
410 "the more hint sets get computed, usually increasing the output font size.\n"
411 "The `gasp' table of the output file always enables grayscale hinting\n"
412 "for all sizes (limited by option -G, which is handled in the bytecode).\n"
413 "Increasing the value of -G does not increase the output font size.\n"
414 "\n");
415 fprintf(handle,
416 "Options -f and -D take a four-letter string that identifies a script.\n"
417 "Option -f sets the script used as a fallback for glyphs that can't be\n"
418 "associated with a known script. By default, such glyphs are hinted;\n"
419 "if option -S is set, they are scaled only instead. Option -D sets the\n"
420 "default script for handling OpenType features.\n"
421 "\n"
422 "Possible four-letter string values are\n"
423 "\n");
424 const Tag_Names* sn = script_names;
425 for(;;)
427 fprintf(handle, " %s (%s)",
428 sn->tag, sn->description);
429 sn++;
430 if (sn->tag)
431 fprintf(handle, ",\n");
432 else
434 fprintf(handle, ".\n");
435 break;
438 fprintf(handle,
439 #ifndef BUILD_GUI
440 "\n"
441 "A control instructions file contains entries of the form\n"
442 "\n"
443 " [<font idx>] <script> <feature> @ <glyph ids>\n"
444 "\n"
445 " [<font idx>] <glyph id> l|r <points> [(<left offset>,<right offset>)]\n"
446 "\n"
447 " [<font idx>] <glyph id> n <points>\n"
448 "\n"
449 " [<font idx>] <glyph id> t|p <points> [x <shift>] [y <shift>] @ <ppems>\n"
450 "\n"
451 "<font idx> is the current subfont, <glyph id> is a glyph name or index,\n"
452 "<glyph ids> is a set of <glyph id>s, <shift> is a real number in px,\n"
453 "<points> and <ppems> are integer ranges as with option `-X'.\n"
454 "\n"
455 "<script> and <feature> are four-letter tags that define a style\n"
456 "the <glyph ids> are assigned to; possible values for <script> are the same\n"
457 "as with option -D, possible values for <feature> are\n"
458 "\n");
459 const Tag_Names* fn = feature_names;
460 for(;;)
462 fprintf(handle, " %s (%s)",
463 fn->tag, fn->description);
464 fn++;
465 if (fn->tag)
466 fprintf(handle, ",\n");
467 else
469 fprintf(handle, ".\n");
470 break;
473 fprintf(handle,
474 "\n"
475 "`l' (`r') creates one-point segments with direction left (right).\n"
476 "<left offset> and <right offset> specify offsets (in font units)\n"
477 "relative to the corresponding points to give the segments a length.\n"
478 "`n' removes points from horizontal segments, making them `weak' points.\n"
479 "`t' (`p') applies delta exceptions to the given points before (after) IUP.\n"
480 "\n"
481 "`#' starts a line comment, which gets ignored.\n"
482 "Empty lines are ignored, too.\n"
483 "\n"
484 "Key letters `l', `r', `n', `p', `t', `x', and `y' have the verbose aliases\n"
485 "`left', `right', `nodir', `point', `touch', `xshift', and `yshift'.\n"
486 #endif
487 "\n"
488 #ifdef BUILD_GUI
489 "A command-line version of this program is called `ttfautohint'.\n"
490 #else
491 "A GUI version of this program is called `ttfautohintGUI'.\n"
492 #endif
493 "\n"
494 "Report bugs to: freetype-devel@nongnu.org\n"
495 "\n"
496 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
498 if (is_error)
499 exit(EXIT_FAILURE);
500 else
501 exit(EXIT_SUCCESS);
505 static void
506 show_version()
508 fprintf(stdout,
509 #ifdef BUILD_GUI
510 "ttfautohintGUI " VERSION "\n"
511 #else
512 "ttfautohint " VERSION "\n"
513 #endif
514 "Copyright (C) 2011-2016 Werner Lemberg <wl@gnu.org>.\n"
515 "License: FreeType License (FTL) or GNU GPLv2.\n"
516 "This is free software: you are free to change and redistribute it.\n"
517 "There is NO WARRANTY, to the extent permitted by law.\n");
519 exit(EXIT_SUCCESS);
521 #endif // CONSOLE_OUTPUT
524 #ifndef BUILD_GUI
526 typedef const struct FT_error_
528 int err_code;
529 const char* err_msg;
530 } FT_error;
532 static FT_error FT_errors[] =
534 #undef __FTERRORS_H__
535 #define FT_ERRORDEF(e, v, s) { e, s },
536 #define FT_ERROR_START_LIST {
537 #define FT_ERROR_END_LIST { 0, NULL } };
538 #include FT_ERRORS_H
541 static const char*
542 FT_get_error_message(FT_Error error)
544 FT_error* e = FT_errors;
546 while (e->err_code || e->err_msg)
548 if (e->err_code == error)
549 return e->err_msg;
550 e++;
553 return NULL;
557 #define BUF_SIZE 0x10000
559 #define TTAG_TTFA FT_MAKE_TAG('T', 'T', 'F', 'A')
561 static void
562 display_TTFA(FILE* in)
564 FT_Byte buf[BUF_SIZE];
565 FT_Byte* in_buf;
566 size_t in_len = 0;
567 size_t read_bytes;
569 if (in == stdin)
570 SET_BINARY(stdin);
572 in_buf = (FT_Byte*)malloc(BUF_SIZE);
573 if (!in_buf)
575 fprintf(stderr, "Can't allocate enough memory.\n");
576 exit(EXIT_FAILURE);
579 while ((read_bytes = fread(buf, 1, BUF_SIZE, in)) > 0)
581 FT_Byte* in_buf_new = (FT_Byte*)realloc(in_buf, in_len + read_bytes);
582 if (!in_buf_new)
584 fprintf(stderr, "Can't reallocate enough memory.\n");
585 exit(EXIT_FAILURE);
587 else
588 in_buf = in_buf_new;
590 memcpy(in_buf + in_len, buf, read_bytes);
592 in_len += read_bytes;
595 if (ferror(in))
597 fprintf(stderr, "Stream error while handling input font.\n");
598 exit(EXIT_FAILURE);
601 FT_Library library;
602 FT_Face face;
603 FT_Error error;
605 error = FT_Init_FreeType(&library);
606 if (error)
608 fprintf(stderr, "Can't initialize FreeType library:\n"
609 "%s\n", FT_get_error_message(error));
610 exit(EXIT_FAILURE);
613 // in a TTC, a `TTFA' table is part of the first subfont,
614 // thus we can simply pass 0 as the face index
615 error = FT_New_Memory_Face(library, in_buf, (FT_Long)in_len, 0, &face);
616 if (error)
618 fprintf(stderr, "Can't open input font:\n"
619 "%s\n", FT_get_error_message(error));
620 exit(EXIT_FAILURE);
623 FT_Byte* ttfa_buf = NULL;
624 FT_ULong ttfa_len = 0;
626 error = FT_Load_Sfnt_Table(face, TTAG_TTFA, 0, NULL, &ttfa_len);
627 if (error)
629 fprintf(stderr, "No `TTFA' table in font.\n");
630 goto Exit;
633 ttfa_buf = (FT_Byte*)malloc(ttfa_len);
634 if (!ttfa_buf)
636 fprintf(stderr, "Can't allocate enough memory.\n");
637 exit(EXIT_FAILURE);
640 error = FT_Load_Sfnt_Table(face, TTAG_TTFA, 0, ttfa_buf, &ttfa_len);
641 if (error)
643 fprintf(stderr, "Error loading `TTFA' table:\n"
644 "%s\n", FT_get_error_message(error));
645 exit(EXIT_FAILURE);
648 fprintf(stdout, "%s", ttfa_buf);
650 Exit:
651 FT_Done_Face(face);
652 FT_Done_FreeType(library);
654 free(in_buf);
655 free(ttfa_buf);
656 if (in != stdin)
657 fclose(in);
659 exit(EXIT_SUCCESS);
661 #endif
665 main(int argc,
666 char** argv)
668 int hinting_range_min = 0;
669 int hinting_range_max = 0;
670 int hinting_limit = 0;
671 int increase_x_height = 0;
672 int fallback_stem_width = 0;
674 bool have_hinting_range_min = false;
675 bool have_hinting_range_max = false;
676 bool have_hinting_limit = false;
677 bool have_increase_x_height = false;
678 bool have_fallback_stem_width = false;
680 bool gray_strong_stem_width = false;
681 bool gdi_cleartype_strong_stem_width = true;
682 bool dw_cleartype_strong_stem_width = false;
684 bool ignore_restrictions = false;
685 bool windows_compatibility = false;
686 bool adjust_subglyphs = false;
687 bool hint_composites = false;
688 bool no_info = false;
689 bool detailed_info = false;
690 bool TTFA_info = false;
691 #ifndef BUILD_GUI
692 bool show_TTFA_info = false;
693 #endif
694 bool symbol = false;
695 bool fallback_scaling = false;
697 const char* default_script = NULL;
698 bool have_default_script = false;
699 const char* fallback_script = NULL;
700 bool have_fallback_script = false;
701 const char* x_height_snapping_exceptions_string = NULL;
702 bool have_x_height_snapping_exceptions_string = false;
703 const char* family_suffix = NULL;
704 bool have_family_suffix = false;
706 bool dehint = false;
708 #ifndef BUILD_GUI
709 bool debug = false;
711 TA_Progress_Func progress_func = NULL;
712 TA_Error_Func err_func = err;
713 TA_Info_Func info_func = info;
714 TA_Info_Post_Func info_post_func = info_post;
716 const char* control_name = NULL;
718 unsigned long long epoch = ULLONG_MAX;
719 #endif
721 // For real numbers (both parsing and displaying) we only use `.' as the
722 // decimal separator; similarly, we don't want localized formats like a
723 // thousands separator for any number.
724 setlocale(LC_NUMERIC, "C");
726 // make GNU, Qt, and X11 command line options look the same;
727 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
728 // and short options specific to ttfautohint
730 // set up a new argument string
731 vector<string> new_arg_string;
732 new_arg_string.push_back(argv[0]);
734 while (1)
736 // use pseudo short options for long-only options
737 enum
739 PASS_THROUGH = CHAR_MAX + 1,
740 HELP_ALL_OPTION,
741 DEBUG_OPTION
744 static struct option long_options[] =
746 {"help", no_argument, NULL, 'h'},
747 #ifdef BUILD_GUI
748 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
749 #endif
751 // ttfautohint options
752 {"adjust-subglyphs", no_argument, NULL, 'p'},
753 {"composites", no_argument, NULL, 'c'},
754 #ifndef BUILD_GUI
755 {"control-file", required_argument, NULL, 'm'},
756 {"debug", no_argument, NULL, DEBUG_OPTION},
757 #endif
758 {"default-script", required_argument, NULL, 'D'},
759 {"dehint", no_argument, NULL, 'd'},
760 {"detailed-info", no_argument, NULL, 'I'},
761 {"fallback-scaling", no_argument, NULL, 'S'},
762 {"fallback-script", required_argument, NULL, 'f'},
763 {"fallback-stem-width", required_argument, NULL, 'H'},
764 {"family-suffix", required_argument, NULL, 'F'},
765 {"hinting-limit", required_argument, NULL, 'G'},
766 {"hinting-range-max", required_argument, NULL, 'r'},
767 {"hinting-range-min", required_argument, NULL, 'l'},
768 {"ignore-restrictions", no_argument, NULL, 'i'},
769 {"increase-x-height", required_argument, NULL, 'x'},
770 {"no-info", no_argument, NULL, 'n'},
771 {"pre-hinting", no_argument, NULL, 'p'},
772 {"strong-stem-width", required_argument, NULL, 'w'},
773 {"symbol", no_argument, NULL, 's'},
774 {"ttfa-table", no_argument, NULL, 't'},
775 #ifndef BUILD_GUI
776 {"ttfa-info", no_argument, NULL, 'T'},
777 #endif
778 {"verbose", no_argument, NULL, 'v'},
779 {"version", no_argument, NULL, 'V'},
780 {"windows-compatibility", no_argument, NULL, 'W'},
781 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
783 // Qt options
784 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
785 {"reverse", no_argument, NULL, PASS_THROUGH},
786 {"session", required_argument, NULL, PASS_THROUGH},
787 {"style", required_argument, NULL, PASS_THROUGH},
788 {"stylesheet", required_argument, NULL, PASS_THROUGH},
790 // X11 options
791 {"background", required_argument, NULL, PASS_THROUGH},
792 {"bg", required_argument, NULL, PASS_THROUGH},
793 {"btn", required_argument, NULL, PASS_THROUGH},
794 {"button", required_argument, NULL, PASS_THROUGH},
795 {"cmap", no_argument, NULL, PASS_THROUGH},
796 {"display", required_argument, NULL, PASS_THROUGH},
797 {"fg", required_argument, NULL, PASS_THROUGH},
798 {"fn", required_argument, NULL, PASS_THROUGH},
799 {"font", required_argument, NULL, PASS_THROUGH},
800 {"foreground", required_argument, NULL, PASS_THROUGH},
801 {"geometry", required_argument, NULL, PASS_THROUGH},
802 {"im", required_argument, NULL, PASS_THROUGH},
803 {"inputstyle", required_argument, NULL, PASS_THROUGH},
804 {"name", required_argument, NULL, PASS_THROUGH},
805 {"ncols", required_argument, NULL, PASS_THROUGH},
806 {"title", required_argument, NULL, PASS_THROUGH},
807 {"visual", required_argument, NULL, PASS_THROUGH},
809 {NULL, 0, NULL, 0}
812 int option_index;
813 int c = getopt_long_only(argc, argv,
814 #ifdef BUILD_GUI
815 "cdD:f:F:G:hH:iIl:npr:sStvVw:Wx:X:",
816 #else
817 "cdD:f:F:G:hH:iIl:m:npr:sStTvVw:Wx:X:",
818 #endif
819 long_options, &option_index);
820 if (c == -1)
821 break;
823 switch (c)
825 case 'c':
826 hint_composites = true;
827 break;
829 case 'd':
830 dehint = true;
831 break;
833 case 'D':
834 default_script = optarg;
835 have_default_script = true;
836 break;
838 case 'f':
839 fallback_script = optarg;
840 have_fallback_script = true;
841 break;
843 case 'F':
844 family_suffix = optarg;
845 have_family_suffix = true;
846 break;
848 case 'G':
849 hinting_limit = atoi(optarg);
850 have_hinting_limit = true;
851 break;
853 case 'h':
854 #ifdef CONSOLE_OUTPUT
855 show_help(false, false);
856 #endif
857 break;
859 case 'H':
860 fallback_stem_width = atoi(optarg);
861 have_fallback_stem_width = true;
862 break;
864 case 'i':
865 ignore_restrictions = true;
866 break;
868 case 'I':
869 detailed_info = true;
870 no_info = false;
871 break;
873 case 'l':
874 hinting_range_min = atoi(optarg);
875 have_hinting_range_min = true;
876 break;
878 #ifndef BUILD_GUI
879 case 'm':
880 control_name = optarg;
881 break;
882 #endif
884 case 'n':
885 no_info = true;
886 detailed_info = false;
887 break;
889 case 'p':
890 adjust_subglyphs = true;
891 break;
893 case 'r':
894 hinting_range_max = atoi(optarg);
895 have_hinting_range_max = true;
896 break;
898 case 's':
899 symbol = true;
900 break;
902 case 'S':
903 fallback_scaling = true;
904 break;
906 case 't':
907 TTFA_info = true;
908 break;
910 #ifndef BUILD_GUI
911 case 'T':
912 show_TTFA_info = true;
913 break;
915 case 'v':
916 progress_func = progress;
917 #endif
918 break;
920 case 'V':
921 #ifdef CONSOLE_OUTPUT
922 show_version();
923 #endif
924 break;
926 case 'w':
927 gray_strong_stem_width = strchr(optarg, 'g') ? true : false;
928 gdi_cleartype_strong_stem_width = strchr(optarg, 'G') ? true : false;
929 dw_cleartype_strong_stem_width = strchr(optarg, 'D') ? true : false;
930 break;
932 case 'W':
933 windows_compatibility = true;
934 break;
936 case 'x':
937 increase_x_height = atoi(optarg);
938 have_increase_x_height = true;
939 break;
941 case 'X':
942 x_height_snapping_exceptions_string = optarg;
943 have_x_height_snapping_exceptions_string = true;
944 break;
946 #ifndef BUILD_GUI
947 case DEBUG_OPTION:
948 debug = true;
949 break;
950 #endif
952 #ifdef BUILD_GUI
953 case HELP_ALL_OPTION:
954 #ifdef CONSOLE_OUTPUT
955 show_help(true, false);
956 #endif
957 break;
958 #endif
960 case PASS_THROUGH:
962 // append argument with proper syntax for Qt
963 string arg;
964 arg += '-';
965 arg += long_options[option_index].name;
967 new_arg_string.push_back(arg);
968 if (optarg)
969 new_arg_string.push_back(optarg);
970 break;
973 default:
974 exit(EXIT_FAILURE);
978 if (dehint)
980 // -d makes ttfautohint ignore all other hinting options
981 have_default_script = false;
982 have_fallback_script = false;
983 have_fallback_stem_width = false;
984 have_hinting_range_max = false;
985 have_hinting_range_min = false;
986 have_hinting_limit = false;
987 have_increase_x_height = false;
988 have_x_height_snapping_exceptions_string = false;
991 #ifndef BUILD_GUI
992 if (show_TTFA_info)
994 // -T makes ttfautohint ignore even more options
995 have_default_script = false;
996 have_fallback_script = false;
997 have_fallback_stem_width = false;
998 have_hinting_range_max = false;
999 have_hinting_range_min = false;
1000 have_hinting_limit = false;
1001 have_increase_x_height = false;
1002 have_x_height_snapping_exceptions_string = false;
1003 have_family_suffix = false;
1004 debug = false;
1006 #endif
1008 if (!have_default_script)
1009 default_script = "latn";
1010 if (!have_fallback_script)
1011 fallback_script = "none";
1012 if (!have_hinting_range_min)
1013 hinting_range_min = TA_HINTING_RANGE_MIN;
1014 if (!have_hinting_range_max)
1015 hinting_range_max = TA_HINTING_RANGE_MAX;
1016 if (!have_hinting_limit)
1017 hinting_limit = TA_HINTING_LIMIT;
1018 if (!have_increase_x_height)
1019 increase_x_height = TA_INCREASE_X_HEIGHT;
1020 if (!have_x_height_snapping_exceptions_string)
1021 x_height_snapping_exceptions_string = "";
1022 if (!have_fallback_stem_width)
1023 fallback_stem_width = 0; // redundant, but avoids a compiler warning
1024 if (!have_family_suffix)
1025 family_suffix = "";
1027 #ifndef BUILD_GUI
1029 // check SOURE_DATE_EPOCH environment variable
1030 const char* source_date_epoch = getenv("SOURCE_DATE_EPOCH");
1031 if (source_date_epoch)
1033 char* endptr;
1034 errno = 0;
1036 epoch = strtoull(source_date_epoch, &endptr, 10);
1037 if ((errno == ERANGE && (epoch == ULLONG_MAX
1038 || epoch == 0))
1039 || (errno != 0
1040 && epoch == 0))
1042 fprintf(stderr,
1043 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1044 " strtoull: %s\n",
1045 strerror(errno));
1046 epoch = ULLONG_MAX;
1048 else if (endptr == source_date_epoch)
1050 fprintf(stderr,
1051 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1052 " No digits were found: %s\n",
1053 endptr);
1054 epoch = ULLONG_MAX;
1056 else if (*endptr != '\0')
1058 fprintf(stderr,
1059 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1060 " Trailing garbage: %s\n",
1061 endptr);
1062 epoch = ULLONG_MAX;
1064 else if (epoch > ULONG_MAX)
1066 fprintf(stderr,
1067 "Environment variable `SOURCE_DATE_EPOCH' ignored\n"
1068 " value must be smaller than or equal to %lu\n"
1069 " but was found to be %llu\n",
1070 ULONG_MAX, epoch);
1071 epoch = ULLONG_MAX;
1075 if (!isatty(fileno(stderr)) && !debug)
1076 setvbuf(stderr, (char*)NULL, _IONBF, BUFSIZ);
1078 if (hinting_range_min < 2)
1080 fprintf(stderr, "The hinting range minimum must be at least 2\n");
1081 exit(EXIT_FAILURE);
1083 if (hinting_range_max < hinting_range_min)
1085 fprintf(stderr, "The hinting range maximum must not be smaller"
1086 " than the minimum (%d)\n",
1087 hinting_range_min);
1088 exit(EXIT_FAILURE);
1090 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
1092 fprintf(stderr, "A non-zero hinting limit must not be smaller"
1093 " than the hinting range maximum (%d)\n",
1094 hinting_range_max);
1095 exit(EXIT_FAILURE);
1097 if (increase_x_height != 0 && increase_x_height < 6)
1099 fprintf(stderr, "A non-zero x height increase limit"
1100 " must be larger than or equal to 6\n");
1101 exit(EXIT_FAILURE);
1103 if (have_fallback_stem_width && fallback_stem_width <= 0)
1105 fprintf(stderr, "The fallback stem width"
1106 " must be a positive integer\n");
1107 exit(EXIT_FAILURE);
1110 if (have_default_script)
1112 const Tag_Names* sn;
1114 for (sn = script_names; sn->tag; sn++)
1115 if (!strcmp(default_script, sn->tag))
1116 break;
1117 if (!sn->tag)
1119 fprintf(stderr, "Unknown script tag `%s'\n", default_script);
1120 exit(EXIT_FAILURE);
1124 if (have_fallback_script)
1126 const Tag_Names* sn;
1128 for (sn = script_names; sn->tag; sn++)
1129 if (!strcmp(fallback_script, sn->tag))
1130 break;
1131 if (!sn->tag)
1133 fprintf(stderr, "Unknown script tag `%s'\n", fallback_script);
1134 exit(EXIT_FAILURE);
1138 if (symbol
1139 && have_fallback_stem_width
1140 && fallback_scaling)
1141 fprintf(stderr,
1142 "Warning: Setting a fallback stem width for a symbol font\n"
1143 " with fallback scaling only has no effect\n");
1145 if (const char* pos = check_family_suffix(family_suffix))
1147 fprintf(stderr,
1148 "Invalid character in family suffix:\n"
1149 " %s\n"
1150 " %*s\n",
1151 family_suffix,
1152 int(pos - family_suffix + 1), "^");
1153 exit(EXIT_FAILURE);
1156 int num_args = argc - optind;
1158 if (num_args > 2)
1159 show_help(false, true);
1161 FILE* in;
1162 if (num_args > 0)
1164 in = fopen(argv[optind], "rb");
1165 if (!in)
1167 fprintf(stderr,
1168 "The following error occurred while opening font `%s':\n"
1169 "\n"
1170 " %s\n",
1171 argv[optind], strerror(errno));
1172 exit(EXIT_FAILURE);
1175 else
1177 if (isatty(fileno(stdin)))
1178 show_help(false, true);
1179 in = stdin;
1182 if (show_TTFA_info)
1183 display_TTFA(in); // this function doesn't return
1185 FILE* out;
1186 if (num_args > 1)
1188 if (!strcmp(argv[optind], argv[optind + 1]))
1190 fprintf(stderr, "Input and output file names must not be identical\n");
1191 exit(EXIT_FAILURE);
1194 out = fopen(argv[optind + 1], "wb");
1195 if (!out)
1197 fprintf(stderr,
1198 "The following error occurred while opening font `%s':\n"
1199 "\n"
1200 " %s\n",
1201 argv[optind + 1], strerror(errno));
1202 exit(EXIT_FAILURE);
1205 else
1207 if (isatty(fileno(stdout)))
1208 show_help(false, true);
1209 out = stdout;
1212 FILE* control = NULL;
1213 if (control_name)
1215 control = fopen(control_name, "r");
1216 if (!control)
1218 fprintf(stderr,
1219 "The following error occurred while open control file `%s':\n"
1220 "\n"
1221 " %s\n",
1222 control_name, strerror(errno));
1223 exit(EXIT_FAILURE);
1226 else
1227 control = NULL;
1229 Progress_Data progress_data = {-1, 1, 0};
1230 Error_Data error_data = {control_name};
1231 Info_Data info_data;
1233 if (!*family_suffix)
1234 info_post_func = NULL;
1236 info_data.no_info = no_info;
1237 info_data.detailed_info = detailed_info;
1238 info_data.info_string = NULL; // must be deallocated after use
1239 info_data.info_string_wide = NULL; // must be deallocated after use
1240 info_data.info_string_len = 0;
1241 info_data.info_string_wide_len = 0;
1243 info_data.control_name = control_name;
1245 info_data.hinting_range_min = hinting_range_min;
1246 info_data.hinting_range_max = hinting_range_max;
1247 info_data.hinting_limit = hinting_limit;
1249 info_data.gray_strong_stem_width = gray_strong_stem_width;
1250 info_data.gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
1251 info_data.dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
1253 info_data.windows_compatibility = windows_compatibility;
1254 info_data.adjust_subglyphs = adjust_subglyphs;
1255 info_data.hint_composites = hint_composites;
1256 info_data.increase_x_height = increase_x_height;
1257 info_data.x_height_snapping_exceptions_string = x_height_snapping_exceptions_string;
1258 info_data.family_suffix = family_suffix;
1259 info_data.family_data_head = NULL;
1260 info_data.fallback_stem_width = fallback_stem_width;
1261 info_data.symbol = symbol;
1262 info_data.fallback_scaling = fallback_scaling;
1263 info_data.TTFA_info = TTFA_info;
1265 strncpy(info_data.default_script,
1266 default_script,
1267 sizeof (info_data.default_script));
1268 strncpy(info_data.fallback_script,
1269 fallback_script,
1270 sizeof (info_data.fallback_script));
1272 info_data.dehint = dehint;
1274 if (!no_info)
1276 int ret = build_version_string(&info_data);
1277 if (ret == 1)
1278 fprintf(stderr, "Warning: Can't allocate memory"
1279 " for ttfautohint options string in `name' table\n");
1280 else if (ret == 2)
1281 fprintf(stderr, "Warning: ttfautohint options string"
1282 " in `name' table too long\n");
1285 if (in == stdin)
1286 SET_BINARY(stdin);
1287 if (out == stdout)
1288 SET_BINARY(stdout);
1290 TA_Error error =
1291 TTF_autohint("in-file, out-file, control-file,"
1292 "hinting-range-min, hinting-range-max, hinting-limit,"
1293 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
1294 "dw-cleartype-strong-stem-width,"
1295 "progress-callback, progress-callback-data,"
1296 "error-callback, error-callback-data,"
1297 "info-callback, info-post-callback, info-callback-data,"
1298 "ignore-restrictions, windows-compatibility,"
1299 "adjust-subglyphs, hint-composites,"
1300 "increase-x-height, x-height-snapping-exceptions,"
1301 "fallback-stem-width, default-script,"
1302 "fallback-script, fallback-scaling,"
1303 "symbol, dehint, debug, TTFA-info, epoch",
1304 in, out, control,
1305 hinting_range_min, hinting_range_max, hinting_limit,
1306 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1307 dw_cleartype_strong_stem_width,
1308 progress_func, &progress_data,
1309 err_func, &error_data,
1310 info_func, info_post_func, &info_data,
1311 ignore_restrictions, windows_compatibility,
1312 adjust_subglyphs, hint_composites,
1313 increase_x_height, x_height_snapping_exceptions_string,
1314 fallback_stem_width, default_script,
1315 fallback_script, fallback_scaling,
1316 symbol, dehint, debug, TTFA_info, epoch);
1318 if (!no_info)
1320 free(info_data.info_string);
1321 free(info_data.info_string_wide);
1324 if (in != stdin)
1325 fclose(in);
1326 if (out != stdout)
1327 fclose(out);
1328 if (control)
1329 fclose(control);
1331 exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
1333 return 0; // never reached
1335 #else // BUILD_GUI
1337 int new_argc = (int)new_arg_string.size();
1338 char** new_argv = new char*[new_argc];
1340 // construct new argc and argv variables from collected data
1341 for (int i = 0; i < new_argc; i++)
1342 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
1344 QApplication app(new_argc, new_argv);
1345 app.setApplicationName("TTFautohint");
1346 app.setApplicationVersion(VERSION);
1347 app.setOrganizationName("FreeType");
1348 app.setOrganizationDomain("freetype.org");
1350 bool alternative_layout = false;
1352 // Display the window off the screen -- to get proper window dimensions
1353 // including the frame, the window manager must have a chance to
1354 // decorate it.
1356 // We don't want to change the default window positioning algorithm of
1357 // the platform's window manager, so we create the main GUI window
1358 // twice.
1360 // The original idea, however, was to simply move the off-screen window
1361 // back to the screen with
1363 // gui.move(100, 100);
1364 // gui.setAttribute(Qt::WA_Moved, false);
1365 // gui.show();
1367 // (unsetting the `WA_Moved' attribute makes the window manager handle
1368 // the previous call to `move' as a position suggestion instead of a
1369 // request). Unfortuntely, there seems to be a bug in Qt 4.8.4 which
1370 // prevents any effect of unsetting `WA_Moved' if `show' has already
1371 // been called.
1373 Main_GUI dummy(alternative_layout,
1374 hinting_range_min, hinting_range_max, hinting_limit,
1375 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1376 dw_cleartype_strong_stem_width, increase_x_height,
1377 x_height_snapping_exceptions_string, fallback_stem_width,
1378 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1379 hint_composites, no_info, detailed_info,
1380 default_script, fallback_script, fallback_scaling,
1381 family_suffix, symbol, dehint, TTFA_info);
1383 dummy.move(-50000, -50000);
1384 dummy.show();
1386 // if the vertical size of our window is too large,
1387 // select a horizontal layout
1388 QRect screen(QApplication::desktop()->availableGeometry());
1389 if (dummy.frameGeometry().height() > screen.height())
1390 alternative_layout = true;
1393 Main_GUI gui(alternative_layout,
1394 hinting_range_min, hinting_range_max, hinting_limit,
1395 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
1396 dw_cleartype_strong_stem_width, increase_x_height,
1397 x_height_snapping_exceptions_string, fallback_stem_width,
1398 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1399 hint_composites, no_info, detailed_info,
1400 default_script, fallback_script, fallback_scaling,
1401 family_suffix, symbol, dehint, TTFA_info);
1402 gui.show();
1404 return app.exec();
1406 #endif // BUILD_GUI
1409 // end of main.cpp