diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.am | 5 | ||||
-rw-r--r-- | util/Makefile.in | 91 | ||||
-rw-r--r-- | util/Makefile.sources | 9 | ||||
-rw-r--r-- | util/ansi-print.cc | 2 | ||||
-rw-r--r-- | util/ansi-print.hh | 1 | ||||
-rw-r--r-- | util/hb-ot-shape-closure.cc | 18 | ||||
-rw-r--r-- | util/hb-shape.cc | 54 | ||||
-rw-r--r-- | util/hb-subset.cc | 127 | ||||
-rw-r--r-- | util/helper-cairo-ansi.hh | 5 | ||||
-rw-r--r-- | util/helper-cairo.cc | 14 | ||||
-rw-r--r-- | util/helper-cairo.hh | 7 | ||||
-rw-r--r-- | util/main-font-text.hh | 36 | ||||
-rw-r--r-- | util/options.cc | 274 | ||||
-rw-r--r-- | util/options.hh | 313 | ||||
-rw-r--r-- | util/shape-consumer.hh | 38 | ||||
-rw-r--r-- | util/view-cairo.hh | 18 |
16 files changed, 779 insertions, 233 deletions
diff --git a/util/Makefile.am b/util/Makefile.am index 2543a60..d4ab9cd 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,5 +1,6 @@ # Process this file with automake to produce Makefile.in +NULL = EXTRA_DIST = CLEANFILES = DISTCLEANFILES = @@ -45,6 +46,10 @@ endif # HAVE_FREETYPE hb_shape_SOURCES = $(HB_SHAPE_sources) bin_PROGRAMS += hb-shape +hb_subset_SOURCES = $(HB_SUBSET_CLI_sources) +hb_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +bin_PROGRAMS += hb-subset + if HAVE_OT hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources) bin_PROGRAMS += hb-ot-shape-closure diff --git a/util/Makefile.in b/util/Makefile.in index f6fe331..21092cf 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2017 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -17,7 +17,17 @@ # Process this file with automake to produce Makefile.in VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -80,27 +90,27 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -DIST_COMMON = $(srcdir)/Makefile.sources $(srcdir)/Makefile.in \ - $(srcdir)/Makefile.am $(top_srcdir)/depcomp bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_1 = hb-view -@HAVE_GLIB_TRUE@am__append_2 = hb-shape +@HAVE_GLIB_TRUE@am__append_2 = hb-shape hb-subset @HAVE_GLIB_TRUE@@HAVE_OT_TRUE@am__append_3 = hb-ot-shape-closure subdir = util ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \ - $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/gtk-doc.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__EXEEXT_1 = hb-view$(EXEEXT) -@HAVE_GLIB_TRUE@am__EXEEXT_2 = hb-shape$(EXEEXT) +@HAVE_GLIB_TRUE@am__EXEEXT_2 = hb-shape$(EXEEXT) hb-subset$(EXEEXT) @HAVE_GLIB_TRUE@@HAVE_OT_TRUE@am__EXEEXT_3 = \ @HAVE_GLIB_TRUE@@HAVE_OT_TRUE@ hb-ot-shape-closure$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" @@ -131,20 +141,27 @@ hb_shape_LDADD = $(LDADD) hb_shape_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) +am__hb_subset_SOURCES_DIST = hb-subset.cc options.cc options.hh \ + main-font-text.hh +am__objects_4 = hb-subset.$(OBJEXT) options.$(OBJEXT) $(am__objects_1) +@HAVE_GLIB_TRUE@am_hb_subset_OBJECTS = $(am__objects_4) +hb_subset_OBJECTS = $(am_hb_subset_OBJECTS) +am__DEPENDENCIES_2 = $(top_builddir)/src/libharfbuzz.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +@HAVE_GLIB_TRUE@hb_subset_DEPENDENCIES = $(am__DEPENDENCIES_2) \ +@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz-subset.la am__hb_view_SOURCES_DIST = hb-view.cc options.cc options.hh \ main-font-text.hh shape-consumer.hh ansi-print.cc \ ansi-print.hh helper-cairo.cc helper-cairo.hh \ helper-cairo-ansi.cc helper-cairo-ansi.hh view-cairo.cc \ view-cairo.hh -am__objects_4 = hb-view.$(OBJEXT) options.$(OBJEXT) \ +am__objects_5 = hb-view.$(OBJEXT) options.$(OBJEXT) \ ansi-print.$(OBJEXT) helper-cairo.$(OBJEXT) \ helper-cairo-ansi.$(OBJEXT) view-cairo.$(OBJEXT) \ $(am__objects_1) -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am_hb_view_OBJECTS = $(am__objects_4) +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am_hb_view_OBJECTS = $(am__objects_5) hb_view_OBJECTS = $(am_hb_view_OBJECTS) -am__DEPENDENCIES_2 = $(top_builddir)/src/libharfbuzz.la \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@hb_view_DEPENDENCIES = $(am__DEPENDENCIES_2) \ @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) \ @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) \ @@ -202,9 +219,10 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(hb_ot_shape_closure_SOURCES) $(hb_shape_SOURCES) \ - $(hb_view_SOURCES) + $(hb_subset_SOURCES) $(hb_view_SOURCES) DIST_SOURCES = $(am__hb_ot_shape_closure_SOURCES_DIST) \ - $(am__hb_shape_SOURCES_DIST) $(am__hb_view_SOURCES_DIST) + $(am__hb_shape_SOURCES_DIST) $(am__hb_subset_SOURCES_DIST) \ + $(am__hb_view_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -229,6 +247,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.sources \ + $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -245,6 +265,12 @@ CAIRO_LIBS = @CAIRO_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@ +CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@ +CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@ CORETEXT_CFLAGS = @CORETEXT_CFLAGS@ CORETEXT_LIBS = @CORETEXT_LIBS@ CPP = @CPP@ @@ -272,6 +298,8 @@ FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ FREETYPE_DEPS = @FREETYPE_DEPS@ FREETYPE_LIBS = @FREETYPE_LIBS@ +GCOV = @GCOV@ +GENHTML = @GENHTML@ GIT = @GIT@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_DEPS = @GLIB_DEPS@ @@ -311,6 +339,7 @@ INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ @@ -319,6 +348,7 @@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -375,6 +405,7 @@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ +have_gobject = @have_gobject@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -395,6 +426,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -403,11 +435,11 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ +NULL = EXTRA_DIST = CLEANFILES = DISTCLEANFILES = MAINTAINERCLEANFILES = -NULL = HB_VIEW_sources = \ hb-view.cc \ options.cc \ @@ -439,6 +471,13 @@ HB_OT_SHAPE_CLOSURE_sources = \ main-font-text.hh \ $(NULL) +HB_SUBSET_CLI_sources = \ + hb-subset.cc \ + options.cc \ + options.hh \ + main-font-text.hh \ + $(NULL) + AM_CPPFLAGS = \ -DHB_DISABLE_DEPRECATED \ -I$(top_srcdir)/src/ \ @@ -463,6 +502,8 @@ LDADD = \ @HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@ $(NULL) @HAVE_GLIB_TRUE@hb_shape_SOURCES = $(HB_SHAPE_sources) +@HAVE_GLIB_TRUE@hb_subset_SOURCES = $(HB_SUBSET_CLI_sources) +@HAVE_GLIB_TRUE@hb_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la @HAVE_GLIB_TRUE@@HAVE_OT_TRUE@hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources) all: all-am @@ -480,7 +521,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/Makefile.sources $(am__c echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits util/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnits util/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -489,7 +529,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; -$(srcdir)/Makefile.sources: +$(srcdir)/Makefile.sources $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh @@ -573,6 +613,10 @@ hb-shape$(EXEEXT): $(hb_shape_OBJECTS) $(hb_shape_DEPENDENCIES) $(EXTRA_hb_shape @rm -f hb-shape$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(hb_shape_OBJECTS) $(hb_shape_LDADD) $(LIBS) +hb-subset$(EXEEXT): $(hb_subset_OBJECTS) $(hb_subset_DEPENDENCIES) $(EXTRA_hb_subset_DEPENDENCIES) + @rm -f hb-subset$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(hb_subset_OBJECTS) $(hb_subset_LDADD) $(LIBS) + hb-view$(EXEEXT): $(hb_view_OBJECTS) $(hb_view_DEPENDENCIES) $(EXTRA_hb_view_DEPENDENCIES) @rm -f hb-view$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(hb_view_OBJECTS) $(hb_view_LDADD) $(LIBS) @@ -586,6 +630,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ansi-print.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-ot-shape-closure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-shape.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-subset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-view.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper-cairo-ansi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper-cairo.Po@am__quote@ @@ -828,6 +873,8 @@ uninstall-am: uninstall-binPROGRAMS mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS +.PRECIOUS: Makefile + # Convenience targets: lib: diff --git a/util/Makefile.sources b/util/Makefile.sources index 368fdb0..6c815d2 100644 --- a/util/Makefile.sources +++ b/util/Makefile.sources @@ -1,5 +1,3 @@ -NULL = - HB_VIEW_sources = \ hb-view.cc \ options.cc \ @@ -30,3 +28,10 @@ HB_OT_SHAPE_CLOSURE_sources = \ options.hh \ main-font-text.hh \ $(NULL) + +HB_SUBSET_CLI_sources = \ + hb-subset.cc \ + options.cc \ + options.hh \ + main-font-text.hh \ + $(NULL) diff --git a/util/ansi-print.cc b/util/ansi-print.cc index e0ce7b3..0daee1f 100644 --- a/util/ansi-print.cc +++ b/util/ansi-print.cc @@ -353,7 +353,7 @@ block_best (const biimage_t &bi, bool *inverse) } else qs += quad[i][j]; if (qs < score) { - const char *c = NULL; + const char *c = nullptr; bool inv = false; switch (q) { case 1: c = "▟"; inv = true; break; diff --git a/util/ansi-print.hh b/util/ansi-print.hh index dad4d4c..1ea5b37 100644 --- a/util/ansi-print.hh +++ b/util/ansi-print.hh @@ -27,6 +27,7 @@ #ifndef ANSI_PRINT_HH #define ANSI_PRINT_HH +#include "hb-private.hh" #include <hb.h> /* for int types */ void diff --git a/util/hb-ot-shape-closure.cc b/util/hb-ot-shape-closure.cc index 859f9a6..77ca201 100644 --- a/util/hb-ot-shape-closure.cc +++ b/util/hb-ot-shape-closure.cc @@ -43,8 +43,8 @@ struct shape_closure_consumer_t : option_group_t { GOptionEntry entries[] = { - {"no-glyph-names", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &this->show_glyph_names, "Use glyph indices instead of names", NULL}, - {NULL} + {"no-glyph-names", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &this->show_glyph_names, "Use glyph indices instead of names", nullptr}, + {nullptr} }; parser->add_group (entries, "format", @@ -53,14 +53,15 @@ struct shape_closure_consumer_t : option_group_t this); } - void init (const font_options_t *font_opts) + void init (hb_buffer_t *buffer_, + const font_options_t *font_opts) { glyphs = hb_set_create (); font = hb_font_reference (font_opts->get_font ()); failed = false; + buffer = hb_buffer_reference (buffer_); } - void consume_line (hb_buffer_t *buffer, - const char *text, + void consume_line (const char *text, unsigned int text_len, const char *text_before, const char *text_after) @@ -92,9 +93,11 @@ struct shape_closure_consumer_t : option_group_t { printf ("\n"); hb_font_destroy (font); - font = NULL; + font = nullptr; hb_set_destroy (glyphs); - glyphs = NULL; + glyphs = nullptr; + hb_buffer_destroy (buffer); + buffer = nullptr; } bool failed; @@ -105,6 +108,7 @@ struct shape_closure_consumer_t : option_group_t hb_set_t *glyphs; hb_font_t *font; + hb_buffer_t *buffer; }; int diff --git a/util/hb-shape.cc b/util/hb-shape.cc index 75c3793..337cd43 100644 --- a/util/hb-shape.cc +++ b/util/hb-shape.cc @@ -33,16 +33,16 @@ struct output_buffer_t output_buffer_t (option_parser_t *parser) : options (parser, hb_buffer_serialize_list_formats ()), format (parser), - gs (NULL), + gs (nullptr), line_no (0), - font (NULL), + font (nullptr), output_format (HB_BUFFER_SERIALIZE_FORMAT_INVALID), format_flags (HB_BUFFER_SERIALIZE_FLAG_DEFAULT) {} - void init (const font_options_t *font_opts) + void init (hb_buffer_t *buffer, const font_options_t *font_opts) { options.get_file_handle (); - gs = g_string_new (NULL); + gs = g_string_new (nullptr); line_no = 0; font = hb_font_reference (font_opts->get_font ()); @@ -72,9 +72,16 @@ struct output_buffer_t flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS; if (!format.show_positions) flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS; + if (!format.show_advances) + flags |= HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES; if (format.show_extents) flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS; + if (format.show_flags) + flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS; format_flags = (hb_buffer_serialize_flags_t) flags; + + if (format.trace) + hb_buffer_set_message_func (buffer, message_func, this, nullptr); } void new_line (void) { @@ -89,13 +96,10 @@ struct output_buffer_t format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs); fprintf (options.fp, "%s", gs->str); } - void shape_failed (hb_buffer_t *buffer, - const char *text, - unsigned int text_len, - hb_bool_t utf8_clusters) + void error (const char *message) { g_string_set_size (gs, 0); - format.serialize_message (line_no, "msg: all shapers failed", gs); + format.serialize_message (line_no, "error", message, gs); fprintf (options.fp, "%s", gs->str); } void consume_glyphs (hb_buffer_t *buffer, @@ -108,14 +112,40 @@ struct output_buffer_t output_format, format_flags, gs); fprintf (options.fp, "%s", gs->str); } - void finish (const font_options_t *font_opts) + void finish (hb_buffer_t *buffer, const font_options_t *font_opts) { + hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr); hb_font_destroy (font); g_string_free (gs, true); - gs = NULL; - font = NULL; + gs = nullptr; + font = nullptr; + } + + static hb_bool_t + message_func (hb_buffer_t *buffer, + hb_font_t *font, + const char *message, + void *user_data) + { + output_buffer_t *that = (output_buffer_t *) user_data; + that->trace (buffer, font, message); + return true; } + void + trace (hb_buffer_t *buffer, + hb_font_t *font, + const char *message) + { + g_string_set_size (gs, 0); + format.serialize_line_no (line_no, gs); + g_string_append_printf (gs, "trace: %s buffer: ", message); + format.serialize_glyphs (buffer, font, output_format, format_flags, gs); + g_string_append_c (gs, '\n'); + fprintf (options.fp, "%s", gs->str); + } + + protected: output_options_t options; format_options_t format; diff --git a/util/hb-subset.cc b/util/hb-subset.cc new file mode 100644 index 0000000..2061755 --- /dev/null +++ b/util/hb-subset.cc @@ -0,0 +1,127 @@ +/* + * Copyright © 2010 Behdad Esfahbod + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger, Rod Sheeter + */ + +#include <stdio.h> + +#include "main-font-text.hh" +#include "hb-subset.h" +#include "hb-subset-private.hh" + +/* + * Command line interface to the harfbuzz font subsetter. + */ + +struct subset_consumer_t +{ + subset_consumer_t (option_parser_t *parser) + : failed (false), options (parser), subset_options (parser), font (nullptr), input (nullptr) {} + + void init (hb_buffer_t *buffer_, + const font_options_t *font_opts) + { + font = hb_font_reference (font_opts->get_font ()); + input = hb_subset_input_create_or_fail (); + } + + void consume_line (const char *text, + unsigned int text_len, + const char *text_before, + const char *text_after) + { + // TODO(Q1) does this only get called with at least 1 codepoint? + hb_set_t *codepoints = hb_subset_input_unicode_set (input); + 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)) != nullptr); + } + + hb_bool_t + write_file (const char *output_file, hb_blob_t *blob) { + unsigned int data_length; + const char* data = hb_blob_get_data (blob, &data_length); + + FILE *fp_out = fopen(output_file, "wb"); + if (fp_out == nullptr) { + fprintf(stderr, "Unable to open output file\n"); + return false; + } + int bytes_written = fwrite(data, 1, data_length, fp_out); + + fclose (fp_out); + + if (bytes_written == -1) { + fprintf(stderr, "Unable to write output file\n"); + return false; + } + if ((unsigned int) bytes_written != data_length) { + fprintf(stderr, "Expected %u bytes written, got %d\n", data_length, + bytes_written); + return false; + } + return true; + } + + void finish (const font_options_t *font_opts) + { + input->drop_hints = subset_options.drop_hints; + + hb_subset_profile_t *subset_profile = hb_subset_profile_create(); + hb_face_t *face = hb_font_get_face (font); + + hb_face_t *new_face = hb_subset(face, subset_profile, input); + hb_blob_t *result = hb_face_reference_blob (new_face); + + failed = !hb_blob_get_length (result); + if (!failed) + write_file (options.output_file, result); + + hb_subset_profile_destroy (subset_profile); + hb_subset_input_destroy (input); + hb_blob_destroy (result); + hb_face_destroy (new_face); + hb_font_destroy (font); + } + + public: + bool failed; + + private: + output_options_t options; + subset_options_t subset_options; + hb_font_t *font; + hb_subset_input_t *input; +}; + +int +main (int argc, char **argv) +{ + main_font_text_t<subset_consumer_t, 10, 0> driver; + return driver.main (argc, argv); +} diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh index eeaaa50..cf18ea4 100644 --- a/util/helper-cairo-ansi.hh +++ b/util/helper-cairo-ansi.hh @@ -24,11 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#include <cairo.h> - #ifndef HELPER_CAIRO_ANSI_HH #define HELPER_CAIRO_ANSI_HH +#include "hb-private.hh" + +#include <cairo.h> cairo_status_t helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface, diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc index 2e2952b..b9f4985 100644 --- a/util/helper-cairo.cc +++ b/util/helper-cairo.cc @@ -79,7 +79,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts) /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because * cairo will reset the face size. As such, create new face... * TODO Perhaps add API to hb-ft to encapsulate this code. */ - FT_Face ft_face = NULL;//hb_ft_font_get_face (font); + FT_Face ft_face = nullptr;//hb_ft_font_get_face (font); if (!ft_face) { if (!ft_library) @@ -103,6 +103,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts) } else { +#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES unsigned int num_coords; const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); if (num_coords) @@ -116,6 +117,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts) free (ft_coords); } } +#endif cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); } @@ -325,7 +327,7 @@ const char *helper_cairo_supported_formats[] = "eps", #endif #endif - NULL + nullptr }; cairo_t * @@ -337,12 +339,12 @@ helper_cairo_create_context (double w, double h, cairo_surface_t *(*constructor) (cairo_write_func_t write_func, void *closure, double width, - double height) = NULL; + double height) = nullptr; cairo_surface_t *(*constructor2) (cairo_write_func_t write_func, void *closure, double width, double height, - cairo_content_t content) = NULL; + cairo_content_t content) = nullptr; const char *extension = out_opts->output_format; if (!extension) { @@ -471,8 +473,8 @@ helper_cairo_line_from_buffer (helper_cairo_line_t *l, memset (l, 0, sizeof (*l)); l->num_glyphs = hb_buffer_get_length (buffer); - hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, NULL); - hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, NULL); + hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr); + hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr); l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1); if (text) { diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh index 27b6eb3..50bc0af 100644 --- a/util/helper-cairo.hh +++ b/util/helper-cairo.hh @@ -24,13 +24,14 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HELPER_CAIRO_HH +#define HELPER_CAIRO_HH + +#include "hb-private.hh" #include "options.hh" #include <cairo.h> -#ifndef HELPER_CAIRO_HH -#define HELPER_CAIRO_HH - cairo_scaled_font_t * helper_cairo_create_scaled_font (const font_options_t *font_opts); diff --git a/util/main-font-text.hh b/util/main-font-text.hh index 55de567..3390371 100644 --- a/util/main-font-text.hh +++ b/util/main-font-text.hh @@ -24,20 +24,21 @@ * Google Author(s): Behdad Esfahbod */ -#include "options.hh" - #ifndef HB_MAIN_FONT_TEXT_HH #define HB_MAIN_FONT_TEXT_HH +#include "hb-private.hh" +#include "options.hh" + /* main() body for utilities taking font and processing text.*/ static char * locale_to_utf8 (char *s) { char *t; - GError *error = NULL; + GError *error = nullptr; - t = g_locale_to_utf8 (s, -1, NULL, NULL, &error); + t = g_locale_to_utf8 (s, -1, nullptr, nullptr, &error); if (!t) { fail (true, "Failed converting text to UTF-8"); @@ -46,23 +47,6 @@ locale_to_utf8 (char *s) return t; } -static hb_bool_t -message_func (hb_buffer_t *buffer, - hb_font_t *font, - const char *message, - void *user_data) -{ - fprintf (stderr, "HB: %s\n", message); - char buf[4096]; - hb_buffer_serialize_glyphs (buffer, 0, hb_buffer_get_length (buffer), - buf, sizeof (buf), NULL, - font, - HB_BUFFER_SERIALIZE_FORMAT_TEXT, - HB_BUFFER_SERIALIZE_FLAG_DEFAULT); - fprintf (stderr, "HB: buffer [%s]\n", buf); - return true; -} - template <typename consumer_t, int default_font_size, int subpixel_bits> struct main_font_text_t { @@ -87,16 +71,14 @@ struct main_font_text_t if (!input.text && !input.text_file) input.text_file = g_strdup ("-"); - consumer.init (&font_opts); - hb_buffer_t *buffer = hb_buffer_create (); - if (debug) - hb_buffer_set_message_func (buffer, message_func, NULL, NULL); + consumer.init (buffer, &font_opts); + hb_buffer_destroy (buffer); + unsigned int text_len; const char *text; while ((text = input.get_line (&text_len))) - consumer.consume_line (buffer, text, text_len, input.text_before, input.text_after); - hb_buffer_destroy (buffer); + consumer.consume_line (text, text_len, input.text_before, input.text_after); consumer.finish (&font_opts); diff --git a/util/options.cc b/util/options.cc index 0f2e207..db7115c 100644 --- a/util/options.cc +++ b/util/options.cc @@ -70,7 +70,7 @@ hb_bool_t debug = false; static gchar * shapers_to_string (void) { - GString *shapers = g_string_new (NULL); + GString *shapers = g_string_new (nullptr); const char **shaper_list = hb_shape_list_shapers (); for (; *shaper_list; shaper_list++) { @@ -106,11 +106,11 @@ option_parser_t::add_main_options (void) GOptionEntry entries[] = { {"version", 0, G_OPTION_FLAG_NO_ARG, - G_OPTION_ARG_CALLBACK, (gpointer) &show_version, "Show version numbers", NULL}, - {"debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Free all resources before exit", NULL}, - {NULL} + G_OPTION_ARG_CALLBACK, (gpointer) &show_version, "Show version numbers", nullptr}, + {"debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Free all resources before exit", nullptr}, + {nullptr} }; - g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_main_entries (context, entries, nullptr); } static gboolean @@ -121,7 +121,7 @@ pre_parse (GOptionContext *context G_GNUC_UNUSED, { option_group_t *option_group = (option_group_t *) data; option_group->pre_parse (error); - return *error == NULL; + return *error == nullptr; } static gboolean @@ -132,7 +132,7 @@ post_parse (GOptionContext *context G_GNUC_UNUSED, { option_group_t *option_group = static_cast<option_group_t *>(data); option_group->post_parse (error); - return *error == NULL; + return *error == nullptr; } void @@ -143,7 +143,7 @@ option_parser_t::add_group (GOptionEntry *entries, option_group_t *option_group) { GOptionGroup *group = g_option_group_new (name, description, help_description, - static_cast<gpointer>(option_group), NULL); + static_cast<gpointer>(option_group), nullptr); g_option_group_add_entries (group, entries); g_option_group_set_parse_hooks (group, pre_parse, post_parse); g_option_context_add_group (context, group); @@ -154,10 +154,10 @@ option_parser_t::parse (int *argc, char ***argv) { setlocale (LC_ALL, ""); - GError *parse_error = NULL; + GError *parse_error = nullptr; if (!g_option_context_parse (context, argc, argv, &parse_error)) { - if (parse_error != NULL) { + if (parse_error != nullptr) { fail (true, "%s", parse_error->message); //g_error_free (parse_error); } else @@ -225,7 +225,7 @@ parse_features (const char *name G_GNUC_UNUSED, shape_opts->num_features = 0; g_free (shape_opts->features); - shape_opts->features = NULL; + shape_opts->features = nullptr; if (!*s) return true; @@ -240,6 +240,8 @@ parse_features (const char *name G_GNUC_UNUSED, } while (p); shape_opts->features = (hb_feature_t *) calloc (shape_opts->num_features, sizeof (*shape_opts->features)); + if (!shape_opts->features) + return false; /* now do the actual parsing */ p = s; @@ -248,7 +250,7 @@ parse_features (const char *name G_GNUC_UNUSED, char *end = strchr (p, ','); if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features])) shape_opts->num_features++; - p = end ? end + 1 : NULL; + p = end ? end + 1 : nullptr; } return true; @@ -266,7 +268,7 @@ parse_variations (const char *name G_GNUC_UNUSED, font_opts->num_variations = 0; g_free (font_opts->variations); - font_opts->variations = NULL; + font_opts->variations = nullptr; if (!*s) return true; @@ -281,6 +283,8 @@ parse_variations (const char *name G_GNUC_UNUSED, } while (p); font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations)); + if (!font_opts->variations) + return false; /* now do the actual parsing */ p = s; @@ -289,24 +293,86 @@ parse_variations (const char *name G_GNUC_UNUSED, char *end = strchr (p, ','); if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations])) font_opts->num_variations++; - p = end ? end + 1 : NULL; + p = end ? end + 1 : nullptr; } return true; } +static gboolean +parse_text (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + text_options_t *text_opts = (text_options_t *) data; + + if (text_opts->text) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text or --unicodes can be provided but not both"); + return false; + } + + text_opts->text = g_strdup (arg); + return true; +} + + +static gboolean +parse_unicodes (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + text_options_t *text_opts = (text_options_t *) data; + + if (text_opts->text) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text or --unicodes can be provided but not both"); + return false; + } + + GString *gs = g_string_new (nullptr); + char *s = (char *) arg; + char *p; + + while (s && *s) + { + while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t", *s)) + s++; + + errno = 0; + hb_codepoint_t u = strtoul (s, &p, 16); + if (errno || s == p) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing Unicode values at: '%s'", s); + return false; + } + + g_string_append_unichar (gs, u); + + s = p; + } + + text_opts->text = g_string_free (gs, FALSE); + return true; +} + void view_options_t::add_options (option_parser_t *parser) { GOptionEntry entries[] = { - {"annotate", 0, 0, G_OPTION_ARG_NONE, &this->annotate, "Annotate output rendering", NULL}, + {"annotate", 0, 0, G_OPTION_ARG_NONE, &this->annotate, "Annotate output rendering", nullptr}, {"background", 0, 0, G_OPTION_ARG_STRING, &this->back, "Set background color (default: " DEFAULT_BACK ")", "rrggbb/rrggbbaa"}, {"foreground", 0, 0, G_OPTION_ARG_STRING, &this->fore, "Set foreground color (default: " DEFAULT_FORE ")", "rrggbb/rrggbbaa"}, {"line-space", 0, 0, G_OPTION_ARG_DOUBLE, &this->line_space, "Set space between lines (default: 0)", "units"}, {"margin", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_margin, "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"}, - {NULL} + {nullptr} }; parser->add_group (entries, "view", @@ -321,21 +387,23 @@ shape_options_t::add_options (option_parser_t *parser) GOptionEntry entries[] = { {"list-shapers", 0, G_OPTION_FLAG_NO_ARG, - G_OPTION_ARG_CALLBACK, (gpointer) &list_shapers, "List available shapers and quit", NULL}, + G_OPTION_ARG_CALLBACK, (gpointer) &list_shapers, "List available shapers and quit", nullptr}, {"shaper", 0, G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_CALLBACK, (gpointer) &parse_shapers, "Hidden duplicate of --shapers", NULL}, + G_OPTION_ARG_CALLBACK, (gpointer) &parse_shapers, "Hidden duplicate of --shapers", nullptr}, {"shapers", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_shapers, "Set comma-separated list of shapers to try","list"}, {"direction", 0, 0, G_OPTION_ARG_STRING, &this->direction, "Set text direction (default: auto)", "ltr/rtl/ttb/btt"}, {"language", 0, 0, G_OPTION_ARG_STRING, &this->language, "Set text language (default: $LANG)", "langstr"}, {"script", 0, 0, G_OPTION_ARG_STRING, &this->script, "Set text script (default: auto)", "ISO-15924 tag"}, - {"bot", 0, 0, G_OPTION_ARG_NONE, &this->bot, "Treat text as beginning-of-paragraph", NULL}, - {"eot", 0, 0, G_OPTION_ARG_NONE, &this->eot, "Treat text as end-of-paragraph", NULL}, - {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", NULL}, - {"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", NULL}, + {"bot", 0, 0, G_OPTION_ARG_NONE, &this->bot, "Treat text as beginning-of-paragraph", nullptr}, + {"eot", 0, 0, G_OPTION_ARG_NONE, &this->eot, "Treat text as end-of-paragraph", nullptr}, + {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr}, + {"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr}, + {"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr}, {"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"}, - {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", NULL}, + {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr}, + {"verify", 0, 0, G_OPTION_ARG_NONE, &this->verify, "Perform sanity checks on shaping results", nullptr}, {"num-iterations", 0, 0, G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"}, - {NULL} + {nullptr} }; parser->add_group (entries, "shape", @@ -382,7 +450,7 @@ shape_options_t::add_options (option_parser_t *parser) GOptionEntry entries2[] = { {"features", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_features, features_help, "list"}, - {NULL} + {nullptr} }; parser->add_group (entries2, "features", @@ -408,19 +476,39 @@ parse_font_size (const char *name G_GNUC_UNUSED, case 2: return true; default: g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "%s argument should be one to four space-separated numbers", + "%s argument should be one or two space-separated numbers", name); return false; } } + +static gboolean +parse_font_ppem (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + font_options_t *font_opts = (font_options_t *) data; + switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) { + case 1: font_opts->y_ppem = font_opts->x_ppem; + case 2: return true; + default: + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "%s argument should be one or two space-separated numbers", + name); + return false; + } +} + void font_options_t::add_options (option_parser_t *parser) { - char *text = NULL; + char *text = nullptr; { - ASSERT_STATIC (ARRAY_LENGTH_CONST (supported_font_funcs) > 0); - GString *s = g_string_new (NULL); + static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0), + "No supported font-funcs found."); + GString *s = g_string_new (nullptr); g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n Supported font function implementations are: %s", supported_font_funcs[0].name, supported_font_funcs[0].name); @@ -444,12 +532,14 @@ font_options_t::add_options (option_parser_t *parser) GOptionEntry entries[] = { - {"font-file", 0, 0, G_OPTION_ARG_STRING, &this->font_file, "Set font file-name", "filename"}, - {"face-index", 0, 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"}, + {"font-file", 0, 0, G_OPTION_ARG_STRING, &this->font_file, "Set font file-name", "filename"}, + {"face-index", 0, 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"}, {"font-size", 0, default_font_size ? 0 : G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_size, font_size_text, "1/2 numbers or 'upem'"}, - {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"}, - {NULL} + G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_size, font_size_text, "1/2 integers or 'upem'"}, + {"font-ppem", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"}, + {"font-ptem", 0, 0, G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"}, + {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"}, + {nullptr} }; parser->add_group (entries, "font", @@ -472,11 +562,11 @@ font_options_t::add_options (option_parser_t *parser) GOptionEntry entries2[] = { {"variations", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_variations, variations_help, "list"}, - {NULL} + {nullptr} }; parser->add_group (entries2, "variations", - "Varitions options:", + "Variations options:", "Options for font variations used", this); } @@ -486,11 +576,12 @@ text_options_t::add_options (option_parser_t *parser) { GOptionEntry entries[] = { - {"text", 0, 0, G_OPTION_ARG_STRING, &this->text, "Set input text", "string"}, + {"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Set input text", "string"}, {"text-file", 0, 0, G_OPTION_ARG_STRING, &this->text_file, "Set input text file-name\n\n If no text is provided, standard input is used for input.\n", "filename"}, + {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Set input Unicode codepoints", "list of hex numbers"}, {"text-before", 0, 0, G_OPTION_ARG_STRING, &this->text_before, "Set text context before each line", "string"}, {"text-after", 0, 0, G_OPTION_ARG_STRING, &this->text_after, "Set text context after each line", "string"}, - {NULL} + {nullptr} }; parser->add_group (entries, "text", @@ -504,7 +595,7 @@ output_options_t::add_options (option_parser_t *parser) { const char *text; - if (NULL == supported_formats) + if (nullptr == supported_formats) text = "Set output serialization format"; else { @@ -516,9 +607,9 @@ output_options_t::add_options (option_parser_t *parser) GOptionEntry entries[] = { - {"output-file", 0, 0, G_OPTION_ARG_STRING, &this->output_file, "Set output file-name (default: stdout)","filename"}, - {"output-format", 0, 0, G_OPTION_ARG_STRING, &this->output_format, text, "format"}, - {NULL} + {"output-file", 'o', 0, G_OPTION_ARG_STRING, &this->output_file, "Set output file-name (default: stdout)","filename"}, + {"output-format", 'O', 0, G_OPTION_ARG_STRING, &this->output_format, text, "format"}, + {nullptr} }; parser->add_group (entries, "output", @@ -535,7 +626,7 @@ font_options_t::get_font (void) const if (font) return font; - hb_blob_t *blob = NULL; + hb_blob_t *blob = nullptr; /* Create the blob */ { @@ -551,7 +642,7 @@ font_options_t::get_font (void) const if (0 == strcmp (font_file, "-")) { /* read it */ - GString *gs = g_string_new (NULL); + GString *gs = g_string_new (nullptr); char buf[BUFSIZ]; #if defined(_WIN32) || defined(__CYGWIN__) setmode (fileno (stdin), O_BINARY); @@ -569,7 +660,7 @@ font_options_t::get_font (void) const destroy = (hb_destroy_func_t) g_free; mm = HB_MEMORY_MODE_WRITABLE; } else { - GError *error = NULL; + GError *error = nullptr; GMappedFile *mf = g_mapped_file_new (font_file, false, &error); if (mf) { font_data = g_mapped_file_get_contents (mf); @@ -588,7 +679,7 @@ font_options_t::get_font (void) const /* GMappedFile is buggy, it doesn't fail if file isn't regular. * Try reading. * https://bugzilla.gnome.org/show_bug.cgi?id=659212 */ - GError *error = NULL; + GError *error = nullptr; gsize l; if (g_file_get_contents (font_file, &font_data, &l, &error)) { len = l; @@ -620,6 +711,9 @@ font_options_t::get_font (void) const if (font_size_y == FONT_SIZE_UPEM) font_size_y = hb_face_get_upem (face); + hb_font_set_ppem (font, x_ppem, y_ppem); + hb_font_set_ptem (font, ptem); + int scale_x = (int) scalbnf (font_size_x, subpixel_bits); int scale_y = (int) scalbnf (font_size_y, subpixel_bits); hb_font_set_scale (font, scale_x, scale_y); @@ -627,7 +721,7 @@ font_options_t::get_font (void) const hb_font_set_variations (font, variations, num_variations); - void (*set_font_funcs) (hb_font_t *) = NULL; + void (*set_font_funcs) (hb_font_t *) = nullptr; if (!font_funcs) { set_font_funcs = supported_font_funcs[0].func; @@ -642,7 +736,7 @@ font_options_t::get_font (void) const } if (!set_font_funcs) { - GString *s = g_string_new (NULL); + GString *s = g_string_new (nullptr); for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) { if (i) @@ -673,7 +767,7 @@ text_options_t::get_line (unsigned int *len) if (!line_len) { *len = 0; - return NULL; + return nullptr; } const char *ret = line; @@ -706,9 +800,15 @@ text_options_t::get_line (unsigned int *len) fail (false, "Failed opening text file `%s': %s", text_file, strerror (errno)); - gs = g_string_new (NULL); + gs = g_string_new (nullptr); } +#ifdef HAVE_SETLINEBUF + setlinebuf (fp); +#else + setvbuf(fp, NULL, _IOLBF, BUFSIZ); +#endif + g_string_set_size (gs, 0); char buf[BUFSIZ]; while (fgets (buf, sizeof (buf), fp)) { @@ -724,7 +824,7 @@ text_options_t::get_line (unsigned int *len) fail (false, "Failed reading text: %s", strerror (errno)); *len = gs->len; - return !*len && feof (fp) ? NULL : gs->str; + return !*len && feof (fp) ? nullptr : gs->str; } @@ -746,6 +846,12 @@ output_options_t::get_file_handle (void) fail (false, "Cannot open output file `%s': %s", g_filename_display_name (output_file), strerror (errno)); +#ifdef HAVE_SETLINEBUF + setlinebuf (fp); +#else + setvbuf(fp, NULL, _IOLBF, BUFSIZ); +#endif + return fp; } @@ -760,24 +866,41 @@ parse_verbose (const char *name G_GNUC_UNUSED, return true; } +static gboolean +parse_ned (const char *name G_GNUC_UNUSED, + const char *arg G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED) +{ + format_options_t *format_opts = (format_options_t *) data; + format_opts->show_clusters = format_opts->show_advances = false; + return true; +} + void format_options_t::add_options (option_parser_t *parser) { GOptionEntry entries[] = { - {"show-text", 0, 0, G_OPTION_ARG_NONE, &this->show_text, "Prefix each line of output with its corresponding input text", NULL}, - {"show-unicode", 0, 0, G_OPTION_ARG_NONE, &this->show_unicode, "Prefix each line of output with its corresponding input codepoint(s)", NULL}, - {"show-line-num", 0, 0, G_OPTION_ARG_NONE, &this->show_line_num, "Prefix each line of output with its corresponding input line number", NULL}, - {"verbose", 0, G_OPTION_FLAG_NO_ARG, - G_OPTION_ARG_CALLBACK, (gpointer) &parse_verbose, "Prefix each line of output with all of the above", NULL}, + {"show-text", 0, 0, G_OPTION_ARG_NONE, &this->show_text, "Prefix each line of output with its corresponding input text", nullptr}, + {"show-unicode", 0, 0, G_OPTION_ARG_NONE, &this->show_unicode, "Prefix each line of output with its corresponding input codepoint(s)", nullptr}, + {"show-line-num", 0, 0, G_OPTION_ARG_NONE, &this->show_line_num, "Prefix each line of output with its corresponding input line number", nullptr}, + {"verbose", 'v', G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, (gpointer) &parse_verbose, "Prefix each line of output with all of the above", nullptr}, {"no-glyph-names", 0, G_OPTION_FLAG_REVERSE, - G_OPTION_ARG_NONE, &this->show_glyph_names, "Output glyph indices instead of names", NULL}, + G_OPTION_ARG_NONE, &this->show_glyph_names, "Output glyph indices instead of names", nullptr}, {"no-positions", 0, G_OPTION_FLAG_REVERSE, - G_OPTION_ARG_NONE, &this->show_positions, "Do not output glyph positions", NULL}, + G_OPTION_ARG_NONE, &this->show_positions, "Do not output glyph positions", nullptr}, + {"no-advances", 0, G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, &this->show_advances, "Do not output glyph advances", nullptr}, {"no-clusters", 0, G_OPTION_FLAG_REVERSE, - G_OPTION_ARG_NONE, &this->show_clusters, "Do not output cluster indices", NULL}, - {"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Output glyph extents", NULL}, - {NULL} + G_OPTION_ARG_NONE, &this->show_clusters, "Do not output cluster indices", nullptr}, + {"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Output glyph extents", nullptr}, + {"show-flags", 0, 0, G_OPTION_ARG_NONE, &this->show_flags, "Output glyph flags", nullptr}, + {"ned", 'v', G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, (gpointer) &parse_ned, "No Extra Data; Do not output clusters or advances", nullptr}, + {"trace", 'V', 0, G_OPTION_ARG_NONE, &this->trace, "Output interim shaping results", nullptr}, + {nullptr} }; parser->add_group (entries, "output-syntax", @@ -794,7 +917,7 @@ format_options_t::serialize_unicode (hb_buffer_t *buffer, GString *gs) { unsigned int num_glyphs = hb_buffer_get_length (buffer); - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); g_string_append_c (gs, '<'); for (unsigned int i = 0; i < num_glyphs; i++) @@ -818,7 +941,8 @@ format_options_t::serialize_glyphs (hb_buffer_t *buffer, unsigned int num_glyphs = hb_buffer_get_length (buffer); unsigned int start = 0; - while (start < num_glyphs) { + while (start < num_glyphs) + { char buf[1024]; unsigned int consumed; start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs, @@ -845,7 +969,8 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer, hb_font_t *font, GString *gs) { - if (show_text) { + if (show_text) + { serialize_line_no (line_no, gs); g_string_append_c (gs, '('); g_string_append_len (gs, text, text_len); @@ -853,7 +978,8 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer, g_string_append_c (gs, '\n'); } - if (show_unicode) { + if (show_unicode) + { serialize_line_no (line_no, gs); serialize_unicode (buffer, gs); g_string_append_c (gs, '\n'); @@ -861,11 +987,12 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer, } void format_options_t::serialize_message (unsigned int line_no, + const char *type, const char *msg, GString *gs) { serialize_line_no (line_no, gs); - g_string_append_printf (gs, "%s", msg); + g_string_append_printf (gs, "%s: %s", type, msg); g_string_append_c (gs, '\n'); } void @@ -882,3 +1009,18 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t *buffer, serialize_glyphs (buffer, font, output_format, format_flags, gs); g_string_append_c (gs, '\n'); } + +void +subset_options_t::add_options (option_parser_t *parser) +{ + GOptionEntry entries[] = + { + {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr}, + {nullptr} + }; + parser->add_group (entries, + "subset", + "Subset options:", + "Options subsetting", + this); +} diff --git a/util/options.hh b/util/options.hh index 9ed4fd0..467350a 100644 --- a/util/options.hh +++ b/util/options.hh @@ -27,15 +27,13 @@ #ifndef OPTIONS_HH #define OPTIONS_HH - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include "hb-private.hh" #include <stdlib.h> #include <stddef.h> #include <string.h> #include <stdio.h> +#include <assert.h> #include <math.h> #include <locale.h> #include <errno.h> @@ -58,35 +56,8 @@ # define g_mapped_file_unref g_mapped_file_free #endif - -/* A few macros copied from hb-private.hh. */ - -#if __GNUC__ >= 4 -#define HB_UNUSED __attribute__((unused)) -#else -#define HB_UNUSED -#endif - -#undef MIN -template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } - -#undef MAX -template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; } - -#undef ARRAY_LENGTH -template <typename Type, unsigned int n> -static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } -/* A const version, but does not detect erratically being called on pointers. */ -#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) - -#define _ASSERT_STATIC1(_line, _cond) HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] -#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond)) -#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond)) - - void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3); - extern hb_bool_t debug; struct option_group_t @@ -110,7 +81,7 @@ struct option_parser_t } ~option_parser_t (void) { g_option_context_free (context); - g_ptr_array_foreach (to_free, (GFunc) g_free, NULL); + g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr); g_ptr_array_free (to_free, TRUE); } @@ -150,8 +121,8 @@ struct view_options_t : option_group_t { view_options_t (option_parser_t *parser) { annotate = false; - fore = NULL; - back = NULL; + fore = nullptr; + back = nullptr; line_space = 0; margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN; @@ -179,14 +150,15 @@ struct shape_options_t : option_group_t { shape_options_t (option_parser_t *parser) { - direction = language = script = NULL; - bot = eot = preserve_default_ignorables = false; - features = NULL; + direction = language = script = nullptr; + bot = eot = preserve_default_ignorables = remove_default_ignorables = false; + features = nullptr; num_features = 0; - shapers = NULL; + shapers = nullptr; utf8_clusters = false; cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; normalize_glyphs = false; + verify = false; num_iterations = 1; add_options (parser); @@ -207,14 +179,26 @@ struct shape_options_t : option_group_t hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1)); hb_buffer_set_script (buffer, hb_script_from_string (script, -1)); hb_buffer_set_language (buffer, hb_language_from_string (language, -1)); - hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_DEFAULT | - (bot ? HB_BUFFER_FLAG_BOT : 0) | - (eot ? HB_BUFFER_FLAG_EOT : 0) | - (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0))); + hb_buffer_set_flags (buffer, (hb_buffer_flags_t) + (HB_BUFFER_FLAG_DEFAULT | + (bot ? HB_BUFFER_FLAG_BOT : 0) | + (eot ? HB_BUFFER_FLAG_EOT : 0) | + (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) | + (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) | + 0)); hb_buffer_set_cluster_level (buffer, cluster_level); hb_buffer_guess_segment_properties (buffer); } + static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src) + { + hb_segment_properties_t props; + hb_buffer_get_segment_properties (src, &props); + hb_buffer_set_segment_properties (dst, &props); + hb_buffer_set_flags (dst, hb_buffer_get_flags (src)); + hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src)); + } + void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len, const char *text_before, const char *text_after) { @@ -232,7 +216,7 @@ struct shape_options_t : option_group_t /* Reset cluster values to refer to Unicode character index * instead of UTF-8 index. */ unsigned int num_glyphs = hb_buffer_get_length (buffer); - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); for (unsigned int i = 0; i < num_glyphs; i++) { info->cluster = i; @@ -243,12 +227,188 @@ struct shape_options_t : option_group_t setup_buffer (buffer); } - hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer) + hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr) { - hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers); + hb_buffer_t *text_buffer = nullptr; + if (verify) + { + text_buffer = hb_buffer_create (); + hb_buffer_append (text_buffer, buffer, 0, -1); + } + + if (!hb_shape_full (font, buffer, features, num_features, shapers)) + { + if (error) + *error = "all shapers failed."; + goto fail; + } + if (normalize_glyphs) hb_buffer_normalize_glyphs (buffer); - return res; + + if (verify && !verify_buffer (buffer, text_buffer, font, error)) + goto fail; + + if (text_buffer) + hb_buffer_destroy (text_buffer); + + return true; + + fail: + if (text_buffer) + hb_buffer_destroy (text_buffer); + + return false; + } + + bool verify_buffer (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const char **error=nullptr) + { + if (!verify_buffer_monotone (buffer, error)) + return false; + if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error)) + return false; + return true; + } + + bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr) + { + /* Check that clusters are monotone. */ + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES || + cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + for (unsigned int i = 1; i < num_glyphs; i++) + if (info[i-1].cluster != info[i].cluster && + (info[i-1].cluster < info[i].cluster) != is_forward) + { + if (error) + *error = "clusters are not monotone."; + return false; + } + } + + return true; + } + + bool verify_buffer_safe_to_break (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const char **error=nullptr) + { + if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && + cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + /* Cannot perform this check without monotone clusters. + * Then again, unsafe-to-break flag is much harder to use without + * monotone clusters. */ + return true; + } + + /* Check that breaking up shaping at safe-to-break is indeed safe. */ + + hb_buffer_t *fragment = hb_buffer_create (); + hb_buffer_t *reconstruction = hb_buffer_create (); + copy_buffer_properties (reconstruction, buffer); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + unsigned int num_chars; + hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); + + /* Chop text and shape fragments. */ + bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + unsigned int start = 0; + unsigned int text_start = forward ? 0 : num_chars; + unsigned int text_end = text_start; + for (unsigned int end = 1; end < num_glyphs + 1; end++) + { + if (end < num_glyphs && + (info[end].cluster == info[end-1].cluster || + info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)) + continue; + + /* Shape segment corresponding to glyphs start..end. */ + if (end == num_glyphs) + { + if (forward) + text_end = num_chars; + else + text_start = 0; + } + else + { + if (forward) + { + unsigned int cluster = info[end].cluster; + while (text_end < num_chars && text[text_end].cluster < cluster) + text_end++; + } + else + { + unsigned int cluster = info[end - 1].cluster; + while (text_start && text[text_start - 1].cluster >= cluster) + text_start--; + } + } + assert (text_start < text_end); + + if (0) + printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + + hb_buffer_clear_contents (fragment); + copy_buffer_properties (fragment, buffer); + + /* TODO: Add pre/post context text. */ + hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); + if (0 < text_start) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + if (text_end < num_chars) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + hb_buffer_set_flags (fragment, flags); + + hb_buffer_append (fragment, text_buffer, text_start, text_end); + if (!hb_shape_full (font, fragment, features, num_features, shapers)) + { + if (error) + *error = "all shapers failed while shaping fragment."; + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + return false; + } + hb_buffer_append (reconstruction, fragment, 0, -1); + + start = end; + if (forward) + text_start = text_end; + else + text_end = text_start; + } + + bool ret = true; + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff) + { + if (error) + *error = "Safe-to-break test failed."; + ret = false; + + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } + + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + + return ret; } void shape_closure (const char *text, int text_len, @@ -270,6 +430,7 @@ struct shape_options_t : option_group_t hb_bool_t bot; hb_bool_t eot; hb_bool_t preserve_default_ignorables; + hb_bool_t remove_default_ignorables; hb_feature_t *features; unsigned int num_features; @@ -277,6 +438,7 @@ struct shape_options_t : option_group_t hb_bool_t utf8_clusters; hb_buffer_cluster_level_t cluster_level; hb_bool_t normalize_glyphs; + hb_bool_t verify; unsigned int num_iterations; }; @@ -287,16 +449,19 @@ struct font_options_t : option_group_t int default_font_size_, unsigned int subpixel_bits_) { - variations = NULL; + variations = nullptr; num_variations = 0; default_font_size = default_font_size_; + x_ppem = 0; + y_ppem = 0; + ptem = 0.; subpixel_bits = subpixel_bits_; - font_file = NULL; + font_file = nullptr; face_index = 0; font_size_x = font_size_y = default_font_size; - font_funcs = NULL; + font_funcs = nullptr; - font = NULL; + font = nullptr; add_options (parser); } @@ -316,6 +481,9 @@ struct font_options_t : option_group_t hb_variation_t *variations; unsigned int num_variations; int default_font_size; + int x_ppem; + int y_ppem; + double ptem; unsigned int subpixel_bits; mutable double font_size_x; mutable double font_size_y; @@ -329,15 +497,15 @@ struct font_options_t : option_group_t struct text_options_t : option_group_t { text_options_t (option_parser_t *parser) { - text_before = NULL; - text_after = NULL; + text_before = nullptr; + text_after = nullptr; - text = NULL; - text_file = NULL; + text = nullptr; + text_file = nullptr; - fp = NULL; - gs = NULL; - line = NULL; + fp = nullptr; + gs = nullptr; + line = nullptr; line_len = (unsigned int) -1; add_options (parser); @@ -380,13 +548,13 @@ struct text_options_t : option_group_t struct output_options_t : option_group_t { output_options_t (option_parser_t *parser, - const char **supported_formats_ = NULL) { - output_file = NULL; - output_format = NULL; + const char **supported_formats_ = nullptr) { + output_file = nullptr; + output_format = nullptr; supported_formats = supported_formats_; explicit_output_format = false; - fp = NULL; + fp = nullptr; add_options (parser); } @@ -414,7 +582,7 @@ struct output_options_t : option_group_t } if (output_file && 0 == strcmp (output_file, "-")) - output_file = NULL; /* STDOUT */ + output_file = nullptr; /* STDOUT */ } FILE *get_file_handle (void); @@ -432,11 +600,14 @@ struct format_options_t : option_group_t format_options_t (option_parser_t *parser) { show_glyph_names = true; show_positions = true; + show_advances = true; show_clusters = true; show_text = false; show_unicode = false; show_line_num = false; show_extents = false; + show_flags = false; + trace = false; add_options (parser); } @@ -459,6 +630,7 @@ struct format_options_t : option_group_t hb_font_t *font, GString *gs); void serialize_message (unsigned int line_no, + const char *type, const char *msg, GString *gs); void serialize_buffer_of_glyphs (hb_buffer_t *buffer, @@ -473,11 +645,28 @@ struct format_options_t : option_group_t hb_bool_t show_glyph_names; hb_bool_t show_positions; + hb_bool_t show_advances; hb_bool_t show_clusters; hb_bool_t show_text; hb_bool_t show_unicode; hb_bool_t show_line_num; hb_bool_t show_extents; + hb_bool_t show_flags; + hb_bool_t trace; +}; + +struct subset_options_t : option_group_t +{ + subset_options_t (option_parser_t *parser) + { + drop_hints = false; + + add_options (parser); + } + + void add_options (option_parser_t *parser); + + hb_bool_t drop_hints; }; /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */ diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh index 422c8cd..fa419f1 100644 --- a/util/shape-consumer.hh +++ b/util/shape-consumer.hh @@ -24,11 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#include "options.hh" - #ifndef HB_SHAPE_CONSUMER_HH #define HB_SHAPE_CONSUMER_HH +#include "hb-private.hh" +#include "options.hh" + template <typename output_t> struct shape_consumer_t @@ -37,16 +38,19 @@ struct shape_consumer_t : failed (false), shaper (parser), output (parser), - font (NULL) {} + font (nullptr), + buffer (nullptr) {} - void init (const font_options_t *font_opts) + void init (hb_buffer_t *buffer_, + const font_options_t *font_opts) { font = hb_font_reference (font_opts->get_font ()); - output.init (font_opts); failed = false; + buffer = hb_buffer_reference (buffer_); + + output.init (buffer, font_opts); } - void consume_line (hb_buffer_t *buffer, - const char *text, + void consume_line (const char *text, unsigned int text_len, const char *text_before, const char *text_after) @@ -55,14 +59,19 @@ struct shape_consumer_t for (unsigned int n = shaper.num_iterations; n; n--) { + const char *error = nullptr; + shaper.populate_buffer (buffer, text, text_len, text_before, text_after); if (n == 1) output.consume_text (buffer, text, text_len, shaper.utf8_clusters); - if (!shaper.shape (font, buffer)) { + if (!shaper.shape (font, buffer, &error)) + { failed = true; - hb_buffer_set_length (buffer, 0); - output.shape_failed (buffer, text, text_len, shaper.utf8_clusters); - return; + output.error (error); + if (hb_buffer_get_content_type (buffer) == HB_BUFFER_CONTENT_TYPE_GLYPHS) + break; + else + return; } } @@ -70,9 +79,11 @@ struct shape_consumer_t } void finish (const font_options_t *font_opts) { - output.finish (font_opts); + output.finish (buffer, font_opts); hb_font_destroy (font); - font = NULL; + font = nullptr; + hb_buffer_destroy (buffer); + buffer = nullptr; } public: @@ -83,6 +94,7 @@ struct shape_consumer_t output_t output; hb_font_t *font; + hb_buffer_t *buffer; }; diff --git a/util/view-cairo.hh b/util/view-cairo.hh index f55d4bb..d28c3cd 100644 --- a/util/view-cairo.hh +++ b/util/view-cairo.hh @@ -24,12 +24,13 @@ * Google Author(s): Behdad Esfahbod */ -#include "options.hh" -#include "helper-cairo.hh" - #ifndef VIEW_CAIRO_HH #define VIEW_CAIRO_HH +#include "hb-private.hh" +#include "options.hh" +#include "helper-cairo.hh" + struct view_cairo_t { @@ -43,7 +44,7 @@ struct view_cairo_t cairo_debug_reset_static_data (); } - void init (const font_options_t *font_opts) + void init (hb_buffer_t *buffer, const font_options_t *font_opts) { lines = g_array_new (false, false, sizeof (helper_cairo_line_t)); scale_bits = -font_opts->subpixel_bits; @@ -57,12 +58,9 @@ struct view_cairo_t hb_bool_t utf8_clusters) { } - void shape_failed (hb_buffer_t *buffer, - const char *text, - unsigned int text_len, - hb_bool_t utf8_clusters) + void error (const char *message) { - fail (false, "all shapers failed"); + g_printerr ("%s: %s\n", g_get_prgname (), message); } void consume_glyphs (hb_buffer_t *buffer, const char *text, @@ -74,7 +72,7 @@ struct view_cairo_t helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale_bits, utf8_clusters); g_array_append_val (lines, l); } - void finish (const font_options_t *font_opts) + void finish (hb_buffer_t *buffer, const font_options_t *font_opts) { render (font_opts); |