From 58bfe40794352afc162c651ff84cbacf5e751960 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 11 Aug 2021 19:48:28 -0600 Subject: [PATCH] [util] Move hb-subset away from main-font-text --- test/subset/run-tests.py | 1 - util/face-options.hh | 6 ++ util/hb-shape.cc | 8 +- util/hb-subset.cc | 160 +++++++++++++++++++++++---------------- util/helper-cairo.hh | 4 +- util/output-options.hh | 15 ++-- util/shape-options.hh | 9 ++- util/text-options.hh | 18 ++--- 8 files changed, 129 insertions(+), 92 deletions(-) diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py index 503c89514..79830c452 100755 --- a/test/subset/run-tests.py +++ b/test/subset/run-tests.py @@ -56,7 +56,6 @@ def run_test (test, should_check_ots): "--drop-tables+=DSIG", "--drop-tables-=sbix"] cli_args.extend (test.get_profile_flags ()) - print (' '.join (cli_args)) ret = subset_cmd (cli_args) if ret != "success": diff --git a/util/face-options.hh b/util/face-options.hh index 3ac366404..386b9339c 100644 --- a/util/face-options.hh +++ b/util/face-options.hh @@ -69,8 +69,11 @@ void face_options_t::post_parse (GError **error) { if (!font_file) + { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "No font file set"); + return; + } assert (font_file); @@ -95,8 +98,11 @@ face_options_t::post_parse (GError **error) cache.font_path = g_strdup (font_path); if (!cache.blob) + { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "%s: Failed reading file", font_path); + return; + } hb_face_destroy (cache.face); cache.face = nullptr; diff --git a/util/hb-shape.cc b/util/hb-shape.cc index 35cad0324..0e5633d3b 100644 --- a/util/hb-shape.cc +++ b/util/hb-shape.cc @@ -95,13 +95,13 @@ struct output_buffer_t : output_options_t { g_string_set_size (gs, 0); format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs); - fprintf (fp, "%s", gs->str); + fprintf (out_fp, "%s", gs->str); } void error (const char *message) { g_string_set_size (gs, 0); format.serialize_message (line_no, "error", message, gs); - fprintf (fp, "%s", gs->str); + fprintf (out_fp, "%s", gs->str); } void consume_glyphs (hb_buffer_t *buffer, const char *text, @@ -111,7 +111,7 @@ struct output_buffer_t : output_options_t g_string_set_size (gs, 0); format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font, serialize_format, serialize_flags, gs); - fprintf (fp, "%s", gs->str); + fprintf (out_fp, "%s", gs->str); } void finish (hb_buffer_t *buffer, const font_options_t *font_opts) { @@ -143,7 +143,7 @@ struct output_buffer_t : output_options_t g_string_append_printf (gs, "trace: %s buffer: ", message); format.serialize (buffer, font, serialize_format, serialize_flags, gs); g_string_append_c (gs, '\n'); - fprintf (fp, "%s", gs->str); + fprintf (out_fp, "%s", gs->str); } diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 1bbeb7f6f..903321a21 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -38,73 +38,37 @@ * Command line interface to the harfbuzz font subsetter. */ - -struct subset_consumer_t : subset_options_t, output_options_t +struct subset_main_t : option_parser_t, face_options_t, text_options_t, subset_options_t, output_options_t { - void add_options (option_parser_t *parser) + int operator () (int argc, char **argv) { - subset_options_t::add_options (parser); - output_options_t::add_options (parser); - } + add_options (); + parse (&argc, &argv); - void init (const face_options_t *face_opts) - { - face = hb_face_reference (face_opts->face); - } - - bool consume_line (text_options_t &text_opts) - { + hb_set_t *codepoints = hb_subset_input_unicode_set (input); unsigned int text_len; const char *text; - if (!(text = text_opts.get_line (&text_len))) - return false; - - // TODO does this only get called with at least 1 codepoint? - hb_set_t *codepoints = hb_subset_input_unicode_set (input); - if (0 == strcmp (text, "*")) + while ((text = get_line (&text_len))) { - hb_face_collect_unicodes (face, codepoints); - return true; + if (0 == strcmp (text, "*")) + { + hb_face_collect_unicodes (face, codepoints); + continue; + } + + if (*text) + { + gchar *c = (gchar *)text; + do + { + gunichar cp = g_utf8_get_char(c); + hb_codepoint_t hb_cp = cp; + hb_set_add (codepoints, hb_cp); + } + while ((c = g_utf8_find_next_char(c, text + text_len))); + } } - gchar *c = (gchar *)text; - do { - gunichar cp = g_utf8_get_char(c); - hb_codepoint_t hb_cp = cp; - hb_set_add (codepoints, hb_cp); - } while ((c = g_utf8_find_next_char(c, text + text_len))); - - return true; - } - - hb_bool_t - write_file (const char *output_file, hb_blob_t *blob) { - unsigned int size; - const char* data = hb_blob_get_data (blob, &size); - - if (!output_file) - fail (true, "No output file was specified"); - - FILE *fp = fopen(output_file, "wb"); - if (!fp) - fail (false, "Cannot open output file `%s': %s", - g_filename_display_name (output_file), strerror (errno)); - - while (size) { - size_t ret = fwrite (data, 1, size, fp); - size -= ret; - data += ret; - if (size && ferror (fp)) - fail (false, "Failed to write output: %s", strerror (errno)); - } - - fclose (fp); - - return true; - } - - void finish (const face_options_t *face_opts) - { hb_face_t *new_face = nullptr; for (unsigned i = 0; i < num_iterations; i++) { @@ -112,8 +76,8 @@ struct subset_consumer_t : subset_options_t, output_options_t new_face = hb_subset_or_fail (face, input); } - failed = !new_face; - if (!failed) + bool success = new_face; + if (success) { hb_blob_t *result = hb_face_reference_blob (new_face); write_file (output_file, result); @@ -121,18 +85,80 @@ struct subset_consumer_t : subset_options_t, output_options_t } hb_face_destroy (new_face); - hb_face_destroy (face); + + return success ? 0 : 1; } - public: - bool failed = false; + bool + write_file (const char *output_file, hb_blob_t *blob) + { + if (!output_file) + fail (true, "No output file was specified"); - hb_face_t *face = nullptr; + unsigned int size; + const char* data = hb_blob_get_data (blob, &size); + + while (size) + { + size_t ret = fwrite (data, 1, size, out_fp); + size -= ret; + data += ret; + if (size && ferror (out_fp)) + fail (false, "Failed to write output: %s", strerror (errno)); + } + + return true; + } + + protected: + + void add_options () + { + face_options_t::add_options (this); + text_options_t::add_options (this); + subset_options_t::add_options (this); + output_options_t::add_options (this); + + GOptionEntry entries[] = + { + {G_OPTION_REMAINING, 0, G_OPTION_FLAG_IN_MAIN, + G_OPTION_ARG_CALLBACK, (gpointer) &collect_rest, nullptr, "[FONT-FILE] [TEXT]"}, + {nullptr} + }; + add_main_group (entries, this); + option_parser_t::add_options (); + } + + private: + + static gboolean + collect_rest (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) + { + subset_main_t *thiz = (subset_main_t *) data; + + if (!thiz->font_file) + { + thiz->font_file = g_strdup (arg); + return true; + } + + if (!thiz->text && !thiz->text_file) + { + thiz->text = g_strdup (arg); + return true; + } + + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Too many arguments on the command line"); + return false; + } }; int main (int argc, char **argv) { - using main_t = main_font_text_t; - return batch_main (argc, argv); + return batch_main (argc, argv); } diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh index 605f17e28..3c4857c79 100644 --- a/util/helper-cairo.hh +++ b/util/helper-cairo.hh @@ -447,7 +447,7 @@ helper_cairo_create_context (double w, double h, const char *extension = out_opts->output_format; if (!extension) { #if HAVE_ISATTY - if (isatty (fileno (out_opts->fp))) + if (isatty (fileno (out_opts->out_fp))) { #ifdef CAIRO_HAS_PNG_FUNCTIONS const char *name; @@ -526,7 +526,7 @@ helper_cairo_create_context (double w, double h, content = CAIRO_CONTENT_COLOR_ALPHA; cairo_surface_t *surface; - FILE *f = out_opts->fp; + FILE *f = out_opts->out_fp; if (constructor) surface = constructor (stdio_write_func, f, w, h); else if (constructor2) diff --git a/util/output-options.hh b/util/output-options.hh index c86096098..9d7b3c723 100644 --- a/util/output-options.hh +++ b/util/output-options.hh @@ -35,8 +35,8 @@ struct output_options_t { g_free (output_file); g_free (output_format); - if (fp && fp != stdout) - fclose (fp); + if (out_fp && out_fp != stdout) + fclose (out_fp); } void add_options (option_parser_t *parser, @@ -48,7 +48,7 @@ struct output_options_t char *output_format = nullptr; bool explicit_output_format = false; - FILE *fp = nullptr; + FILE *out_fp = nullptr; }; void @@ -71,18 +71,21 @@ output_options_t::post_parse (GError **error) output_file = nullptr; /* STDOUT */ if (output_file) - fp = fopen (output_file, "wb"); + out_fp = fopen (output_file, "wb"); else { #if defined(_WIN32) || defined(__CYGWIN__) setmode (fileno (stdout), O_BINARY); #endif - fp = stdout; + out_fp = stdout; } - if (!fp) + if (!out_fp) + { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Cannot open output file `%s': %s", g_filename_display_name (output_file), strerror (errno)); + return; + } } void diff --git a/util/shape-options.hh b/util/shape-options.hh index f19578bbf..c3dedb521 100644 --- a/util/shape-options.hh +++ b/util/shape-options.hh @@ -322,15 +322,18 @@ parse_shapers (const char *name G_GNUC_UNUSED, shape_options_t *shape_opts = (shape_options_t *) data; char **shapers = g_strsplit (arg, ",", 0); - for (char **shaper = shapers; *shaper; shaper++) { + for (char **shaper = shapers; *shaper; shaper++) + { bool found = false; for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) { - if (strcmp (*shaper, *hb_shaper) == 0) { + if (strcmp (*shaper, *hb_shaper) == 0) + { found = true; break; } } - if (!found) { + if (!found) + { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Unknown or unsupported shaper: %s", *shaper); g_strfreev (shapers); diff --git a/util/text-options.hh b/util/text-options.hh index 9ed47fd7e..121045421 100644 --- a/util/text-options.hh +++ b/util/text-options.hh @@ -40,8 +40,8 @@ struct text_options_t g_free (text_file); if (gs) g_string_free (gs, true); - if (fp && fp != stdin) - fclose (fp); + if (in_fp && in_fp != stdin) + fclose (in_fp); } void add_options (option_parser_t *parser); @@ -62,11 +62,11 @@ struct text_options_t if (text_file) { if (0 != strcmp (text_file, "-")) - fp = fopen (text_file, "r"); + in_fp = fopen (text_file, "r"); else - fp = stdin; + in_fp = stdin; - if (!fp) + if (!in_fp) g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Failed opening text file `%s': %s", text_file, strerror (errno)); @@ -80,7 +80,7 @@ struct text_options_t char *text_file = nullptr; private: - FILE *fp = nullptr; + FILE *in_fp = nullptr; GString *gs = nullptr; }; @@ -197,7 +197,7 @@ text_options_t::get_line (unsigned int *len) g_string_set_size (gs, 0); char buf[BUFSIZ]; - while (fgets (buf, sizeof (buf), fp)) + while (fgets (buf, sizeof (buf), in_fp)) { unsigned bytes = strlen (buf); if (bytes && buf[bytes - 1] == '\n') @@ -208,10 +208,10 @@ text_options_t::get_line (unsigned int *len) } g_string_append_len (gs, buf, bytes); } - if (ferror (fp)) + if (ferror (in_fp)) fail (false, "Failed reading text: %s", strerror (errno)); *len = gs->len; - return !*len && feof (fp) ? nullptr : gs->str; + return !*len && feof (in_fp) ? nullptr : gs->str; } void