[ttfautohint] Make option `-R` work on Windows.
[ttfautohint.git] / frontend / main.cpp
blob7706e2c1768ca0ed2c697da0d5914dd0cb57637d
1 // main.cpp
3 // Copyright (C) 2011-2022 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 #ifdef 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 #ifndef BUILD_GUI
53 # ifdef _WIN32
54 # include <fcntl.h>
55 # define SET_BINARY(f) do { \
56 if (!isatty(fileno(f))) \
57 setmode(fileno(f), O_BINARY); \
58 } while (0)
59 # endif
61 # ifndef SET_BINARY
62 # define SET_BINARY(f) do {} while (0)
63 # endif
64 #endif
67 using namespace std;
70 typedef struct Tag_Names_
72 const char* tag;
73 const char* description;
74 } Tag_Names;
77 // the available script tags and its descriptions are directly extracted
78 // from `ttfautohint-scripts.h'
79 #undef SCRIPT
80 #define SCRIPT(s, S, d, h, H, ss) \
81 {#s, d},
83 const Tag_Names script_names[] =
85 #include <ttfautohint-scripts.h>
86 {NULL, NULL}
90 #ifndef BUILD_GUI
91 // the available feature tags and its descriptions are directly extracted
92 // from `ttfautohint-coverages.h'
93 # undef COVERAGE
94 # define COVERAGE(n, N, d, t, t1, t2, t3, t4) \
95 {#t, d},
97 const Tag_Names feature_names[] =
99 #include <ttfautohint-coverages.h>
100 {NULL, NULL}
102 #endif
105 #ifndef BUILD_GUI
106 extern "C" {
108 typedef struct Progress_Data_
110 long last_sfnt;
111 bool begin;
112 int last_percent;
113 } Progress_Data;
116 static int
117 progress(long curr_idx,
118 long num_glyphs,
119 long curr_sfnt,
120 long num_sfnts,
121 void* user)
123 Progress_Data* data = (Progress_Data*)user;
125 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
127 fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts);
128 data->last_sfnt = curr_sfnt;
129 data->last_percent = 0;
130 data->begin = true;
133 if (data->begin)
135 fprintf(stderr, " %ld glyphs\n"
136 " ", num_glyphs);
137 data->begin = false;
140 // print progress approx. every 10%
141 int curr_percent = int(curr_idx * 100 / num_glyphs);
142 int curr_diff = curr_percent - data->last_percent;
144 if (curr_diff >= 10)
146 fprintf(stderr, " %d%%", curr_percent);
147 data->last_percent = curr_percent - curr_percent % 10;
150 if (curr_idx + 1 == num_glyphs)
151 fprintf(stderr, "\n");
153 return 0;
157 typedef struct Error_Data_
159 const char* control_name;
160 } Error_Data;
163 static void
164 err(TA_Error error,
165 const char* error_string,
166 unsigned int errlinenum,
167 const char* errline,
168 const char* errpos,
169 void* user)
171 Error_Data* data = static_cast<Error_Data*>(user);
173 if (!error)
174 return;
176 // We replace some terse error strings with more user-friendly versions.
177 if (error == TA_Err_Invalid_FreeType_Version)
178 fprintf(stderr,
179 "FreeType version 2.4.5 or higher is needed.\n"
180 "Perhaps using a wrong FreeType DLL?\n");
181 else if (error == TA_Err_Invalid_Font_Type)
182 fprintf(stderr,
183 "This font is not a valid font"
184 " in SFNT format with TrueType outlines.\n"
185 "In particular, CFF outlines are not supported.\n");
186 else if (error == TA_Err_Already_Processed)
187 fprintf(stderr,
188 "This font has already been processed with ttfautohint.\n");
189 else if (error == TA_Err_Missing_Legal_Permission)
190 fprintf(stderr,
191 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
192 "This font must not be modified"
193 " without permission of the legal owner.\n"
194 "Use command line option `-i' to continue"
195 " if you have such a permission.\n");
196 else if (error == TA_Err_Missing_Unicode_CMap)
197 fprintf(stderr,
198 "No Unicode character map.\n");
199 else if (error == TA_Err_Missing_Symbol_CMap)
200 fprintf(stderr,
201 "No symbol character map.\n");
202 else if (error == TA_Err_Missing_Glyph)
203 fprintf(stderr,
204 "No glyph for a standard character"
205 " to derive standard width and height.\n"
206 "Please check the documentation for a list of"
207 " script-specific standard characters,\n"
208 "or use option `--symbol'.\n");
209 else
211 if (error < 0x100)
213 fprintf(stderr, "An error with code 0x%02x occurred"
214 " while autohinting fonts\n",
215 error);
216 if (error_string)
217 fprintf(stderr, " %s", error_string);
219 else if (error >= 0x100 && error < 0x200)
221 fprintf(stderr, "An error with code 0x%03x occurred"
222 " while parsing the argument of option `-X'",
223 error);
224 fprintf(stderr, errline ? ":\n" : ".\n");
226 if (errline)
227 fprintf(stderr, " %s\n", errline);
228 if (errpos && errline)
229 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
231 else if (error >= 0x200 && error < 0x300)
233 fprintf(stderr, "%s:", data->control_name);
234 if (errlinenum)
235 fprintf(stderr, "%u:", errlinenum);
236 if (errpos && errline)
237 fprintf(stderr, "%d:", int(errpos - errline + 1));
238 if (error_string)
239 fprintf(stderr, " %s", error_string);
240 fprintf(stderr, " (0x%02X)\n", error);
241 if (errline)
242 fprintf(stderr, " %s\n", errline);
243 if (errpos && errline)
244 fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^");
246 else if (error >= 0x300 && error < 0x400)
248 error -= 0x300;
249 fprintf(stderr, "An error with code 0x%02x occurred"
250 " while loading the reference font\n",
251 error);
252 if (error_string)
253 fprintf(stderr, " %s", error_string);
259 } // extern "C"
260 #endif // !BUILD_GUI
263 #ifdef CONSOLE_OUTPUT
264 static void
265 show_help(bool
266 #ifdef BUILD_GUI
268 #endif
270 bool is_error)
272 FILE* handle = is_error ? stderr : stdout;
274 fprintf(handle,
275 #ifdef BUILD_GUI
276 "Usage: ttfautohintGUI [OPTION]...\n"
277 "A GUI application to replace hints in a TrueType font.\n"
278 #else
279 "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n"
280 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
281 "If OUT-FILE is missing, standard output is used instead;\n"
282 "if IN-FILE is missing also, standard input and output are used.\n"
283 #endif
284 "\n"
285 "The new hints are based on FreeType's auto-hinter.\n"
286 "\n"
287 "This program is a simple front-end to the `ttfautohint' library.\n"
288 "\n");
290 fprintf(handle,
291 "Long options can be given with one or two dashes,\n"
292 "and with and without equal sign between option and argument.\n"
293 "This means that the following forms are acceptable:\n"
294 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
295 "\n"
296 "Mandatory arguments to long options are mandatory for short options too.\n"
297 #ifdef BUILD_GUI
298 "Options not related to Qt or X11 set default values.\n"
299 #endif
300 "\n"
303 fprintf(handle,
304 "Options:\n"
305 #ifndef BUILD_GUI
306 " --debug print debugging information\n"
307 #endif
308 " -a, --stem-width-mode=S select stem width mode for grayscale, GDI\n"
309 " ClearType, and DW ClearType, where S is a\n"
310 " string of three letters with possible values\n"
311 " `n' for natural, `q' for quantized, and `s'\n"
312 " for strong (default: qsq)\n"
313 " -c, --composites hint glyph composites also\n"
314 " -d, --dehint remove all hints\n"
315 " -D, --default-script=S set default OpenType script (default: latn)\n"
316 " -f, --fallback-script=S set fallback script (default: none)\n"
317 " -F, --family-suffix=S append suffix to the family name string(s)\n"
318 " in the `name' table\n"
319 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
320 " (default: %d); value 0 means no limit\n"
321 " -h, --help display this help and exit\n"
322 " -H, --fallback-stem-width=N\n"
323 " set fallback stem width\n"
324 " (default: 50 font units at 2048 UPEM)\n"
325 #ifdef BUILD_GUI
326 " --help-all show Qt and X11 specific options also\n"
327 #endif
328 " -i, --ignore-restrictions override font license restrictions\n"
329 " -I, --detailed-info add detailed ttfautohint info\n"
330 " to the version string(s) in the `name' table\n"
331 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
332 " (default: %d)\n"
333 #ifndef BUILD_GUI
334 " -m, --control-file=FILE get control instructions from FILE\n"
335 #endif
336 " -n, --no-info don't add ttfautohint info\n"
337 " to the version string(s) in the `name' table\n"
338 " -p, --adjust-subglyphs handle subglyph adjustments in exotic fonts\n",
339 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
340 fprintf(handle,
341 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
342 " (default: %d)\n"
343 #ifndef BUILD_GUI
344 " -R, --reference=FILE derive blue zones from reference font FILE\n"
345 #endif
346 " -s, --symbol input is symbol font\n"
347 " -S, --fallback-scaling use fallback scaling, not hinting\n"
348 " -t, --ttfa-table add TTFA information table\n"
349 #ifndef BUILD_GUI
350 " -T, --ttfa-info display TTFA table in IN-FILE and exit\n"
351 #endif
352 " -v, --verbose show progress information\n"
353 " -V, --version print version information and exit\n"
354 " -W, --windows-compatibility\n"
355 " add blue zones for `usWinAscent' and\n"
356 " `usWinDescent' to avoid clipping\n"
357 " -x, --increase-x-height=N increase x height for sizes in the range\n"
358 " 6<=PPEM<=N; value 0 switches off this feature\n"
359 " (default: %d)\n"
360 " -X, --x-height-snapping-exceptions=STRING\n"
361 " specify a comma-separated list of\n"
362 " x-height snapping exceptions, for example\n"
363 " \"-9, 13-17, 19\" (default: \"\")\n"
364 #ifndef BUILD_GUI
365 " -Z, --reference-index=N face index of reference font (default: 0)\n"
366 #endif
367 "\n",
368 TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT);
370 #ifdef BUILD_GUI
371 if (all)
373 fprintf(handle,
374 "Qt Options:\n"
375 #if QT_VERSION < 0x050000
376 " --graphicssystem=SYSTEM\n"
377 " select a different graphics system backend\n"
378 " instead of the default one\n"
379 " (possible values: `raster', `opengl')\n"
380 #endif
381 " --reverse set layout direction to right-to-left\n");
382 fprintf(handle,
383 #if QT_VERSION < 0x050000
384 " --session=ID restore the application for the given ID\n"
385 #endif
386 " --style=STYLE set application GUI style\n"
387 " (available values like `windows' or `gtk'\n"
388 " depend on Qt version and installed plug-ins)\n"
389 " --stylesheet=SHEET apply the given Qt stylesheet\n"
390 " to the application widgets\n"
391 "\n");
393 #if QT_VERSION < 0x050000
394 fprintf(handle,
395 "X11 options:\n"
396 " --background=COLOR set the default background color\n"
397 " and an application palette\n"
398 " (light and dark shades are calculated)\n"
399 " --bg=COLOR same as --background\n"
400 " --btn=COLOR set the default button color\n"
401 " --button=COLOR same as --btn\n"
402 " --cmap use a private color map on an 8-bit display\n"
403 " --display=NAME use the given X-server display\n");
404 fprintf(handle,
405 " --fg=COLOR set the default foreground color\n"
406 " --fn=FONTNAME set the application font\n"
407 " --font=FONTNAME same as --fn\n"
408 " --foreground=COLOR same as --fg\n"
409 " --geometry=GEOMETRY set the client geometry of first window\n"
410 " --im=SERVER set the X Input Method (XIM) server\n"
411 " --inputstyle=STYLE set X Input Method input style\n"
412 " (possible values: onthespot, overthespot,\n"
413 " offthespot, root)\n");
414 fprintf(handle,
415 " --name=NAME set the application name\n"
416 " --ncols=COUNT limit the number of colors allocated\n"
417 " in the color cube on an 8-bit display,\n"
418 " if the application is using the\n"
419 " QApplication::ManyColor color specification\n"
420 " --title=TITLE set the application title (caption)\n"
421 " --visual=VISUAL force the application\n"
422 " to use the given visual on an 8-bit display\n"
423 " (only possible value: TrueColor)\n"
424 "\n");
425 #endif
427 #endif // BUILD_GUI
429 fprintf(handle,
430 "The program accepts both TTF and TTC files as input.\n"
431 "Use option -i only if you have a legal permission to modify the font.\n"
432 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
433 "With option -s, use default values for standard stem width and height,\n"
434 "otherwise they are derived from script-specific characters\n"
435 "resembling the shape of character `o'.\n"
436 "\n");
437 fprintf(handle,
438 "A hint set contains the optimal hinting for a certain PPEM value;\n"
439 "the larger the hint set range (as given by options -l and -r),\n"
440 "the more hint sets get computed, usually increasing the output font size.\n"
441 "The `gasp' table of the output file always enables grayscale hinting\n"
442 "for all sizes (limited by option -G, which is handled in the bytecode).\n"
443 "Increasing the value of -G does not increase the output font size.\n"
444 "\n");
445 fprintf(handle,
446 "Options -f and -D take a four-letter string that identifies a script.\n"
447 "Option -f sets the script used as a fallback for glyphs that can't be\n"
448 "associated with a known script. By default, such glyphs are hinted;\n"
449 "if option -S is set, they are scaled only instead. Option -D sets the\n"
450 "default script for handling OpenType features.\n"
451 "\n"
452 "Possible four-letter string values are\n"
453 "\n");
454 const Tag_Names* sn = script_names;
455 for(;;)
457 fprintf(handle, " %s (%s)",
458 sn->tag, sn->description);
459 sn++;
460 if (sn->tag)
461 fprintf(handle, ",\n");
462 else
464 fprintf(handle, ".\n");
465 break;
468 fprintf(handle,
469 #ifndef BUILD_GUI
470 "\n"
471 "A control instructions file contains entries of the form\n"
472 "\n"
473 " [<font idx>] <script> <feature> @ <glyph ids>\n"
474 "\n"
475 " [<font idx>] <script> <feature> w <stem widths>\n"
476 "\n"
477 " [<font idx>] <glyph id> l|r <points> [(<left offset>,<right offset>)]\n"
478 "\n"
479 " [<font idx>] <glyph id> n <points>\n"
480 "\n"
481 " [<font idx>] <glyph id> t|p <points> [x <shift>] [y <shift>] @ <ppems>\n"
482 "\n"
483 "<font idx> is the current subfont, <glyph id> is a glyph name or index,\n"
484 "<glyph ids> is a set of <glyph id>s, <stem widths> is an unordered set of\n"
485 "integer stem widths in font units, <shift> is a real number in px,\n"
486 "<points> and <ppems> are integer ranges as with option `-X'.\n"
487 "\n"
488 "<script> and <feature> are four-letter tags that define a style\n"
489 "the <glyph ids> are assigned to; possible values for <script> are the same\n"
490 "as with option -D, possible values for <feature> are\n"
491 "\n");
492 const Tag_Names* fn = feature_names;
493 for(;;)
495 fprintf(handle, " %s (%s)",
496 fn->tag, fn->description);
497 fn++;
498 if (fn->tag)
499 fprintf(handle, ",\n");
500 else
502 fprintf(handle, ".\n");
503 break;
506 fprintf(handle,
507 "\n"
508 "`w' assigns stem widths to a style; the first value sets the default.\n"
509 "`l' (`r') creates one-point segments with direction left (right).\n"
510 "<left offset> and <right offset> specify offsets (in font units)\n"
511 "relative to the corresponding points to give the segments a length.\n"
512 "`n' removes points from horizontal segments, making them `weak' points.\n"
513 "`t' (`p') applies delta exceptions to the given points before (after) IUP.\n"
514 "\n"
515 "`#' starts a line comment, which gets ignored.\n"
516 "Empty lines are ignored, too.\n"
517 "\n"
518 "Key letters `l', `r', `n', `p', `t', `w', `x', and `y'\n"
519 "have the verbose aliases `left', `right', `nodir', `point', `touch',\n"
520 "`width', `xshift', and `yshift', respectively.\n"
521 #endif
522 "\n"
523 #ifdef BUILD_GUI
524 "A command-line version of this program is called `ttfautohint'.\n"
525 #else
526 "A GUI version of this program is called `ttfautohintGUI'.\n"
527 #endif
528 "\n"
529 "Report bugs to: freetype-devel@nongnu.org\n"
530 "\n"
531 "ttfautohint home page: <https://www.freetype.org/ttfautohint>\n");
533 if (is_error)
534 exit(EXIT_FAILURE);
535 else
536 exit(EXIT_SUCCESS);
540 static void
541 show_version()
543 fprintf(stdout,
544 #ifdef BUILD_GUI
545 "ttfautohintGUI " VERSION "\n"
546 #else
547 "ttfautohint " VERSION "\n"
548 #endif
549 "Copyright (C) 2011-2022 Werner Lemberg <wl@gnu.org>.\n"
550 "License: FreeType License (FTL) or GNU GPLv2.\n"
551 "This is free software: you are free to change and redistribute it.\n"
552 "There is NO WARRANTY, to the extent permitted by law.\n");
554 exit(EXIT_SUCCESS);
556 #endif // CONSOLE_OUTPUT
559 #ifndef BUILD_GUI
561 typedef const struct FT_error_
563 int err_code;
564 const char* err_msg;
565 } FT_error;
567 static FT_error FT_errors[] =
569 #undef __FTERRORS_H__
570 #define FT_ERRORDEF(e, v, s) { e, s },
571 #define FT_ERROR_START_LIST {
572 #define FT_ERROR_END_LIST { 0, NULL } };
573 #include FT_ERRORS_H
576 static const char*
577 FT_get_error_message(FT_Error error)
579 FT_error* e = FT_errors;
581 while (e->err_code || e->err_msg)
583 if (e->err_code == error)
584 return e->err_msg;
585 e++;
588 return NULL;
592 #define BUF_SIZE 0x10000
594 #define TTAG_TTFA FT_MAKE_TAG('T', 'T', 'F', 'A')
596 static void
597 display_TTFA(FILE* in)
599 FT_Byte buf[BUF_SIZE];
600 FT_Byte* in_buf;
601 size_t in_len = 0;
602 size_t read_bytes;
604 if (in == stdin)
605 SET_BINARY(stdin);
607 in_buf = (FT_Byte*)malloc(BUF_SIZE);
608 if (!in_buf)
610 fprintf(stderr, "Can't allocate enough memory.\n");
611 exit(EXIT_FAILURE);
614 while ((read_bytes = fread(buf, 1, BUF_SIZE, in)) > 0)
616 FT_Byte* in_buf_new = (FT_Byte*)realloc(in_buf, in_len + read_bytes);
617 if (!in_buf_new)
619 fprintf(stderr, "Can't reallocate enough memory.\n");
620 exit(EXIT_FAILURE);
622 else
623 in_buf = in_buf_new;
625 memcpy(in_buf + in_len, buf, read_bytes);
627 in_len += read_bytes;
630 if (ferror(in))
632 fprintf(stderr, "Stream error while handling input font.\n");
633 exit(EXIT_FAILURE);
636 FT_Library library = NULL;
637 FT_Face face = NULL;
638 FT_Error error;
640 error = FT_Init_FreeType(&library);
641 if (error)
643 fprintf(stderr, "Can't initialize FreeType library:\n"
644 "%s\n",
645 FT_get_error_message(error));
646 exit(EXIT_FAILURE);
649 // in a TTC, a `TTFA' table is part of the first subfont,
650 // thus we can simply pass 0 as the face index
651 error = FT_New_Memory_Face(library, in_buf, (FT_Long)in_len, 0, &face);
652 if (error)
654 fprintf(stderr, "Can't open input font:\n"
655 "%s\n",
656 FT_get_error_message(error));
657 exit(EXIT_FAILURE);
660 FT_Byte* ttfa_buf = NULL;
661 FT_ULong ttfa_len = 0;
663 error = FT_Load_Sfnt_Table(face, TTAG_TTFA, 0, NULL, &ttfa_len);
664 if (error)
666 fprintf(stderr, "No `TTFA' table in font.\n");
667 goto Exit;
670 ttfa_buf = (FT_Byte*)malloc(ttfa_len);
671 if (!ttfa_buf)
673 fprintf(stderr, "Can't allocate enough memory.\n");
674 exit(EXIT_FAILURE);
677 error = FT_Load_Sfnt_Table(face, TTAG_TTFA, 0, ttfa_buf, &ttfa_len);
678 if (error)
680 fprintf(stderr, "Error loading `TTFA' table:\n"
681 "%s\n",
682 FT_get_error_message(error));
683 exit(EXIT_FAILURE);
686 fprintf(stdout, "%s", ttfa_buf);
688 Exit:
689 FT_Done_Face(face);
690 FT_Done_FreeType(library);
692 free(in_buf);
693 free(ttfa_buf);
694 if (in != stdin)
695 fclose(in);
697 exit(EXIT_SUCCESS);
699 #endif
703 main(int argc,
704 char** argv)
706 int hinting_range_min = 0;
707 int hinting_range_max = 0;
708 int hinting_limit = 0;
709 int increase_x_height = 0;
710 int fallback_stem_width = 0;
712 bool have_hinting_range_min = false;
713 bool have_hinting_range_max = false;
714 bool have_hinting_limit = false;
715 bool have_increase_x_height = false;
716 bool have_fallback_stem_width = false;
718 int gray_stem_width_mode = TA_STEM_WIDTH_MODE_QUANTIZED;
719 int gdi_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_STRONG;
720 int dw_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_QUANTIZED;
722 #ifndef BUILD_GUI
723 bool have_option_w = false;
724 const char* option_w_arg;
725 #endif
727 bool ignore_restrictions = false;
728 bool windows_compatibility = false;
729 bool adjust_subglyphs = false;
730 bool hint_composites = false;
731 bool no_info = false;
732 bool detailed_info = false;
733 bool TTFA_info = false;
734 #ifndef BUILD_GUI
735 bool show_TTFA_info = false;
736 #endif
737 bool symbol = false;
738 bool fallback_scaling = false;
740 const char* default_script = NULL;
741 bool have_default_script = false;
742 const char* fallback_script = NULL;
743 bool have_fallback_script = false;
744 const char* x_height_snapping_exceptions_string = NULL;
745 bool have_x_height_snapping_exceptions_string = false;
746 const char* family_suffix = NULL;
747 bool have_family_suffix = false;
749 bool dehint = false;
751 #ifndef BUILD_GUI
752 bool debug = false;
754 TA_Progress_Func progress_func = NULL;
755 TA_Error_Func err_func = err;
756 TA_Info_Func info_func = info;
757 TA_Info_Post_Func info_post_func = info_post;
759 const char* control_name = NULL;
760 const char* reference_name = NULL;
761 int reference_index = 0;
763 unsigned long long epoch = ULLONG_MAX;
764 #endif
766 // For real numbers (both parsing and displaying) we only use `.' as the
767 // decimal separator; similarly, we don't want localized formats like a
768 // thousands separator for any number.
769 setlocale(LC_NUMERIC, "C");
771 // make GNU, Qt, and X11 command line options look the same;
772 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
773 // and short options specific to ttfautohint
775 // set up a new argument string
776 vector<string> new_arg_string;
777 new_arg_string.push_back(argv[0]);
779 while (1)
781 // use pseudo short options for long-only options
782 enum
784 PASS_THROUGH = CHAR_MAX + 1,
785 HELP_ALL_OPTION,
786 DEBUG_OPTION
789 static struct option long_options[] =
791 {"help", no_argument, NULL, 'h'},
792 #ifdef BUILD_GUI
793 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
794 #endif
796 // ttfautohint options
797 {"adjust-subglyphs", no_argument, NULL, 'p'},
798 {"composites", no_argument, NULL, 'c'},
799 #ifndef BUILD_GUI
800 {"control-file", required_argument, NULL, 'm'},
801 {"debug", no_argument, NULL, DEBUG_OPTION},
802 #endif
803 {"default-script", required_argument, NULL, 'D'},
804 {"dehint", no_argument, NULL, 'd'},
805 {"detailed-info", no_argument, NULL, 'I'},
806 {"fallback-scaling", no_argument, NULL, 'S'},
807 {"fallback-script", required_argument, NULL, 'f'},
808 {"fallback-stem-width", required_argument, NULL, 'H'},
809 {"family-suffix", required_argument, NULL, 'F'},
810 {"hinting-limit", required_argument, NULL, 'G'},
811 {"hinting-range-max", required_argument, NULL, 'r'},
812 {"hinting-range-min", required_argument, NULL, 'l'},
813 {"ignore-restrictions", no_argument, NULL, 'i'},
814 {"increase-x-height", required_argument, NULL, 'x'},
815 {"no-info", no_argument, NULL, 'n'},
816 {"pre-hinting", no_argument, NULL, 'p'},
817 #ifndef BUILD_GUI
818 {"reference", required_argument, NULL, 'R'},
819 {"reference-index", required_argument, NULL, 'Z'},
820 #endif
821 {"stem-width-mode", required_argument, NULL, 'a'},
822 {"strong-stem-width", required_argument, NULL, 'w'},
823 {"symbol", no_argument, NULL, 's'},
824 {"ttfa-table", no_argument, NULL, 't'},
825 #ifndef BUILD_GUI
826 {"ttfa-info", no_argument, NULL, 'T'},
827 #endif
828 {"verbose", no_argument, NULL, 'v'},
829 {"version", no_argument, NULL, 'V'},
830 {"windows-compatibility", no_argument, NULL, 'W'},
831 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
833 // Qt options
834 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
835 {"reverse", no_argument, NULL, PASS_THROUGH},
836 {"session", required_argument, NULL, PASS_THROUGH},
837 {"style", required_argument, NULL, PASS_THROUGH},
838 {"stylesheet", required_argument, NULL, PASS_THROUGH},
840 // X11 options
841 {"background", required_argument, NULL, PASS_THROUGH},
842 {"bg", required_argument, NULL, PASS_THROUGH},
843 {"btn", required_argument, NULL, PASS_THROUGH},
844 {"button", required_argument, NULL, PASS_THROUGH},
845 {"cmap", no_argument, NULL, PASS_THROUGH},
846 {"display", required_argument, NULL, PASS_THROUGH},
847 {"fg", required_argument, NULL, PASS_THROUGH},
848 {"fn", required_argument, NULL, PASS_THROUGH},
849 {"font", required_argument, NULL, PASS_THROUGH},
850 {"foreground", required_argument, NULL, PASS_THROUGH},
851 {"geometry", required_argument, NULL, PASS_THROUGH},
852 {"im", required_argument, NULL, PASS_THROUGH},
853 {"inputstyle", required_argument, NULL, PASS_THROUGH},
854 {"name", required_argument, NULL, PASS_THROUGH},
855 {"ncols", required_argument, NULL, PASS_THROUGH},
856 {"title", required_argument, NULL, PASS_THROUGH},
857 {"visual", required_argument, NULL, PASS_THROUGH},
859 {NULL, 0, NULL, 0}
862 int option_index;
863 int c = getopt_long_only(argc, argv,
864 #ifdef BUILD_GUI
865 "a:cdD:f:F:G:hH:iIl:npr:sStvVw:Wx:X:",
866 #else
867 "a:cdD:f:F:G:hH:iIl:m:npr:R:sStTvVw:Wx:X:Z:",
868 #endif
869 long_options, &option_index);
870 if (c == -1)
871 break;
873 switch (c)
875 case 'a':
876 if (strlen(optarg) != 3)
878 fprintf(stderr, "Stem width mode string must consist of exactly"
879 " three letters\n");
880 exit(EXIT_FAILURE);
883 switch (optarg[0])
885 case 'n':
886 gray_stem_width_mode = TA_STEM_WIDTH_MODE_NATURAL;
887 break;
888 case 'q':
889 gray_stem_width_mode = TA_STEM_WIDTH_MODE_QUANTIZED;
890 break;
891 case 's':
892 gray_stem_width_mode = TA_STEM_WIDTH_MODE_STRONG;
893 break;
894 default:
895 fprintf(stderr, "Stem width mode letter for grayscale rendering"
896 " must be `n', `q', or `s'\n");
897 exit(EXIT_FAILURE);
900 switch (optarg[1])
902 case 'n':
903 gdi_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_NATURAL;
904 break;
905 case 'q':
906 gdi_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_QUANTIZED;
907 break;
908 case 's':
909 gdi_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_STRONG;
910 break;
911 default:
912 fprintf(stderr, "Stem width mode letter for GDI ClearType rendering"
913 " must be `n', `q', or `s'\n");
914 exit(EXIT_FAILURE);
917 switch (optarg[2])
919 case 'n':
920 dw_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_NATURAL;
921 break;
922 case 'q':
923 dw_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_QUANTIZED;
924 break;
925 case 's':
926 dw_cleartype_stem_width_mode = TA_STEM_WIDTH_MODE_STRONG;
927 break;
928 default:
929 fprintf(stderr, "Stem width mode letter for DW ClearType rendering"
930 " must be `n', `q', or `s'\n");
931 exit(EXIT_FAILURE);
934 break;
936 case 'c':
937 hint_composites = true;
938 break;
940 case 'd':
941 dehint = true;
942 break;
944 case 'D':
945 default_script = optarg;
946 have_default_script = true;
947 break;
949 case 'f':
950 fallback_script = optarg;
951 have_fallback_script = true;
952 break;
954 case 'F':
955 family_suffix = optarg;
956 have_family_suffix = true;
957 break;
959 case 'G':
960 hinting_limit = atoi(optarg);
961 have_hinting_limit = true;
962 break;
964 case 'h':
965 #ifdef CONSOLE_OUTPUT
966 show_help(false, false);
967 #endif
968 break;
970 case 'H':
971 fallback_stem_width = atoi(optarg);
972 have_fallback_stem_width = true;
973 break;
975 case 'i':
976 ignore_restrictions = true;
977 break;
979 case 'I':
980 detailed_info = true;
981 no_info = false;
982 break;
984 case 'l':
985 hinting_range_min = atoi(optarg);
986 have_hinting_range_min = true;
987 break;
989 #ifndef BUILD_GUI
990 case 'm':
991 control_name = optarg;
992 break;
993 #endif
995 case 'n':
996 no_info = true;
997 detailed_info = false;
998 break;
1000 case 'p':
1001 adjust_subglyphs = true;
1002 break;
1004 case 'r':
1005 hinting_range_max = atoi(optarg);
1006 have_hinting_range_max = true;
1007 break;
1009 #ifndef BUILD_GUI
1010 case 'R':
1011 reference_name = optarg;
1012 break;
1013 #endif
1015 case 's':
1016 symbol = true;
1017 break;
1019 case 'S':
1020 fallback_scaling = true;
1021 break;
1023 case 't':
1024 TTFA_info = true;
1025 break;
1027 #ifndef BUILD_GUI
1028 case 'T':
1029 show_TTFA_info = true;
1030 break;
1031 #endif
1033 case 'v':
1034 #ifndef BUILD_GUI
1035 progress_func = progress;
1036 #endif
1037 break;
1039 case 'V':
1040 #ifdef CONSOLE_OUTPUT
1041 show_version();
1042 #endif
1043 break;
1045 case 'w':
1046 gray_stem_width_mode = strchr(optarg, 'g')
1047 ? TA_STEM_WIDTH_MODE_STRONG
1048 : TA_STEM_WIDTH_MODE_QUANTIZED;
1049 gdi_cleartype_stem_width_mode = strchr(optarg, 'G')
1050 ? TA_STEM_WIDTH_MODE_STRONG
1051 : TA_STEM_WIDTH_MODE_QUANTIZED;
1052 dw_cleartype_stem_width_mode = strchr(optarg, 'D')
1053 ? TA_STEM_WIDTH_MODE_STRONG
1054 : TA_STEM_WIDTH_MODE_QUANTIZED;
1055 #ifndef BUILD_GUI
1056 have_option_w = true;
1057 option_w_arg = optarg;
1058 #endif
1059 break;
1061 case 'W':
1062 windows_compatibility = true;
1063 break;
1065 case 'x':
1066 increase_x_height = atoi(optarg);
1067 have_increase_x_height = true;
1068 break;
1070 case 'X':
1071 x_height_snapping_exceptions_string = optarg;
1072 have_x_height_snapping_exceptions_string = true;
1073 break;
1075 #ifndef BUILD_GUI
1076 case 'Z':
1077 reference_index = atoi(optarg);
1078 break;
1079 #endif
1081 #ifndef BUILD_GUI
1082 case DEBUG_OPTION:
1083 debug = true;
1084 break;
1085 #endif
1087 #ifdef BUILD_GUI
1088 case HELP_ALL_OPTION:
1089 #ifdef CONSOLE_OUTPUT
1090 show_help(true, false);
1091 #endif
1092 break;
1093 #endif
1095 case PASS_THROUGH:
1097 // append argument with proper syntax for Qt
1098 string arg;
1099 arg += '-';
1100 arg += long_options[option_index].name;
1102 new_arg_string.push_back(arg);
1103 if (optarg)
1104 new_arg_string.push_back(optarg);
1105 break;
1108 default:
1109 exit(EXIT_FAILURE);
1113 if (dehint)
1115 // -d makes ttfautohint ignore all other hinting options
1116 have_default_script = false;
1117 have_fallback_script = false;
1118 have_fallback_stem_width = false;
1119 have_hinting_limit = false;
1120 have_hinting_range_max = false;
1121 have_hinting_range_min = false;
1122 have_increase_x_height = false;
1123 have_x_height_snapping_exceptions_string = false;
1126 #ifndef BUILD_GUI
1127 if (show_TTFA_info)
1129 // -T makes ttfautohint ignore even more options
1130 have_default_script = false;
1131 have_fallback_script = false;
1132 have_fallback_stem_width = false;
1133 have_family_suffix = false;
1134 have_hinting_limit = false;
1135 have_hinting_range_max = false;
1136 have_hinting_range_min = false;
1137 have_increase_x_height = false;
1138 have_x_height_snapping_exceptions_string = false;
1139 debug = false;
1141 #endif
1143 if (!have_default_script)
1144 default_script = "latn";
1145 if (!have_fallback_script)
1146 fallback_script = "none";
1147 if (!have_hinting_range_min)
1148 hinting_range_min = TA_HINTING_RANGE_MIN;
1149 if (!have_hinting_range_max)
1150 hinting_range_max = TA_HINTING_RANGE_MAX;
1151 if (!have_hinting_limit)
1152 hinting_limit = TA_HINTING_LIMIT;
1153 if (!have_increase_x_height)
1154 increase_x_height = TA_INCREASE_X_HEIGHT;
1155 if (!have_x_height_snapping_exceptions_string)
1156 x_height_snapping_exceptions_string = "";
1157 if (!have_fallback_stem_width)
1158 fallback_stem_width = 0; // redundant, but avoids a compiler warning
1159 if (!have_family_suffix)
1160 family_suffix = "";
1162 #ifndef BUILD_GUI
1164 // check SOURE_DATE_EPOCH environment variable
1165 const char* source_date_epoch = getenv("SOURCE_DATE_EPOCH");
1166 if (source_date_epoch)
1168 char* endptr;
1169 errno = 0;
1171 epoch = strtoull(source_date_epoch, &endptr, 10);
1172 if ((errno == ERANGE && (epoch == ULLONG_MAX
1173 || epoch == 0))
1174 || (errno != 0
1175 && epoch == 0))
1177 fprintf(stderr,
1178 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1179 " strtoull: %s\n",
1180 strerror(errno));
1181 epoch = ULLONG_MAX;
1183 else if (endptr == source_date_epoch)
1185 fprintf(stderr,
1186 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1187 " No digits were found: %s\n",
1188 endptr);
1189 epoch = ULLONG_MAX;
1191 else if (*endptr != '\0')
1193 fprintf(stderr,
1194 "Environment variable `SOURCE_DATE_EPOCH' ignored:\n"
1195 " Trailing garbage: %s\n",
1196 endptr);
1197 epoch = ULLONG_MAX;
1199 else if (epoch > ULONG_MAX)
1201 fprintf(stderr,
1202 "Environment variable `SOURCE_DATE_EPOCH' ignored\n"
1203 " value must be smaller than or equal to %lu\n"
1204 " but was found to be %llu\n",
1205 ULONG_MAX, epoch);
1206 epoch = ULLONG_MAX;
1210 if (have_option_w)
1212 char option_a_arg[4];
1214 option_a_arg[0] =
1215 gray_stem_width_mode == TA_STEM_WIDTH_MODE_STRONG ? 's' : 'q';
1216 option_a_arg[1] =
1217 gdi_cleartype_stem_width_mode == TA_STEM_WIDTH_MODE_STRONG ? 's' : 'q';
1218 option_a_arg[2] =
1219 dw_cleartype_stem_width_mode == TA_STEM_WIDTH_MODE_STRONG ? 's' : 'q';
1220 option_a_arg[3] = '\0';
1222 fprintf(stderr,
1223 "Warning: Option `-w %s' is deprecated!"
1224 " Use option `-a %s' instead\n",
1225 option_w_arg,
1226 option_a_arg);
1229 if (!isatty(fileno(stderr)) && !debug)
1230 setvbuf(stderr, (char*)NULL, _IONBF, BUFSIZ);
1232 if (hinting_range_min < 2)
1234 fprintf(stderr, "The hinting range minimum must be at least 2\n");
1235 exit(EXIT_FAILURE);
1237 if (hinting_range_max < hinting_range_min)
1239 fprintf(stderr, "The hinting range maximum must not be smaller"
1240 " than the minimum (%d)\n",
1241 hinting_range_min);
1242 exit(EXIT_FAILURE);
1244 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
1246 fprintf(stderr, "A non-zero hinting limit must not be smaller"
1247 " than the hinting range maximum (%d)\n",
1248 hinting_range_max);
1249 exit(EXIT_FAILURE);
1251 if (increase_x_height != 0 && increase_x_height < 6)
1253 fprintf(stderr, "A non-zero x height increase limit"
1254 " must be larger than or equal to 6\n");
1255 exit(EXIT_FAILURE);
1257 if (have_fallback_stem_width && fallback_stem_width <= 0)
1259 fprintf(stderr, "The fallback stem width"
1260 " must be a positive integer\n");
1261 exit(EXIT_FAILURE);
1264 if (have_default_script)
1266 const Tag_Names* sn;
1268 for (sn = script_names; sn->tag; sn++)
1269 if (!strcmp(default_script, sn->tag))
1270 break;
1271 if (!sn->tag)
1273 fprintf(stderr, "Unknown script tag `%s'\n", default_script);
1274 exit(EXIT_FAILURE);
1278 if (have_fallback_script)
1280 const Tag_Names* sn;
1282 for (sn = script_names; sn->tag; sn++)
1283 if (!strcmp(fallback_script, sn->tag))
1284 break;
1285 if (!sn->tag)
1287 fprintf(stderr, "Unknown script tag `%s'\n", fallback_script);
1288 exit(EXIT_FAILURE);
1292 if (symbol
1293 && have_fallback_stem_width
1294 && fallback_scaling)
1295 fprintf(stderr,
1296 "Warning: Setting a fallback stem width for a symbol font\n"
1297 " with fallback scaling only has no effect\n");
1299 if (const char* pos = check_family_suffix(family_suffix))
1301 fprintf(stderr,
1302 "Invalid character in family suffix:\n"
1303 " %s\n"
1304 " %*s\n",
1305 family_suffix,
1306 int(pos - family_suffix + 1), "^");
1307 exit(EXIT_FAILURE);
1310 int num_args = argc - optind;
1312 if (num_args > 2)
1313 show_help(false, true);
1315 FILE* in;
1316 if (num_args > 0)
1318 in = fopen(argv[optind], "rb");
1319 if (!in)
1321 fprintf(stderr,
1322 "The following error occurred while opening font `%s':\n"
1323 "\n"
1324 " %s\n",
1325 argv[optind], strerror(errno));
1326 exit(EXIT_FAILURE);
1329 else
1331 if (isatty(fileno(stdin)))
1332 show_help(false, true);
1333 in = stdin;
1336 if (show_TTFA_info)
1337 display_TTFA(in); // this function doesn't return
1339 FILE* out;
1340 if (num_args > 1)
1342 if (!strcmp(argv[optind], argv[optind + 1]))
1344 fprintf(stderr, "Input and output file names must not be identical\n");
1345 exit(EXIT_FAILURE);
1348 out = fopen(argv[optind + 1], "wb");
1349 if (!out)
1351 fprintf(stderr,
1352 "The following error occurred while opening font `%s':\n"
1353 "\n"
1354 " %s\n",
1355 argv[optind + 1], strerror(errno));
1356 exit(EXIT_FAILURE);
1359 else
1361 if (isatty(fileno(stdout)))
1362 show_help(false, true);
1363 out = stdout;
1366 FILE* control = NULL;
1367 if (control_name)
1369 control = fopen(control_name, "r");
1370 if (!control)
1372 fprintf(stderr,
1373 "The following error occurred"
1374 " while opening control file `%s':\n"
1375 "\n"
1376 " %s\n",
1377 control_name, strerror(errno));
1378 exit(EXIT_FAILURE);
1381 else
1382 control = NULL;
1384 FILE* reference = NULL;
1385 if (reference_name)
1387 reference = fopen(reference_name, "rb");
1388 if (!reference)
1390 fprintf(stderr,
1391 "The following error occurred"
1392 " while opening reference font `%s':\n"
1393 "\n"
1394 " %s\n",
1395 reference_name, strerror(errno));
1396 exit(EXIT_FAILURE);
1399 if (reference_index != 0)
1401 FT_Library library = NULL;
1402 FT_Face face = NULL;
1403 FT_Error error;
1405 error = FT_Init_FreeType(&library);
1406 if (error)
1408 fprintf(stderr, "Can't initialize FreeType library:\n"
1409 "%s\n",
1410 FT_get_error_message(error));
1411 exit(EXIT_FAILURE);
1414 error = FT_New_Face(library, reference_name, -1, &face);
1415 if (error)
1417 fprintf(stderr, "Can't check number of faces in reference font:\n"
1418 "%s\n",
1419 FT_get_error_message(error));
1420 exit(EXIT_FAILURE);
1423 if (reference_index < 0
1424 || reference_index >= face->num_faces)
1426 fprintf(stderr, "Face index for reference font must be"
1427 " in the range [0;%ld]\n",
1428 face->num_faces - 1);
1429 exit(EXIT_FAILURE);
1432 FT_Done_Face(face);
1433 FT_Done_FreeType(library);
1436 else
1437 reference = NULL;
1439 Progress_Data progress_data = {-1, 1, 0};
1440 Error_Data error_data = {control_name};
1441 Info_Data info_data;
1443 if (!*family_suffix)
1444 info_post_func = NULL;
1446 info_data.no_info = no_info;
1447 info_data.detailed_info = detailed_info;
1448 info_data.info_string = NULL; // must be deallocated after use
1449 info_data.info_string_wide = NULL; // must be deallocated after use
1450 info_data.info_string_len = 0;
1451 info_data.info_string_wide_len = 0;
1453 info_data.control_name = control_name;
1454 info_data.reference_name = reference_name;
1455 info_data.reference_index = reference_index;
1457 info_data.hinting_range_min = hinting_range_min;
1458 info_data.hinting_range_max = hinting_range_max;
1459 info_data.hinting_limit = hinting_limit;
1461 info_data.gray_stem_width_mode = gray_stem_width_mode;
1462 info_data.gdi_cleartype_stem_width_mode = gdi_cleartype_stem_width_mode;
1463 info_data.dw_cleartype_stem_width_mode = dw_cleartype_stem_width_mode;
1465 info_data.windows_compatibility = windows_compatibility;
1466 info_data.adjust_subglyphs = adjust_subglyphs;
1467 info_data.hint_composites = hint_composites;
1468 info_data.increase_x_height = increase_x_height;
1469 info_data.x_height_snapping_exceptions_string = x_height_snapping_exceptions_string;
1470 info_data.family_suffix = family_suffix;
1471 info_data.family_data_head = NULL;
1472 info_data.fallback_stem_width = fallback_stem_width;
1473 info_data.symbol = symbol;
1474 info_data.fallback_scaling = fallback_scaling;
1475 info_data.TTFA_info = TTFA_info;
1477 strncpy(info_data.default_script,
1478 default_script,
1479 sizeof (info_data.default_script));
1480 strncpy(info_data.fallback_script,
1481 fallback_script,
1482 sizeof (info_data.fallback_script));
1484 info_data.dehint = dehint;
1486 if (!no_info)
1488 int ret = build_version_string(&info_data);
1489 if (ret == 1)
1490 fprintf(stderr, "Warning: Can't allocate memory"
1491 " for ttfautohint options string in `name' table\n");
1492 else if (ret == 2)
1493 fprintf(stderr, "Warning: ttfautohint options string"
1494 " in `name' table too long\n");
1497 if (in == stdin)
1498 SET_BINARY(stdin);
1499 if (out == stdout)
1500 SET_BINARY(stdout);
1502 TA_Error error =
1503 TTF_autohint("in-file, out-file, control-file,"
1504 "reference-file, reference-index, reference-name,"
1505 "hinting-range-min, hinting-range-max, hinting-limit,"
1506 "gray-stem-width-mode, gdi-cleartype-stem-width-mode,"
1507 "dw-cleartype-stem-width-mode,"
1508 "progress-callback, progress-callback-data,"
1509 "error-callback, error-callback-data,"
1510 "info-callback, info-post-callback, info-callback-data,"
1511 "ignore-restrictions, windows-compatibility,"
1512 "adjust-subglyphs, hint-composites,"
1513 "increase-x-height, x-height-snapping-exceptions,"
1514 "fallback-stem-width, default-script,"
1515 "fallback-script, fallback-scaling,"
1516 "symbol, dehint, debug, TTFA-info, epoch",
1517 in, out, control,
1518 reference, reference_index, reference_name,
1519 hinting_range_min, hinting_range_max, hinting_limit,
1520 gray_stem_width_mode, gdi_cleartype_stem_width_mode,
1521 dw_cleartype_stem_width_mode,
1522 progress_func, &progress_data,
1523 err_func, &error_data,
1524 info_func, info_post_func, &info_data,
1525 ignore_restrictions, windows_compatibility,
1526 adjust_subglyphs, hint_composites,
1527 increase_x_height, x_height_snapping_exceptions_string,
1528 fallback_stem_width, default_script,
1529 fallback_script, fallback_scaling,
1530 symbol, dehint, debug, TTFA_info, epoch);
1532 if (!no_info)
1534 free(info_data.info_string);
1535 free(info_data.info_string_wide);
1538 if (in != stdin)
1539 fclose(in);
1540 if (out != stdout)
1541 fclose(out);
1542 if (control)
1543 fclose(control);
1544 if (reference)
1545 fclose(reference);
1547 exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
1549 return 0; // never reached
1551 #else // BUILD_GUI
1553 int new_argc = (int)new_arg_string.size();
1554 char** new_argv = new char*[new_argc];
1556 // construct new argc and argv variables from collected data
1557 for (unsigned int i = 0; i < (unsigned int)new_argc; i++)
1558 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
1560 QApplication app(new_argc, new_argv);
1561 app.setApplicationName("TTFautohint");
1562 app.setApplicationVersion(VERSION);
1563 app.setOrganizationName("FreeType");
1564 app.setOrganizationDomain("freetype.org");
1566 bool alternative_layout = false;
1568 // Display the window off the screen -- to get proper window dimensions
1569 // including the frame, the window manager must have a chance to
1570 // decorate it.
1572 // We don't want to change the default window positioning algorithm of
1573 // the platform's window manager, so we create the main GUI window
1574 // twice.
1576 // The original idea, however, was to simply move the off-screen window
1577 // back to the screen with
1579 // gui.move(100, 100);
1580 // gui.setAttribute(Qt::WA_Moved, false);
1581 // gui.show();
1583 // (unsetting the `WA_Moved' attribute makes the window manager handle
1584 // the previous call to `move' as a position suggestion instead of a
1585 // request). Unfortuntely, there seems to be a bug in Qt 4.8.4 which
1586 // prevents any effect of unsetting `WA_Moved' if `show' has already
1587 // been called.
1589 Main_GUI dummy(alternative_layout,
1590 hinting_range_min, hinting_range_max, hinting_limit,
1591 gray_stem_width_mode, gdi_cleartype_stem_width_mode,
1592 dw_cleartype_stem_width_mode, increase_x_height,
1593 x_height_snapping_exceptions_string, fallback_stem_width,
1594 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1595 hint_composites, no_info, detailed_info,
1596 default_script, fallback_script, fallback_scaling,
1597 family_suffix, symbol, dehint, TTFA_info);
1599 dummy.move(-50000, -50000);
1600 dummy.show();
1602 // if the vertical size of our window is too large,
1603 // select a horizontal layout
1604 QRect screen(QApplication::desktop()->availableGeometry());
1605 if (dummy.frameGeometry().height() > screen.height())
1606 alternative_layout = true;
1609 Main_GUI gui(alternative_layout,
1610 hinting_range_min, hinting_range_max, hinting_limit,
1611 gray_stem_width_mode, gdi_cleartype_stem_width_mode,
1612 dw_cleartype_stem_width_mode, increase_x_height,
1613 x_height_snapping_exceptions_string, fallback_stem_width,
1614 ignore_restrictions, windows_compatibility, adjust_subglyphs,
1615 hint_composites, no_info, detailed_info,
1616 default_script, fallback_script, fallback_scaling,
1617 family_suffix, symbol, dehint, TTFA_info);
1618 gui.show();
1620 return app.exec();
1622 #endif // BUILD_GUI
1625 // end of main.cpp