diff options
author | Bowon Ryu <bowon.ryu@samsung.com> | 2019-02-14 17:33:09 +0900 |
---|---|---|
committer | Bowon Ryu <bowon.ryu@samsung.com> | 2019-02-14 17:33:09 +0900 |
commit | 1baac414088e430483b85f702898c8448083bfc2 (patch) | |
tree | 59799dda277ac726617ff1b6ffb4747e775f551a /src | |
parent | b9f425ddd6223cd82b3d35f13fbd060d3c0c0e38 (diff) | |
download | harfbuzz-1baac414088e430483b85f702898c8448083bfc2.tar.gz harfbuzz-1baac414088e430483b85f702898c8448083bfc2.tar.bz2 harfbuzz-1baac414088e430483b85f702898c8448083bfc2.zip |
Imported Upstream version 2.3.1upstream/2.3.1
Diffstat (limited to 'src')
242 files changed, 38785 insertions, 18228 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 9d5662e..4a130e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,8 +13,8 @@ TESTS = check_PROGRAMS = # Convenience targets: -lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la -fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la +lib: $(BUILT_SOURCES) libharfbuzz.la +libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) lib_LTLIBRARIES = libharfbuzz.la @@ -28,12 +28,6 @@ HBSOURCES = $(HB_BASE_sources) HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources) HBHEADERS = $(HB_BASE_headers) -if HAVE_OT -HBSOURCES += $(HB_OT_sources) -HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources) -HBHEADERS += $(HB_OT_headers) -endif - if HAVE_FALLBACK HBSOURCES += $(HB_FALLBACK_sources) endif @@ -170,37 +164,6 @@ pkginclude_HEADERS += $(HB_SUBSET_headers) pkgconfig_DATA += harfbuzz-subset.pc EXTRA_DIST += harfbuzz-subset.pc.in -FUZZING_CPPFLAGS = \ - -DHB_NDEBUG \ - -DHB_MAX_NESTING_LEVEL=3 \ - -DHB_SANITIZE_MAX_EDITS=3 \ - -DHB_SANITIZE_MAX_OPS_FACTOR=3 \ - -DHB_SANITIZE_MAX_OPS_MIN=128 \ - -DHB_BUFFER_MAX_LEN_FACTOR=3 \ - -DHB_BUFFER_MAX_LEN_MIN=8 \ - -DHB_BUFFER_MAX_LEN_DEFAULT=128 \ - -DHB_BUFFER_MAX_OPS_FACTOR=8 \ - -DHB_BUFFER_MAX_OPS_MIN=64 \ - -DHB_BUFFER_MAX_OPS_DEFAULT=1024 \ - $(NULL) -EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la - -libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS) -libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES) -libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD) -EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES) -CLEANFILES += libharfbuzz-fuzzing.la - -libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS) -libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES) -libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_subset_fuzzing_la_LIBADD = $(libharfbuzz_subset_la_LIBADD) -EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES) -CLEANFILES += libharfbuzz-subset-fuzzing.la - if HAVE_ICU if HAVE_ICU_BUILTIN HBCFLAGS += $(ICU_CFLAGS) @@ -270,31 +233,37 @@ EXTRA_DIST += \ CLEANFILES += $(pkgconfig_DATA) -DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def +DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt if HAVE_GOBJECT DEF_FILES += harfbuzz-gobject.def endif check: $(DEF_FILES) # For check-symbols.sh CLEANFILES += $(DEF_FILES) harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-subset.def: $(HB_SUBSET_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-icu.def: $(HB_ICU_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-gobject.def: $(HB_GOBJECT_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ +harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h + $(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^ GENERATORS = \ gen-arabic-table.py \ + gen-def.py \ + gen-emoji-table.py \ gen-indic-table.py \ + gen-os2-unicode-ranges.py \ + gen-tag-table.py \ gen-use-table.py \ - gen-def.py \ + gen-vowel-constraints.py \ $(NULL) EXTRA_DIST += $(GENERATORS) -unicode-tables: arabic-table indic-table use-table +unicode-tables: arabic-table indic-table tag-table use-table emoji-table arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \ @@ -304,22 +273,32 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategor $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false) +tag-table: gen-tag-table.py languagetags language-subtag-registry + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \ + || ($(RM) $(srcdir)/hb-ot-tag-table.hh; false) + use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false) +vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \ + || ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false) + +emoji-table: gen-emoji-table.py emoji-data.txt + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ + || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) + built-sources: $(BUILT_SOURCES) -.PHONY: unicode-tables arabic-table indic-table use-table built-sources +.PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-table built-sources RAGEL_GENERATED = \ $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ - $(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \ $(NULL) BUILT_SOURCES += $(RAGEL_GENERATED) EXTRA_DIST += \ $(HB_BASE_RAGEL_sources) \ - $(HB_OT_RAGEL_sources) \ $(NULL) # We decided to add ragel-generated files to git... #MAINTAINERCLEANFILES += $(RAGEL_GENERATED) @@ -331,6 +310,7 @@ noinst_PROGRAMS = \ main \ test \ test-buffer-serialize \ + test-name-table \ test-size-params \ test-would-substitute \ $(NULL) @@ -344,17 +324,30 @@ test_SOURCES = test.cc test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) -test_would_substitute_SOURCES = test-would-substitute.cc -test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) -test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) +test_buffer_serialize_SOURCES = test-buffer-serialize.cc +test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) +test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) + +test_name_table_SOURCES = test-name-table.cc +test_name_table_CPPFLAGS = $(HBCFLAGS) +test_name_table_LDADD = libharfbuzz.la $(HBLIBS) test_size_params_SOURCES = test-size-params.cc test_size_params_CPPFLAGS = $(HBCFLAGS) test_size_params_LDADD = libharfbuzz.la $(HBLIBS) -test_buffer_serialize_SOURCES = test-buffer-serialize.cc -test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) -test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) +test_would_substitute_SOURCES = test-would-substitute.cc +test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) +test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) + +if HAVE_FREETYPE +if HAVE_CAIRO_FT +noinst_PROGRAMS += test-ot-color +test_ot_color_SOURCES = test-ot-color.cc +test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) +test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS) +endif # HAVE_CAIRO_FT +endif # HAVE_FREETYPE dist_check_SCRIPTS = \ check-c-linkage-decls.sh \ @@ -373,15 +366,11 @@ dist_check_SCRIPTS += \ endif check_PROGRAMS += \ - dump-fon \ dump-indic-data \ dump-khmer-data \ dump-myanmar-data \ dump-use-data \ $(NULL) -dump_fon_SOURCES = dump-fon.cc -dump_fon_CPPFLAGS = $(HBCFLAGS) -dump_fon_LDADD = libharfbuzz.la $(HBLIBS) dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc dump_indic_data_CPPFLAGS = $(HBCFLAGS) dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS) @@ -395,24 +384,23 @@ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc dump_use_data_CPPFLAGS = $(HBCFLAGS) dump_use_data_LDADD = libharfbuzz.la $(HBLIBS) -if HAVE_FREETYPE -if HAVE_CAIRO_FT -check_PROGRAMS += dump-emoji -dump_emoji_SOURCES = dump-emoji.cc -dump_emoji_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) -dump_emoji_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS) -endif # HAVE_CAIRO_FT -endif # HAVE_FREETYPE +COMPILED_TESTS = test-iter test-ot-tag test-unicode-ranges +COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG +COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS) +check_PROGRAMS += $(COMPILED_TESTS) +TESTS += $(COMPILED_TESTS) -check_PROGRAMS += test-ot-tag test-unicode-ranges -TESTS += test-ot-tag test-unicode-ranges +test_iter_SOURCES = test-iter.cc hb-static.cc +test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_iter_LDADD = $(COMPILED_TESTS_LDADD) test_ot_tag_SOURCES = hb-ot-tag.cc -test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN -test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD) test_unicode_ranges_SOURCES = test-unicode-ranges.cc -test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS) +test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD) TESTS_ENVIRONMENT = \ srcdir="$(srcdir)" \ @@ -438,6 +426,8 @@ HarfBuzz_0_0_gir_CFLAGS = \ -DHB_H_IN \ -DHB_OT_H \ -DHB_OT_H_IN \ + -DHB_AAT_H \ + -DHB_AAT_H_IN \ -DHB_GOBJECT_H \ -DHB_GOBJECT_H_IN \ -DHB_EXTERN= \ diff --git a/src/Makefile.in b/src/Makefile.in index e3715e8..beba71c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -95,86 +95,82 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -TESTS = $(am__EXEEXT_4) test-ot-tag$(EXEEXT) \ - test-unicode-ranges$(EXEEXT) -check_PROGRAMS = dump-fon$(EXEEXT) dump-indic-data$(EXEEXT) \ - dump-khmer-data$(EXEEXT) dump-myanmar-data$(EXEEXT) \ - dump-use-data$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ - test-ot-tag$(EXEEXT) test-unicode-ranges$(EXEEXT) -@HAVE_OT_TRUE@am__append_1 = $(HB_OT_sources) \ -@HAVE_OT_TRUE@ $(HB_OT_RAGEL_GENERATED_sources) -@HAVE_OT_TRUE@am__append_2 = $(HB_OT_headers) -@HAVE_FALLBACK_TRUE@am__append_3 = $(HB_FALLBACK_sources) -@HAVE_PTHREAD_TRUE@am__append_4 = $(PTHREAD_CFLAGS) -@HAVE_PTHREAD_TRUE@am__append_5 = $(PTHREAD_LIBS) -@HAVE_GLIB_TRUE@am__append_6 = $(GLIB_CFLAGS) -@HAVE_GLIB_TRUE@am__append_7 = $(GLIB_LIBS) -@HAVE_GLIB_TRUE@am__append_8 = $(GLIB_DEPS) -@HAVE_GLIB_TRUE@am__append_9 = $(HB_GLIB_sources) -@HAVE_GLIB_TRUE@am__append_10 = $(HB_GLIB_headers) -@HAVE_FREETYPE_TRUE@am__append_11 = $(FREETYPE_CFLAGS) -@HAVE_FREETYPE_TRUE@am__append_12 = $(FREETYPE_LIBS) +TESTS = $(am__EXEEXT_5) $(am__EXEEXT_2) +check_PROGRAMS = dump-indic-data$(EXEEXT) dump-khmer-data$(EXEEXT) \ + dump-myanmar-data$(EXEEXT) dump-use-data$(EXEEXT) \ + $(am__EXEEXT_1) $(am__EXEEXT_2) +@HAVE_FALLBACK_TRUE@am__append_1 = $(HB_FALLBACK_sources) +@HAVE_PTHREAD_TRUE@am__append_2 = $(PTHREAD_CFLAGS) +@HAVE_PTHREAD_TRUE@am__append_3 = $(PTHREAD_LIBS) +@HAVE_GLIB_TRUE@am__append_4 = $(GLIB_CFLAGS) +@HAVE_GLIB_TRUE@am__append_5 = $(GLIB_LIBS) +@HAVE_GLIB_TRUE@am__append_6 = $(GLIB_DEPS) +@HAVE_GLIB_TRUE@am__append_7 = $(HB_GLIB_sources) +@HAVE_GLIB_TRUE@am__append_8 = $(HB_GLIB_headers) +@HAVE_FREETYPE_TRUE@am__append_9 = $(FREETYPE_CFLAGS) +@HAVE_FREETYPE_TRUE@am__append_10 = $(FREETYPE_LIBS) # XXX # The following creates a recursive dependency on FreeType if FreeType is # built with HarfBuzz support enabled. Newer pkg-config handles that just # fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes. Remove # in a year or two, or otherwise work around it... #HBDEPS += $(FREETYPE_DEPS) -@HAVE_FREETYPE_TRUE@am__append_13 = $(HB_FT_sources) -@HAVE_FREETYPE_TRUE@am__append_14 = $(HB_FT_headers) -@HAVE_GRAPHITE2_TRUE@am__append_15 = $(GRAPHITE2_CFLAGS) -@HAVE_GRAPHITE2_TRUE@am__append_16 = $(GRAPHITE2_LIBS) -@HAVE_GRAPHITE2_TRUE@am__append_17 = $(GRAPHITE2_DEPS) -@HAVE_GRAPHITE2_TRUE@am__append_18 = $(HB_GRAPHITE2_sources) -@HAVE_GRAPHITE2_TRUE@am__append_19 = $(HB_GRAPHITE2_headers) -@HAVE_UNISCRIBE_TRUE@am__append_20 = $(UNISCRIBE_CFLAGS) -@HAVE_UNISCRIBE_TRUE@am__append_21 = $(UNISCRIBE_LIBS) -@HAVE_UNISCRIBE_TRUE@am__append_22 = $(HB_UNISCRIBE_sources) -@HAVE_UNISCRIBE_TRUE@am__append_23 = $(HB_UNISCRIBE_headers) -@HAVE_DIRECTWRITE_TRUE@am__append_24 = $(DIRECTWRITE_CXXFLAGS) -@HAVE_DIRECTWRITE_TRUE@am__append_25 = $(DIRECTWRITE_LIBS) -@HAVE_DIRECTWRITE_TRUE@am__append_26 = $(HB_DIRECTWRITE_sources) -@HAVE_DIRECTWRITE_TRUE@am__append_27 = $(HB_DIRECTWRITE_headers) -@HAVE_CORETEXT_TRUE@am__append_28 = $(CORETEXT_CFLAGS) -@HAVE_CORETEXT_TRUE@am__append_29 = $(CORETEXT_LIBS) -@HAVE_CORETEXT_TRUE@am__append_30 = $(HB_CORETEXT_sources) -@HAVE_CORETEXT_TRUE@am__append_31 = $(HB_CORETEXT_headers) -@HAVE_UCDN_TRUE@am__append_32 = hb-ucdn -@HAVE_UCDN_TRUE@am__append_33 = -I$(srcdir)/hb-ucdn -@HAVE_UCDN_TRUE@am__append_34 = hb-ucdn/libhb-ucdn.la -@HAVE_UCDN_TRUE@am__append_35 = $(HB_UCDN_sources) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_36 = $(ICU_CFLAGS) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_37 = $(ICU_LIBS) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_38 = $(HB_ICU_sources) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_39 = $(HB_ICU_headers) -@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_40 = libharfbuzz-icu.la -@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_41 = $(HB_ICU_headers) -@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_42 = harfbuzz-icu.pc -@HAVE_GOBJECT_TRUE@am__append_43 = libharfbuzz-gobject.la -@HAVE_GOBJECT_TRUE@am__append_44 = $(HB_GOBJECT_DIST_headers) -@HAVE_GOBJECT_TRUE@am__append_45 = $(HB_GOBJECT_NODIST_headers) -@HAVE_GOBJECT_TRUE@am__append_46 = harfbuzz-gobject.pc -@HAVE_GOBJECT_TRUE@am__append_47 = \ +@HAVE_FREETYPE_TRUE@am__append_11 = $(HB_FT_sources) +@HAVE_FREETYPE_TRUE@am__append_12 = $(HB_FT_headers) +@HAVE_GRAPHITE2_TRUE@am__append_13 = $(GRAPHITE2_CFLAGS) +@HAVE_GRAPHITE2_TRUE@am__append_14 = $(GRAPHITE2_LIBS) +@HAVE_GRAPHITE2_TRUE@am__append_15 = $(GRAPHITE2_DEPS) +@HAVE_GRAPHITE2_TRUE@am__append_16 = $(HB_GRAPHITE2_sources) +@HAVE_GRAPHITE2_TRUE@am__append_17 = $(HB_GRAPHITE2_headers) +@HAVE_UNISCRIBE_TRUE@am__append_18 = $(UNISCRIBE_CFLAGS) +@HAVE_UNISCRIBE_TRUE@am__append_19 = $(UNISCRIBE_LIBS) +@HAVE_UNISCRIBE_TRUE@am__append_20 = $(HB_UNISCRIBE_sources) +@HAVE_UNISCRIBE_TRUE@am__append_21 = $(HB_UNISCRIBE_headers) +@HAVE_DIRECTWRITE_TRUE@am__append_22 = $(DIRECTWRITE_CXXFLAGS) +@HAVE_DIRECTWRITE_TRUE@am__append_23 = $(DIRECTWRITE_LIBS) +@HAVE_DIRECTWRITE_TRUE@am__append_24 = $(HB_DIRECTWRITE_sources) +@HAVE_DIRECTWRITE_TRUE@am__append_25 = $(HB_DIRECTWRITE_headers) +@HAVE_CORETEXT_TRUE@am__append_26 = $(CORETEXT_CFLAGS) +@HAVE_CORETEXT_TRUE@am__append_27 = $(CORETEXT_LIBS) +@HAVE_CORETEXT_TRUE@am__append_28 = $(HB_CORETEXT_sources) +@HAVE_CORETEXT_TRUE@am__append_29 = $(HB_CORETEXT_headers) +@HAVE_UCDN_TRUE@am__append_30 = hb-ucdn +@HAVE_UCDN_TRUE@am__append_31 = -I$(srcdir)/hb-ucdn +@HAVE_UCDN_TRUE@am__append_32 = hb-ucdn/libhb-ucdn.la +@HAVE_UCDN_TRUE@am__append_33 = $(HB_UCDN_sources) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_34 = $(ICU_CFLAGS) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_35 = $(ICU_LIBS) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_36 = $(HB_ICU_sources) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_37 = $(HB_ICU_headers) +@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_38 = libharfbuzz-icu.la +@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_39 = $(HB_ICU_headers) +@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_40 = harfbuzz-icu.pc +@HAVE_GOBJECT_TRUE@am__append_41 = libharfbuzz-gobject.la +@HAVE_GOBJECT_TRUE@am__append_42 = $(HB_GOBJECT_DIST_headers) +@HAVE_GOBJECT_TRUE@am__append_43 = $(HB_GOBJECT_NODIST_headers) +@HAVE_GOBJECT_TRUE@am__append_44 = harfbuzz-gobject.pc +@HAVE_GOBJECT_TRUE@am__append_45 = \ @HAVE_GOBJECT_TRUE@ $(HB_GOBJECT_ENUM_sources) \ @HAVE_GOBJECT_TRUE@ $(HB_GOBJECT_ENUM_headers) \ @HAVE_GOBJECT_TRUE@ $(NULL) -@HAVE_GOBJECT_TRUE@am__append_48 = \ +@HAVE_GOBJECT_TRUE@am__append_46 = \ @HAVE_GOBJECT_TRUE@ $(HB_GOBJECT_ENUM_sources) \ @HAVE_GOBJECT_TRUE@ $(HB_GOBJECT_ENUM_headers) \ @HAVE_GOBJECT_TRUE@ $(NULL) -@HAVE_GOBJECT_TRUE@am__append_49 = harfbuzz-gobject.def +@HAVE_GOBJECT_TRUE@am__append_47 = harfbuzz-gobject.def noinst_PROGRAMS = main$(EXEEXT) test$(EXEEXT) \ - test-buffer-serialize$(EXEEXT) test-size-params$(EXEEXT) \ - test-would-substitute$(EXEEXT) $(am__EXEEXT_1) + test-buffer-serialize$(EXEEXT) test-name-table$(EXEEXT) \ + test-size-params$(EXEEXT) test-would-substitute$(EXEEXT) \ + $(am__EXEEXT_1) $(am__EXEEXT_3) bin_PROGRAMS = -@WITH_LIBSTDCXX_FALSE@am__append_50 = \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am__append_48 = test-ot-color +@WITH_LIBSTDCXX_FALSE@am__append_49 = \ @WITH_LIBSTDCXX_FALSE@ check-libstdc++.sh \ @WITH_LIBSTDCXX_FALSE@ $(NULL) -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am__append_51 = dump-emoji -@HAVE_INTROSPECTION_TRUE@am__append_52 = $(gir_DATA) $(typelib_DATA) +@HAVE_INTROSPECTION_TRUE@am__append_50 = $(gir_DATA) $(typelib_DATA) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.m4 \ @@ -182,8 +178,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.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 + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_check_SCRIPTS_DIST) \ @@ -225,177 +220,16 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkgincludedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = -@HAVE_GLIB_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) -@HAVE_FREETYPE_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) -@HAVE_GRAPHITE2_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) -@HAVE_PTHREAD_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) -@HAVE_UNISCRIBE_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) -@HAVE_DIRECTWRITE_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1) -@HAVE_CORETEXT_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1) -am__DEPENDENCIES_9 = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \ - $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__DEPENDENCIES_10 = \ -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__DEPENDENCIES_1) -am__DEPENDENCIES_11 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ - $(am__DEPENDENCIES_4) $(am__append_34) $(am__DEPENDENCIES_9) \ - $(am__DEPENDENCIES_10) -am__DEPENDENCIES_12 = $(am__DEPENDENCIES_11) -libharfbuzz_fuzzing_la_DEPENDENCIES = $(am__DEPENDENCIES_12) -am__libharfbuzz_fuzzing_la_SOURCES_DIST = hb-atomic-private.hh \ - hb-blob-private.hh hb-blob.cc hb-buffer-private.hh \ - hb-buffer-serialize.cc hb-buffer.cc hb-common.cc hb-debug.hh \ - hb-dsalgs.hh hb-face-private.hh hb-face.cc hb-font-private.hh \ - hb-font.cc hb-map-private.hh hb-map.cc hb-mutex-private.hh \ - hb-object-private.hh hb-open-file-private.hh \ - hb-open-type-private.hh hb-ot-color-cbdt-table.hh \ - hb-ot-cmap-table.hh hb-ot-glyf-table.hh hb-ot-hdmx-table.hh \ - hb-ot-head-table.hh hb-ot-hhea-table.hh hb-ot-hmtx-table.hh \ - hb-ot-kern-table.hh hb-ot-maxp-table.hh hb-ot-name-table.hh \ - hb-ot-os2-table.hh hb-ot-os2-unicode-ranges.hh \ - hb-ot-post-macroman.hh hb-ot-post-table.hh hb-ot-tag.cc \ - hb-private.hh hb-set-digest-private.hh hb-set-private.hh \ - hb-set.cc hb-shape.cc hb-shape-plan-private.hh \ - hb-shape-plan.cc hb-shaper-list.hh hb-shaper-impl-private.hh \ - hb-shaper-private.hh hb-shaper.cc hb-static.cc \ - hb-string-array.hh hb-unicode-private.hh hb-unicode.cc \ - hb-utf-private.hh hb-warning.cc hb-buffer-deserialize-json.hh \ - hb-buffer-deserialize-text.hh hb-aat-layout.cc \ - hb-aat-layout-common-private.hh hb-aat-layout-ankr-table.hh \ - hb-aat-layout-bsln-table.hh hb-aat-layout-feat-table.hh \ - hb-aat-layout-kerx-table.hh hb-aat-layout-morx-table.hh \ - hb-aat-layout-trak-table.hh hb-aat-layout-private.hh \ - hb-aat-fmtx-table.hh hb-aat-gcid-table.hh hb-aat-ltag-table.hh \ - hb-ot-font.cc hb-ot-layout.cc hb-ot-layout-base-table.hh \ - hb-ot-layout-common-private.hh hb-ot-layout-gdef-table.hh \ - hb-ot-layout-gpos-table.hh hb-ot-layout-gsubgpos-private.hh \ - hb-ot-layout-gsub-table.hh hb-ot-layout-jstf-table.hh \ - hb-ot-layout-private.hh hb-ot-color.cc \ - hb-ot-color-colr-table.hh hb-ot-color-cpal-table.hh \ - hb-ot-color-sbix-table.hh hb-ot-color-svg-table.hh \ - hb-ot-map.cc hb-ot-map-private.hh hb-ot-math.cc \ - hb-ot-math-table.hh hb-ot-shape.cc \ - hb-ot-shape-complex-arabic.cc \ - hb-ot-shape-complex-arabic-fallback.hh \ - hb-ot-shape-complex-arabic-private.hh \ - hb-ot-shape-complex-arabic-table.hh \ - hb-ot-shape-complex-arabic-win1256.hh \ - hb-ot-shape-complex-default.cc hb-ot-shape-complex-hangul.cc \ - hb-ot-shape-complex-hebrew.cc hb-ot-shape-complex-indic.cc \ - hb-ot-shape-complex-indic-private.hh \ - hb-ot-shape-complex-indic-table.cc \ - hb-ot-shape-complex-khmer-private.hh \ - hb-ot-shape-complex-khmer.cc \ - hb-ot-shape-complex-myanmar-private.hh \ - hb-ot-shape-complex-myanmar.cc hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-tibetan.cc hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use-private.hh \ - hb-ot-shape-complex-use-table.cc \ - hb-ot-shape-complex-private.hh \ - hb-ot-shape-normalize-private.hh hb-ot-shape-normalize.cc \ - hb-ot-shape-fallback-private.hh hb-ot-shape-fallback.cc \ - hb-ot-shape-private.hh hb-ot-var.cc hb-ot-var-avar-table.hh \ - hb-ot-var-fvar-table.hh hb-ot-var-hvar-table.hh \ - hb-ot-var-mvar-table.hh hb-ot-shape-complex-indic-machine.hh \ - hb-ot-shape-complex-khmer-machine.hh \ - hb-ot-shape-complex-myanmar-machine.hh \ - hb-ot-shape-complex-use-machine.hh hb-fallback-shape.cc \ - hb-glib.cc hb-ft.cc hb-graphite2.cc hb-uniscribe.cc \ - hb-directwrite.cc hb-coretext.cc hb-ucdn.cc hb-icu.cc hb.h \ - hb-blob.h hb-buffer.h hb-common.h hb-deprecated.h hb-face.h \ - hb-font.h hb-map.h hb-set.h hb-shape.h hb-shape-plan.h \ - hb-unicode.h hb-version.h hb-ot.h hb-ot-font.h hb-ot-layout.h \ - hb-ot-math.h hb-ot-shape.h hb-ot-tag.h hb-ot-var.h hb-glib.h \ - hb-ft.h hb-graphite2.h hb-uniscribe.h hb-directwrite.h \ - hb-coretext.h hb-icu.h -am__objects_1 = -am__objects_2 = libharfbuzz_fuzzing_la-hb-blob.lo \ - libharfbuzz_fuzzing_la-hb-buffer-serialize.lo \ - libharfbuzz_fuzzing_la-hb-buffer.lo \ - libharfbuzz_fuzzing_la-hb-common.lo \ - libharfbuzz_fuzzing_la-hb-face.lo \ - libharfbuzz_fuzzing_la-hb-font.lo \ - libharfbuzz_fuzzing_la-hb-map.lo \ - libharfbuzz_fuzzing_la-hb-ot-tag.lo \ - libharfbuzz_fuzzing_la-hb-set.lo \ - libharfbuzz_fuzzing_la-hb-shape.lo \ - libharfbuzz_fuzzing_la-hb-shape-plan.lo \ - libharfbuzz_fuzzing_la-hb-shaper.lo \ - libharfbuzz_fuzzing_la-hb-static.lo \ - libharfbuzz_fuzzing_la-hb-unicode.lo \ - libharfbuzz_fuzzing_la-hb-warning.lo $(am__objects_1) -am__objects_3 = $(am__objects_1) -am__objects_4 = libharfbuzz_fuzzing_la-hb-aat-layout.lo \ - libharfbuzz_fuzzing_la-hb-ot-font.lo \ - libharfbuzz_fuzzing_la-hb-ot-layout.lo \ - libharfbuzz_fuzzing_la-hb-ot-color.lo \ - libharfbuzz_fuzzing_la-hb-ot-map.lo \ - libharfbuzz_fuzzing_la-hb-ot-math.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo \ - libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo \ - libharfbuzz_fuzzing_la-hb-ot-var.lo $(am__objects_1) -@HAVE_OT_TRUE@am__objects_5 = $(am__objects_4) $(am__objects_3) -am__objects_6 = libharfbuzz_fuzzing_la-hb-fallback-shape.lo \ - $(am__objects_1) -@HAVE_FALLBACK_TRUE@am__objects_7 = $(am__objects_6) -am__objects_8 = libharfbuzz_fuzzing_la-hb-glib.lo -@HAVE_GLIB_TRUE@am__objects_9 = $(am__objects_8) -am__objects_10 = libharfbuzz_fuzzing_la-hb-ft.lo -@HAVE_FREETYPE_TRUE@am__objects_11 = $(am__objects_10) -am__objects_12 = libharfbuzz_fuzzing_la-hb-graphite2.lo -@HAVE_GRAPHITE2_TRUE@am__objects_13 = $(am__objects_12) -am__objects_14 = libharfbuzz_fuzzing_la-hb-uniscribe.lo -@HAVE_UNISCRIBE_TRUE@am__objects_15 = $(am__objects_14) -am__objects_16 = libharfbuzz_fuzzing_la-hb-directwrite.lo -@HAVE_DIRECTWRITE_TRUE@am__objects_17 = $(am__objects_16) -am__objects_18 = libharfbuzz_fuzzing_la-hb-coretext.lo -@HAVE_CORETEXT_TRUE@am__objects_19 = $(am__objects_18) -am__objects_20 = libharfbuzz_fuzzing_la-hb-ucdn.lo -@HAVE_UCDN_TRUE@am__objects_21 = $(am__objects_20) -am__objects_22 = libharfbuzz_fuzzing_la-hb-icu.lo -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_23 = \ -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_22) -am__objects_24 = $(am__objects_2) $(am__objects_3) $(am__objects_5) \ - $(am__objects_7) $(am__objects_9) $(am__objects_11) \ - $(am__objects_13) $(am__objects_15) $(am__objects_17) \ - $(am__objects_19) $(am__objects_21) $(am__objects_23) -@HAVE_OT_TRUE@am__objects_25 = $(am__objects_3) -@HAVE_GLIB_TRUE@am__objects_26 = $(am__objects_1) -@HAVE_FREETYPE_TRUE@am__objects_27 = $(am__objects_1) -@HAVE_GRAPHITE2_TRUE@am__objects_28 = $(am__objects_1) -@HAVE_UNISCRIBE_TRUE@am__objects_29 = $(am__objects_1) -@HAVE_DIRECTWRITE_TRUE@am__objects_30 = $(am__objects_1) -@HAVE_CORETEXT_TRUE@am__objects_31 = $(am__objects_1) -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_32 = \ -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_1) -am__objects_33 = $(am__objects_3) $(am__objects_25) $(am__objects_26) \ - $(am__objects_27) $(am__objects_28) $(am__objects_29) \ - $(am__objects_30) $(am__objects_31) $(am__objects_32) -am__objects_34 = $(am__objects_24) $(am__objects_33) -am_libharfbuzz_fuzzing_la_OBJECTS = $(am__objects_34) -libharfbuzz_fuzzing_la_OBJECTS = $(am_libharfbuzz_fuzzing_la_OBJECTS) @HAVE_GOBJECT_TRUE@libharfbuzz_gobject_la_DEPENDENCIES = \ @HAVE_GOBJECT_TRUE@ $(am__DEPENDENCIES_1) libharfbuzz.la am__libharfbuzz_gobject_la_SOURCES_DIST = hb-gobject-structs.cc -am__objects_35 = libharfbuzz_gobject_la-hb-gobject-structs.lo +am__objects_1 = libharfbuzz_gobject_la-hb-gobject-structs.lo @HAVE_GOBJECT_TRUE@am_libharfbuzz_gobject_la_OBJECTS = \ -@HAVE_GOBJECT_TRUE@ $(am__objects_35) -am__objects_36 = libharfbuzz_gobject_la-hb-gobject-enums.lo -am__objects_37 = $(am__objects_36) +@HAVE_GOBJECT_TRUE@ $(am__objects_1) +am__objects_2 = libharfbuzz_gobject_la-hb-gobject-enums.lo +am__objects_3 = $(am__objects_2) @HAVE_GOBJECT_TRUE@nodist_libharfbuzz_gobject_la_OBJECTS = \ -@HAVE_GOBJECT_TRUE@ $(am__objects_37) +@HAVE_GOBJECT_TRUE@ $(am__objects_3) libharfbuzz_gobject_la_OBJECTS = $(am_libharfbuzz_gobject_la_OBJECTS) \ $(nodist_libharfbuzz_gobject_la_OBJECTS) @HAVE_GOBJECT_TRUE@am_libharfbuzz_gobject_la_rpath = -rpath $(libdir) @@ -403,9 +237,9 @@ libharfbuzz_gobject_la_OBJECTS = $(am_libharfbuzz_gobject_la_OBJECTS) \ @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@ $(am__DEPENDENCIES_1) \ @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@ libharfbuzz.la am__libharfbuzz_icu_la_SOURCES_DIST = hb-icu.cc -am__objects_38 = libharfbuzz_icu_la-hb-icu.lo +am__objects_4 = libharfbuzz_icu_la-hb-icu.lo @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am_libharfbuzz_icu_la_OBJECTS = \ -@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@ $(am__objects_38) +@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@ $(am__objects_4) libharfbuzz_icu_la_OBJECTS = $(am_libharfbuzz_icu_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -417,167 +251,184 @@ libharfbuzz_icu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(LDFLAGS) -o $@ @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am_libharfbuzz_icu_la_rpath = \ @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@ -rpath $(libdir) -libharfbuzz_subset_fuzzing_la_DEPENDENCIES = \ - $(libharfbuzz_subset_la_LIBADD) -am__objects_39 = libharfbuzz_subset_fuzzing_la-hb-static.lo \ - libharfbuzz_subset_fuzzing_la-hb-subset.lo \ - libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo \ - libharfbuzz_subset_fuzzing_la-hb-subset-input.lo \ - libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo \ - $(am__objects_1) -am__objects_40 = $(am__objects_39) -am_libharfbuzz_subset_fuzzing_la_OBJECTS = $(am__objects_40) -libharfbuzz_subset_fuzzing_la_OBJECTS = \ - $(am_libharfbuzz_subset_fuzzing_la_OBJECTS) libharfbuzz_subset_la_DEPENDENCIES = libharfbuzz.la -am__objects_41 = libharfbuzz_subset_la-hb-static.lo \ - libharfbuzz_subset_la-hb-subset.lo \ +am__objects_5 = +am__objects_6 = libharfbuzz_subset_la-hb-ot-cff1-table.lo \ + libharfbuzz_subset_la-hb-ot-cff2-table.lo \ + libharfbuzz_subset_la-hb-static.lo \ + libharfbuzz_subset_la-hb-subset-cff-common.lo \ + libharfbuzz_subset_la-hb-subset-cff1.lo \ + libharfbuzz_subset_la-hb-subset-cff2.lo \ libharfbuzz_subset_la-hb-subset-glyf.lo \ libharfbuzz_subset_la-hb-subset-input.lo \ - libharfbuzz_subset_la-hb-subset-plan.lo $(am__objects_1) -am_libharfbuzz_subset_la_OBJECTS = $(am__objects_41) + libharfbuzz_subset_la-hb-subset-plan.lo \ + libharfbuzz_subset_la-hb-subset.lo $(am__objects_5) +am_libharfbuzz_subset_la_OBJECTS = $(am__objects_6) libharfbuzz_subset_la_OBJECTS = $(am_libharfbuzz_subset_la_OBJECTS) libharfbuzz_subset_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libharfbuzz_subset_la_LDFLAGS) \ $(LDFLAGS) -o $@ +@HAVE_GLIB_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +@HAVE_FREETYPE_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) +@HAVE_GRAPHITE2_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) +@HAVE_PTHREAD_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) +@HAVE_UNISCRIBE_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) +@HAVE_DIRECTWRITE_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1) +@HAVE_CORETEXT_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1) +am__DEPENDENCIES_9 = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \ + $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__DEPENDENCIES_10 = \ +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__DEPENDENCIES_1) +am__DEPENDENCIES_11 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ + $(am__DEPENDENCIES_4) $(am__append_32) $(am__DEPENDENCIES_9) \ + $(am__DEPENDENCIES_10) libharfbuzz_la_DEPENDENCIES = $(am__DEPENDENCIES_11) -am__libharfbuzz_la_SOURCES_DIST = hb-atomic-private.hh \ - hb-blob-private.hh hb-blob.cc hb-buffer-private.hh \ - hb-buffer-serialize.cc hb-buffer.cc hb-common.cc hb-debug.hh \ - hb-dsalgs.hh hb-face-private.hh hb-face.cc hb-font-private.hh \ - hb-font.cc hb-map-private.hh hb-map.cc hb-mutex-private.hh \ - hb-object-private.hh hb-open-file-private.hh \ - hb-open-type-private.hh hb-ot-color-cbdt-table.hh \ - hb-ot-cmap-table.hh hb-ot-glyf-table.hh hb-ot-hdmx-table.hh \ - hb-ot-head-table.hh hb-ot-hhea-table.hh hb-ot-hmtx-table.hh \ - hb-ot-kern-table.hh hb-ot-maxp-table.hh hb-ot-name-table.hh \ - hb-ot-os2-table.hh hb-ot-os2-unicode-ranges.hh \ - hb-ot-post-macroman.hh hb-ot-post-table.hh hb-ot-tag.cc \ - hb-private.hh hb-set-digest-private.hh hb-set-private.hh \ - hb-set.cc hb-shape.cc hb-shape-plan-private.hh \ - hb-shape-plan.cc hb-shaper-list.hh hb-shaper-impl-private.hh \ - hb-shaper-private.hh hb-shaper.cc hb-static.cc \ - hb-string-array.hh hb-unicode-private.hh hb-unicode.cc \ - hb-utf-private.hh hb-warning.cc hb-buffer-deserialize-json.hh \ - hb-buffer-deserialize-text.hh hb-aat-layout.cc \ - hb-aat-layout-common-private.hh hb-aat-layout-ankr-table.hh \ - hb-aat-layout-bsln-table.hh hb-aat-layout-feat-table.hh \ - hb-aat-layout-kerx-table.hh hb-aat-layout-morx-table.hh \ - hb-aat-layout-trak-table.hh hb-aat-layout-private.hh \ - hb-aat-fmtx-table.hh hb-aat-gcid-table.hh hb-aat-ltag-table.hh \ - hb-ot-font.cc hb-ot-layout.cc hb-ot-layout-base-table.hh \ - hb-ot-layout-common-private.hh hb-ot-layout-gdef-table.hh \ - hb-ot-layout-gpos-table.hh hb-ot-layout-gsubgpos-private.hh \ - hb-ot-layout-gsub-table.hh hb-ot-layout-jstf-table.hh \ - hb-ot-layout-private.hh hb-ot-color.cc \ +am__libharfbuzz_la_SOURCES_DIST = hb-aat-fdsc-table.hh \ + hb-aat-layout-ankr-table.hh hb-aat-layout-bsln-table.hh \ + hb-aat-layout-common.hh hb-aat-layout-feat-table.hh \ + hb-aat-layout-just-table.hh hb-aat-layout-kerx-table.hh \ + hb-aat-layout-lcar-table.hh hb-aat-layout-morx-table.hh \ + hb-aat-layout-trak-table.hh hb-aat-layout.cc hb-aat-layout.hh \ + hb-aat-ltag-table.hh hb-aat-map.cc hb-aat-map.hh hb-array.hh \ + hb-atomic.hh hb-blob.cc hb-blob.hh hb-buffer-serialize.cc \ + hb-buffer.cc hb-buffer.hh hb-cache.hh hb-cff-interp-common.hh \ + hb-cff-interp-cs-common.hh hb-cff-interp-dict-common.hh \ + hb-cff1-interp-cs.hh hb-cff2-interp-cs.hh hb-common.cc \ + hb-debug.hh hb-dsalgs.hh hb-face.cc hb-face.hh hb-font.cc \ + hb-font.hh hb-iter.hh hb-kern.hh hb-machinery.hh hb-map.cc \ + hb-map.hh hb-mutex.hh hb-null.hh hb-object.hh hb-open-file.hh \ + hb-open-type.hh hb-ot-cff-common.hh hb-ot-cff1-table.cc \ + hb-ot-cff1-table.hh hb-ot-cff2-table.cc hb-ot-cff2-table.hh \ + hb-ot-cmap-table.hh hb-ot-color-cbdt-table.hh \ hb-ot-color-colr-table.hh hb-ot-color-cpal-table.hh \ hb-ot-color-sbix-table.hh hb-ot-color-svg-table.hh \ - hb-ot-map.cc hb-ot-map-private.hh hb-ot-math.cc \ - hb-ot-math-table.hh hb-ot-shape.cc \ - hb-ot-shape-complex-arabic.cc \ - hb-ot-shape-complex-arabic-fallback.hh \ - hb-ot-shape-complex-arabic-private.hh \ + hb-ot-color.cc hb-ot-face.cc hb-ot-face.hh hb-ot-font.cc \ + hb-ot-gasp-table.hh hb-ot-glyf-table.hh hb-ot-hdmx-table.hh \ + hb-ot-head-table.hh hb-ot-hhea-table.hh hb-ot-hmtx-table.hh \ + hb-ot-kern-table.hh hb-ot-layout-base-table.hh \ + hb-ot-layout-common.hh hb-ot-layout-gdef-table.hh \ + hb-ot-layout-gpos-table.hh hb-ot-layout-gsub-table.hh \ + hb-ot-layout-gsubgpos.hh hb-ot-layout-jstf-table.hh \ + hb-ot-layout.cc hb-ot-layout.hh hb-ot-map.cc hb-ot-map.hh \ + hb-ot-math-table.hh hb-ot-math.cc hb-ot-maxp-table.hh \ + hb-ot-name-language.cc hb-ot-name-language.hh \ + hb-ot-name-table.hh hb-ot-name.cc hb-ot-os2-table.hh \ + hb-ot-os2-unicode-ranges.hh hb-ot-post-macroman.hh \ + hb-ot-post-table.hh hb-ot-shape-complex-arabic-fallback.hh \ hb-ot-shape-complex-arabic-table.hh \ hb-ot-shape-complex-arabic-win1256.hh \ + hb-ot-shape-complex-arabic.cc hb-ot-shape-complex-arabic.hh \ hb-ot-shape-complex-default.cc hb-ot-shape-complex-hangul.cc \ - hb-ot-shape-complex-hebrew.cc hb-ot-shape-complex-indic.cc \ - hb-ot-shape-complex-indic-private.hh \ + hb-ot-shape-complex-hebrew.cc \ hb-ot-shape-complex-indic-table.cc \ - hb-ot-shape-complex-khmer-private.hh \ - hb-ot-shape-complex-khmer.cc \ - hb-ot-shape-complex-myanmar-private.hh \ - hb-ot-shape-complex-myanmar.cc hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-tibetan.cc hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use-private.hh \ - hb-ot-shape-complex-use-table.cc \ - hb-ot-shape-complex-private.hh \ - hb-ot-shape-normalize-private.hh hb-ot-shape-normalize.cc \ - hb-ot-shape-fallback-private.hh hb-ot-shape-fallback.cc \ - hb-ot-shape-private.hh hb-ot-var.cc hb-ot-var-avar-table.hh \ - hb-ot-var-fvar-table.hh hb-ot-var-hvar-table.hh \ - hb-ot-var-mvar-table.hh hb-ot-shape-complex-indic-machine.hh \ + hb-ot-shape-complex-indic.cc hb-ot-shape-complex-indic.hh \ + hb-ot-shape-complex-khmer.cc hb-ot-shape-complex-khmer.hh \ + hb-ot-shape-complex-myanmar.cc hb-ot-shape-complex-myanmar.hh \ + hb-ot-shape-complex-thai.cc hb-ot-shape-complex-use-table.cc \ + hb-ot-shape-complex-use.cc hb-ot-shape-complex-use.hh \ + hb-ot-shape-complex-vowel-constraints.cc \ + hb-ot-shape-complex-vowel-constraints.hh \ + hb-ot-shape-complex.hh hb-ot-shape-fallback.cc \ + hb-ot-shape-fallback.hh hb-ot-shape-normalize.cc \ + hb-ot-shape-normalize.hh hb-ot-shape.cc hb-ot-shape.hh \ + hb-ot-stat-table.hh hb-ot-tag-table.hh hb-ot-tag.cc \ + hb-ot-var-avar-table.hh hb-ot-var-fvar-table.hh \ + hb-ot-var-hvar-table.hh hb-ot-var-mvar-table.hh hb-ot-var.cc \ + hb-ot-vorg-table.hh hb-set-digest.hh hb-set.cc hb-set.hh \ + hb-shape-plan.cc hb-shape-plan.hh hb-shape.cc \ + hb-shaper-impl.hh hb-shaper-list.hh hb-shaper.cc hb-shaper.hh \ + hb-static.cc hb-string-array.hh hb-unicode-emoji-table.hh \ + hb-unicode.cc hb-unicode.hh hb-utf.hh hb-vector.hh \ + hb-warning.cc hb.hh hb-buffer-deserialize-json.hh \ + hb-buffer-deserialize-text.hh \ + hb-ot-shape-complex-indic-machine.hh \ hb-ot-shape-complex-khmer-machine.hh \ hb-ot-shape-complex-myanmar-machine.hh \ hb-ot-shape-complex-use-machine.hh hb-fallback-shape.cc \ hb-glib.cc hb-ft.cc hb-graphite2.cc hb-uniscribe.cc \ - hb-directwrite.cc hb-coretext.cc hb-ucdn.cc hb-icu.cc hb.h \ - hb-blob.h hb-buffer.h hb-common.h hb-deprecated.h hb-face.h \ - hb-font.h hb-map.h hb-set.h hb-shape.h hb-shape-plan.h \ - hb-unicode.h hb-version.h hb-ot.h hb-ot-font.h hb-ot-layout.h \ - hb-ot-math.h hb-ot-shape.h hb-ot-tag.h hb-ot-var.h hb-glib.h \ - hb-ft.h hb-graphite2.h hb-uniscribe.h hb-directwrite.h \ - hb-coretext.h hb-icu.h -am__objects_42 = libharfbuzz_la-hb-blob.lo \ + hb-directwrite.cc hb-coretext.cc hb-ucdn.cc hb-icu.cc \ + hb-aat-layout.h hb-aat.h hb-blob.h hb-buffer.h hb-common.h \ + hb-deprecated.h hb-face.h hb-font.h hb-map.h hb-ot-color.h \ + hb-ot-deprecated.h hb-ot-font.h hb-ot-layout.h hb-ot-math.h \ + hb-ot-name.h hb-ot-shape.h hb-ot-var.h hb-ot.h hb-set.h \ + hb-shape-plan.h hb-shape.h hb-unicode.h hb-version.h hb.h \ + hb-glib.h hb-ft.h hb-graphite2.h hb-uniscribe.h \ + hb-directwrite.h hb-coretext.h hb-icu.h +am__objects_7 = libharfbuzz_la-hb-aat-layout.lo \ + libharfbuzz_la-hb-aat-map.lo libharfbuzz_la-hb-blob.lo \ libharfbuzz_la-hb-buffer-serialize.lo \ libharfbuzz_la-hb-buffer.lo libharfbuzz_la-hb-common.lo \ libharfbuzz_la-hb-face.lo libharfbuzz_la-hb-font.lo \ - libharfbuzz_la-hb-map.lo libharfbuzz_la-hb-ot-tag.lo \ - libharfbuzz_la-hb-set.lo libharfbuzz_la-hb-shape.lo \ - libharfbuzz_la-hb-shape-plan.lo libharfbuzz_la-hb-shaper.lo \ - libharfbuzz_la-hb-static.lo libharfbuzz_la-hb-unicode.lo \ - libharfbuzz_la-hb-warning.lo $(am__objects_1) -am__objects_43 = libharfbuzz_la-hb-aat-layout.lo \ + libharfbuzz_la-hb-map.lo libharfbuzz_la-hb-ot-cff1-table.lo \ + libharfbuzz_la-hb-ot-cff2-table.lo \ + libharfbuzz_la-hb-ot-color.lo libharfbuzz_la-hb-ot-face.lo \ libharfbuzz_la-hb-ot-font.lo libharfbuzz_la-hb-ot-layout.lo \ - libharfbuzz_la-hb-ot-color.lo libharfbuzz_la-hb-ot-map.lo \ - libharfbuzz_la-hb-ot-math.lo libharfbuzz_la-hb-ot-shape.lo \ + libharfbuzz_la-hb-ot-map.lo libharfbuzz_la-hb-ot-math.lo \ + libharfbuzz_la-hb-ot-name-language.lo \ + libharfbuzz_la-hb-ot-name.lo \ libharfbuzz_la-hb-ot-shape-complex-arabic.lo \ libharfbuzz_la-hb-ot-shape-complex-default.lo \ libharfbuzz_la-hb-ot-shape-complex-hangul.lo \ libharfbuzz_la-hb-ot-shape-complex-hebrew.lo \ - libharfbuzz_la-hb-ot-shape-complex-indic.lo \ libharfbuzz_la-hb-ot-shape-complex-indic-table.lo \ + libharfbuzz_la-hb-ot-shape-complex-indic.lo \ libharfbuzz_la-hb-ot-shape-complex-khmer.lo \ libharfbuzz_la-hb-ot-shape-complex-myanmar.lo \ libharfbuzz_la-hb-ot-shape-complex-thai.lo \ - libharfbuzz_la-hb-ot-shape-complex-tibetan.lo \ - libharfbuzz_la-hb-ot-shape-complex-use.lo \ libharfbuzz_la-hb-ot-shape-complex-use-table.lo \ - libharfbuzz_la-hb-ot-shape-normalize.lo \ + libharfbuzz_la-hb-ot-shape-complex-use.lo \ + libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo \ libharfbuzz_la-hb-ot-shape-fallback.lo \ - libharfbuzz_la-hb-ot-var.lo $(am__objects_1) -@HAVE_OT_TRUE@am__objects_44 = $(am__objects_43) $(am__objects_3) -am__objects_45 = libharfbuzz_la-hb-fallback-shape.lo $(am__objects_1) -@HAVE_FALLBACK_TRUE@am__objects_46 = $(am__objects_45) -am__objects_47 = libharfbuzz_la-hb-glib.lo -@HAVE_GLIB_TRUE@am__objects_48 = $(am__objects_47) -am__objects_49 = libharfbuzz_la-hb-ft.lo -@HAVE_FREETYPE_TRUE@am__objects_50 = $(am__objects_49) -am__objects_51 = libharfbuzz_la-hb-graphite2.lo -@HAVE_GRAPHITE2_TRUE@am__objects_52 = $(am__objects_51) -am__objects_53 = libharfbuzz_la-hb-uniscribe.lo -@HAVE_UNISCRIBE_TRUE@am__objects_54 = $(am__objects_53) -am__objects_55 = libharfbuzz_la-hb-directwrite.lo -@HAVE_DIRECTWRITE_TRUE@am__objects_56 = $(am__objects_55) -am__objects_57 = libharfbuzz_la-hb-coretext.lo -@HAVE_CORETEXT_TRUE@am__objects_58 = $(am__objects_57) -am__objects_59 = libharfbuzz_la-hb-ucdn.lo -@HAVE_UCDN_TRUE@am__objects_60 = $(am__objects_59) -am__objects_61 = libharfbuzz_la-hb-icu.lo -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_62 = \ -@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_61) -am__objects_63 = $(am__objects_42) $(am__objects_3) $(am__objects_44) \ - $(am__objects_46) $(am__objects_48) $(am__objects_50) \ - $(am__objects_52) $(am__objects_54) $(am__objects_56) \ - $(am__objects_58) $(am__objects_60) $(am__objects_62) -am_libharfbuzz_la_OBJECTS = $(am__objects_63) $(am__objects_33) + libharfbuzz_la-hb-ot-shape-normalize.lo \ + libharfbuzz_la-hb-ot-shape.lo libharfbuzz_la-hb-ot-tag.lo \ + libharfbuzz_la-hb-ot-var.lo libharfbuzz_la-hb-set.lo \ + libharfbuzz_la-hb-shape-plan.lo libharfbuzz_la-hb-shape.lo \ + libharfbuzz_la-hb-shaper.lo libharfbuzz_la-hb-static.lo \ + libharfbuzz_la-hb-unicode.lo libharfbuzz_la-hb-warning.lo \ + $(am__objects_5) +am__objects_8 = $(am__objects_5) +am__objects_9 = libharfbuzz_la-hb-fallback-shape.lo $(am__objects_5) +@HAVE_FALLBACK_TRUE@am__objects_10 = $(am__objects_9) +am__objects_11 = libharfbuzz_la-hb-glib.lo +@HAVE_GLIB_TRUE@am__objects_12 = $(am__objects_11) +am__objects_13 = libharfbuzz_la-hb-ft.lo +@HAVE_FREETYPE_TRUE@am__objects_14 = $(am__objects_13) +am__objects_15 = libharfbuzz_la-hb-graphite2.lo +@HAVE_GRAPHITE2_TRUE@am__objects_16 = $(am__objects_15) +am__objects_17 = libharfbuzz_la-hb-uniscribe.lo +@HAVE_UNISCRIBE_TRUE@am__objects_18 = $(am__objects_17) +am__objects_19 = libharfbuzz_la-hb-directwrite.lo +@HAVE_DIRECTWRITE_TRUE@am__objects_20 = $(am__objects_19) +am__objects_21 = libharfbuzz_la-hb-coretext.lo +@HAVE_CORETEXT_TRUE@am__objects_22 = $(am__objects_21) +am__objects_23 = libharfbuzz_la-hb-ucdn.lo +@HAVE_UCDN_TRUE@am__objects_24 = $(am__objects_23) +am__objects_25 = libharfbuzz_la-hb-icu.lo +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_26 = \ +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_25) +am__objects_27 = $(am__objects_7) $(am__objects_8) $(am__objects_10) \ + $(am__objects_12) $(am__objects_14) $(am__objects_16) \ + $(am__objects_18) $(am__objects_20) $(am__objects_22) \ + $(am__objects_24) $(am__objects_26) +@HAVE_GLIB_TRUE@am__objects_28 = $(am__objects_5) +@HAVE_FREETYPE_TRUE@am__objects_29 = $(am__objects_5) +@HAVE_GRAPHITE2_TRUE@am__objects_30 = $(am__objects_5) +@HAVE_UNISCRIBE_TRUE@am__objects_31 = $(am__objects_5) +@HAVE_DIRECTWRITE_TRUE@am__objects_32 = $(am__objects_5) +@HAVE_CORETEXT_TRUE@am__objects_33 = $(am__objects_5) +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_34 = \ +@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_5) +am__objects_35 = $(am__objects_8) $(am__objects_28) $(am__objects_29) \ + $(am__objects_30) $(am__objects_31) $(am__objects_32) \ + $(am__objects_33) $(am__objects_34) +am_libharfbuzz_la_OBJECTS = $(am__objects_27) $(am__objects_35) libharfbuzz_la_OBJECTS = $(am_libharfbuzz_la_OBJECTS) am__EXEEXT_1 = -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am__EXEEXT_2 = \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ dump-emoji$(EXEEXT) +am__EXEEXT_2 = test-iter$(EXEEXT) test-ot-tag$(EXEEXT) \ + test-unicode-ranges$(EXEEXT) +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am__EXEEXT_3 = test-ot-color$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) -am__dump_emoji_SOURCES_DIST = dump-emoji.cc -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am_dump_emoji_OBJECTS = dump_emoji-dump-emoji.$(OBJEXT) -dump_emoji_OBJECTS = $(am_dump_emoji_OBJECTS) -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@dump_emoji_DEPENDENCIES = \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ libharfbuzz.la \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_11) \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) \ -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) -am_dump_fon_OBJECTS = dump_fon-dump-fon.$(OBJEXT) -dump_fon_OBJECTS = $(am_dump_fon_OBJECTS) -dump_fon_DEPENDENCIES = libharfbuzz.la $(am__DEPENDENCIES_11) am_dump_indic_data_OBJECTS = \ dump_indic_data-dump-indic-data.$(OBJEXT) \ dump_indic_data-hb-ot-shape-complex-indic-table.$(OBJEXT) @@ -609,17 +460,35 @@ am_test_buffer_serialize_OBJECTS = \ test_buffer_serialize_OBJECTS = $(am_test_buffer_serialize_OBJECTS) test_buffer_serialize_DEPENDENCIES = libharfbuzz.la \ $(am__DEPENDENCIES_11) +am_test_iter_OBJECTS = test_iter-test-iter.$(OBJEXT) \ + test_iter-hb-static.$(OBJEXT) +test_iter_OBJECTS = $(am_test_iter_OBJECTS) +am__DEPENDENCIES_12 = libharfbuzz.la $(am__DEPENDENCIES_11) +test_iter_DEPENDENCIES = $(am__DEPENDENCIES_12) +am_test_name_table_OBJECTS = \ + test_name_table-test-name-table.$(OBJEXT) +test_name_table_OBJECTS = $(am_test_name_table_OBJECTS) +test_name_table_DEPENDENCIES = libharfbuzz.la $(am__DEPENDENCIES_11) +am__test_ot_color_SOURCES_DIST = test-ot-color.cc +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@am_test_ot_color_OBJECTS = test_ot_color-test-ot-color.$(OBJEXT) +test_ot_color_OBJECTS = $(am_test_ot_color_OBJECTS) +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@test_ot_color_DEPENDENCIES = \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ libharfbuzz.la \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_11) \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) \ +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@ $(am__DEPENDENCIES_1) am_test_ot_tag_OBJECTS = test_ot_tag-hb-ot-tag.$(OBJEXT) test_ot_tag_OBJECTS = $(am_test_ot_tag_OBJECTS) -test_ot_tag_DEPENDENCIES = libharfbuzz.la $(am__DEPENDENCIES_11) +test_ot_tag_DEPENDENCIES = $(am__DEPENDENCIES_12) am_test_size_params_OBJECTS = \ test_size_params-test-size-params.$(OBJEXT) test_size_params_OBJECTS = $(am_test_size_params_OBJECTS) test_size_params_DEPENDENCIES = libharfbuzz.la $(am__DEPENDENCIES_11) -am_test_unicode_ranges_OBJECTS = test-unicode-ranges.$(OBJEXT) +am_test_unicode_ranges_OBJECTS = \ + test_unicode_ranges-test-unicode-ranges.$(OBJEXT) test_unicode_ranges_OBJECTS = $(am_test_unicode_ranges_OBJECTS) -test_unicode_ranges_DEPENDENCIES = libharfbuzz.la \ - $(am__DEPENDENCIES_11) +test_unicode_ranges_DEPENDENCIES = $(am__DEPENDENCIES_12) am_test_would_substitute_OBJECTS = \ test_would_substitute-test-would-substitute.$(OBJEXT) test_would_substitute_OBJECTS = $(am_test_would_substitute_OBJECTS) @@ -680,31 +549,27 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(libharfbuzz_fuzzing_la_SOURCES) \ - $(libharfbuzz_gobject_la_SOURCES) \ +SOURCES = $(libharfbuzz_gobject_la_SOURCES) \ $(nodist_libharfbuzz_gobject_la_SOURCES) \ - $(libharfbuzz_icu_la_SOURCES) \ - $(libharfbuzz_subset_fuzzing_la_SOURCES) \ - $(libharfbuzz_subset_la_SOURCES) $(libharfbuzz_la_SOURCES) \ - $(dump_emoji_SOURCES) $(dump_fon_SOURCES) \ - $(dump_indic_data_SOURCES) $(dump_khmer_data_SOURCES) \ - $(dump_myanmar_data_SOURCES) $(dump_use_data_SOURCES) \ - $(main_SOURCES) $(test_SOURCES) \ - $(test_buffer_serialize_SOURCES) $(test_ot_tag_SOURCES) \ - $(test_size_params_SOURCES) $(test_unicode_ranges_SOURCES) \ + $(libharfbuzz_icu_la_SOURCES) $(libharfbuzz_subset_la_SOURCES) \ + $(libharfbuzz_la_SOURCES) $(dump_indic_data_SOURCES) \ + $(dump_khmer_data_SOURCES) $(dump_myanmar_data_SOURCES) \ + $(dump_use_data_SOURCES) $(main_SOURCES) $(test_SOURCES) \ + $(test_buffer_serialize_SOURCES) $(test_iter_SOURCES) \ + $(test_name_table_SOURCES) $(test_ot_color_SOURCES) \ + $(test_ot_tag_SOURCES) $(test_size_params_SOURCES) \ + $(test_unicode_ranges_SOURCES) \ $(test_would_substitute_SOURCES) -DIST_SOURCES = $(am__libharfbuzz_fuzzing_la_SOURCES_DIST) \ - $(am__libharfbuzz_gobject_la_SOURCES_DIST) \ +DIST_SOURCES = $(am__libharfbuzz_gobject_la_SOURCES_DIST) \ $(am__libharfbuzz_icu_la_SOURCES_DIST) \ - $(libharfbuzz_subset_fuzzing_la_SOURCES) \ $(libharfbuzz_subset_la_SOURCES) \ - $(am__libharfbuzz_la_SOURCES_DIST) \ - $(am__dump_emoji_SOURCES_DIST) $(dump_fon_SOURCES) \ - $(dump_indic_data_SOURCES) $(dump_khmer_data_SOURCES) \ - $(dump_myanmar_data_SOURCES) $(dump_use_data_SOURCES) \ - $(main_SOURCES) $(test_SOURCES) \ - $(test_buffer_serialize_SOURCES) $(test_ot_tag_SOURCES) \ - $(test_size_params_SOURCES) $(test_unicode_ranges_SOURCES) \ + $(am__libharfbuzz_la_SOURCES_DIST) $(dump_indic_data_SOURCES) \ + $(dump_khmer_data_SOURCES) $(dump_myanmar_data_SOURCES) \ + $(dump_use_data_SOURCES) $(main_SOURCES) $(test_SOURCES) \ + $(test_buffer_serialize_SOURCES) $(test_iter_SOURCES) \ + $(test_name_table_SOURCES) $(am__test_ot_color_SOURCES_DIST) \ + $(test_ot_tag_SOURCES) $(test_size_params_SOURCES) \ + $(test_unicode_ranges_SOURCES) \ $(test_would_substitute_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ @@ -720,14 +585,14 @@ am__can_run_installinfo = \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(cmake_DATA) $(gir_DATA) $(pkgconfig_DATA) $(typelib_DATA) -am__pkginclude_HEADERS_DIST = hb.h hb-blob.h hb-buffer.h hb-common.h \ - hb-deprecated.h hb-face.h hb-font.h hb-map.h hb-set.h \ - hb-shape.h hb-shape-plan.h hb-unicode.h hb-version.h hb-ot.h \ - hb-ot-font.h hb-ot-layout.h hb-ot-math.h hb-ot-shape.h \ - hb-ot-tag.h hb-ot-var.h hb-glib.h hb-ft.h hb-graphite2.h \ - hb-uniscribe.h hb-directwrite.h hb-coretext.h hb-icu.h \ - hb-subset.h hb-subset-glyf.hh hb-subset-plan.hh \ - hb-subset-private.hh hb-gobject.h hb-gobject-structs.h +am__pkginclude_HEADERS_DIST = hb-aat-layout.h hb-aat.h hb-blob.h \ + hb-buffer.h hb-common.h hb-deprecated.h hb-face.h hb-font.h \ + hb-map.h hb-ot-color.h hb-ot-deprecated.h hb-ot-font.h \ + hb-ot-layout.h hb-ot-math.h hb-ot-name.h hb-ot-shape.h \ + hb-ot-var.h hb-ot.h hb-set.h hb-shape-plan.h hb-shape.h \ + hb-unicode.h hb-version.h hb.h hb-glib.h hb-ft.h \ + hb-graphite2.h hb-uniscribe.h hb-directwrite.h hb-coretext.h \ + hb-icu.h hb-subset.h hb-gobject.h hb-gobject-structs.h HEADERS = $(nodist_pkginclude_HEADERS) $(pkginclude_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive @@ -912,11 +777,11 @@ am__set_TESTS_bases = \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) -@WITH_LIBSTDCXX_FALSE@am__EXEEXT_3 = check-libstdc++.sh \ +@WITH_LIBSTDCXX_FALSE@am__EXEEXT_4 = check-libstdc++.sh \ @WITH_LIBSTDCXX_FALSE@ $(am__EXEEXT_1) -am__EXEEXT_4 = check-c-linkage-decls.sh check-externs.sh \ +am__EXEEXT_5 = check-c-linkage-decls.sh check-externs.sh \ check-header-guards.sh check-includes.sh check-static-inits.sh \ - check-symbols.sh $(am__EXEEXT_1) $(am__EXEEXT_3) + check-symbols.sh $(am__EXEEXT_1) $(am__EXEEXT_4) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver @@ -1083,6 +948,8 @@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ @@ -1152,87 +1019,189 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = -SUBDIRS = $(am__append_32) +SUBDIRS = $(am__append_30) DIST_SUBDIRS = hb-ucdn -BUILT_SOURCES = hb-version.h $(am__append_47) $(RAGEL_GENERATED) +BUILT_SOURCES = hb-version.h $(am__append_45) $(RAGEL_GENERATED) EXTRA_DIST = hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in \ harfbuzz-subset.pc.in harfbuzz-icu.pc.in \ harfbuzz-gobject.pc.in hb-gobject-enums.cc.tmpl \ hb-gobject-enums.h.tmpl $(NULL) $(GENERATORS) \ - $(HB_BASE_RAGEL_sources) $(HB_OT_RAGEL_sources) $(NULL) -CLEANFILES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la \ - $(pkgconfig_DATA) $(DEF_FILES) $(am__append_52) -DISTCLEANFILES = $(am__append_48) + $(HB_BASE_RAGEL_sources) $(NULL) +CLEANFILES = $(pkgconfig_DATA) $(DEF_FILES) $(am__append_50) +DISTCLEANFILES = $(am__append_46) MAINTAINERCLEANFILES = DISTCHECK_CONFIGURE_FLAGS = --enable-introspection lib_LTLIBRARIES = libharfbuzz.la libharfbuzz-subset.la \ - $(am__append_40) $(am__append_43) + $(am__append_38) $(am__append_41) HB_BASE_sources = \ - hb-atomic-private.hh \ - hb-blob-private.hh \ + hb-aat-fdsc-table.hh \ + hb-aat-layout-ankr-table.hh \ + hb-aat-layout-bsln-table.hh \ + hb-aat-layout-common.hh \ + hb-aat-layout-feat-table.hh \ + hb-aat-layout-just-table.hh \ + hb-aat-layout-kerx-table.hh \ + hb-aat-layout-lcar-table.hh \ + hb-aat-layout-morx-table.hh \ + hb-aat-layout-trak-table.hh \ + hb-aat-layout.cc \ + hb-aat-layout.hh \ + hb-aat-ltag-table.hh \ + hb-aat-map.cc \ + hb-aat-map.hh \ + hb-array.hh \ + hb-atomic.hh \ hb-blob.cc \ - hb-buffer-private.hh \ + hb-blob.hh \ hb-buffer-serialize.cc \ hb-buffer.cc \ + hb-buffer.hh \ + hb-cache.hh \ + hb-cff-interp-common.hh \ + hb-cff-interp-cs-common.hh \ + hb-cff-interp-dict-common.hh \ + hb-cff1-interp-cs.hh \ + hb-cff2-interp-cs.hh \ hb-common.cc \ hb-debug.hh \ hb-dsalgs.hh \ - hb-face-private.hh \ hb-face.cc \ - hb-font-private.hh \ + hb-face.hh \ hb-font.cc \ - hb-map-private.hh \ + hb-font.hh \ + hb-iter.hh \ + hb-kern.hh \ + hb-machinery.hh \ hb-map.cc \ - hb-mutex-private.hh \ - hb-object-private.hh \ - hb-open-file-private.hh \ - hb-open-type-private.hh \ - hb-ot-color-cbdt-table.hh \ + hb-map.hh \ + hb-mutex.hh \ + hb-null.hh \ + hb-object.hh \ + hb-open-file.hh \ + hb-open-type.hh \ + hb-ot-cff-common.hh \ + hb-ot-cff1-table.cc \ + hb-ot-cff1-table.hh \ + hb-ot-cff2-table.cc \ + hb-ot-cff2-table.hh \ hb-ot-cmap-table.hh \ + hb-ot-color-cbdt-table.hh \ + hb-ot-color-colr-table.hh \ + hb-ot-color-cpal-table.hh \ + hb-ot-color-sbix-table.hh \ + hb-ot-color-svg-table.hh \ + hb-ot-color.cc \ + hb-ot-face.cc \ + hb-ot-face.hh \ + hb-ot-font.cc \ + hb-ot-gasp-table.hh \ hb-ot-glyf-table.hh \ hb-ot-hdmx-table.hh \ hb-ot-head-table.hh \ hb-ot-hhea-table.hh \ hb-ot-hmtx-table.hh \ hb-ot-kern-table.hh \ + hb-ot-layout-base-table.hh \ + hb-ot-layout-common.hh \ + hb-ot-layout-gdef-table.hh \ + hb-ot-layout-gpos-table.hh \ + hb-ot-layout-gsub-table.hh \ + hb-ot-layout-gsubgpos.hh \ + hb-ot-layout-jstf-table.hh \ + hb-ot-layout.cc \ + hb-ot-layout.hh \ + hb-ot-map.cc \ + hb-ot-map.hh \ + hb-ot-math-table.hh \ + hb-ot-math.cc \ hb-ot-maxp-table.hh \ + hb-ot-name-language.cc \ + hb-ot-name-language.hh \ hb-ot-name-table.hh \ + hb-ot-name.cc \ hb-ot-os2-table.hh \ hb-ot-os2-unicode-ranges.hh \ hb-ot-post-macroman.hh \ hb-ot-post-table.hh \ + hb-ot-shape-complex-arabic-fallback.hh \ + hb-ot-shape-complex-arabic-table.hh \ + hb-ot-shape-complex-arabic-win1256.hh \ + hb-ot-shape-complex-arabic.cc \ + hb-ot-shape-complex-arabic.hh \ + hb-ot-shape-complex-default.cc \ + hb-ot-shape-complex-hangul.cc \ + hb-ot-shape-complex-hebrew.cc \ + hb-ot-shape-complex-indic-table.cc \ + hb-ot-shape-complex-indic.cc \ + hb-ot-shape-complex-indic.hh \ + hb-ot-shape-complex-khmer.cc \ + hb-ot-shape-complex-khmer.hh \ + hb-ot-shape-complex-myanmar.cc \ + hb-ot-shape-complex-myanmar.hh \ + hb-ot-shape-complex-thai.cc \ + hb-ot-shape-complex-use-table.cc \ + hb-ot-shape-complex-use.cc \ + hb-ot-shape-complex-use.hh \ + hb-ot-shape-complex-vowel-constraints.cc \ + hb-ot-shape-complex-vowel-constraints.hh \ + hb-ot-shape-complex.hh \ + hb-ot-shape-fallback.cc \ + hb-ot-shape-fallback.hh \ + hb-ot-shape-normalize.cc \ + hb-ot-shape-normalize.hh \ + hb-ot-shape.cc \ + hb-ot-shape.hh \ + hb-ot-stat-table.hh \ + hb-ot-tag-table.hh \ hb-ot-tag.cc \ - hb-private.hh \ - hb-set-digest-private.hh \ - hb-set-private.hh \ + hb-ot-var-avar-table.hh \ + hb-ot-var-fvar-table.hh \ + hb-ot-var-hvar-table.hh \ + hb-ot-var-mvar-table.hh \ + hb-ot-var.cc \ + hb-ot-vorg-table.hh \ + hb-set-digest.hh \ hb-set.cc \ - hb-shape.cc \ - hb-shape-plan-private.hh \ + hb-set.hh \ hb-shape-plan.cc \ + hb-shape-plan.hh \ + hb-shape.cc \ + hb-shaper-impl.hh \ hb-shaper-list.hh \ - hb-shaper-impl-private.hh \ - hb-shaper-private.hh \ hb-shaper.cc \ + hb-shaper.hh \ hb-static.cc \ hb-string-array.hh \ - hb-unicode-private.hh \ + hb-unicode-emoji-table.hh \ hb-unicode.cc \ - hb-utf-private.hh \ + hb-unicode.hh \ + hb-utf.hh \ + hb-vector.hh \ hb-warning.cc \ + hb.hh \ $(NULL) HB_BASE_RAGEL_GENERATED_sources = \ hb-buffer-deserialize-json.hh \ hb-buffer-deserialize-text.hh \ + hb-ot-shape-complex-indic-machine.hh \ + hb-ot-shape-complex-khmer-machine.hh \ + hb-ot-shape-complex-myanmar-machine.hh \ + hb-ot-shape-complex-use-machine.hh \ $(NULL) HB_BASE_RAGEL_sources = \ hb-buffer-deserialize-json.rl \ hb-buffer-deserialize-text.rl \ + hb-ot-shape-complex-indic-machine.rl \ + hb-ot-shape-complex-khmer-machine.rl \ + hb-ot-shape-complex-myanmar-machine.rl \ + hb-ot-shape-complex-use-machine.rl \ $(NULL) HB_BASE_headers = \ - hb.h \ + hb-aat-layout.h \ + hb-aat.h \ hb-blob.h \ hb-buffer.h \ hb-common.h \ @@ -1240,107 +1209,27 @@ HB_BASE_headers = \ hb-face.h \ hb-font.h \ hb-map.h \ + hb-ot-color.h \ + hb-ot-deprecated.h \ + hb-ot-font.h \ + hb-ot-layout.h \ + hb-ot-math.h \ + hb-ot-name.h \ + hb-ot-shape.h \ + hb-ot-var.h \ + hb-ot.h \ hb-set.h \ - hb-shape.h \ hb-shape-plan.h \ + hb-shape.h \ hb-unicode.h \ hb-version.h \ + hb.h \ $(NULL) HB_FALLBACK_sources = \ hb-fallback-shape.cc \ $(NULL) -HB_OT_sources = \ - hb-aat-layout.cc \ - hb-aat-layout-common-private.hh \ - hb-aat-layout-ankr-table.hh \ - hb-aat-layout-bsln-table.hh \ - hb-aat-layout-feat-table.hh \ - hb-aat-layout-kerx-table.hh \ - hb-aat-layout-morx-table.hh \ - hb-aat-layout-trak-table.hh \ - hb-aat-layout-private.hh \ - hb-aat-fmtx-table.hh \ - hb-aat-gcid-table.hh \ - hb-aat-ltag-table.hh \ - hb-ot-font.cc \ - hb-ot-layout.cc \ - hb-ot-layout-base-table.hh \ - hb-ot-layout-common-private.hh \ - hb-ot-layout-gdef-table.hh \ - hb-ot-layout-gpos-table.hh \ - hb-ot-layout-gsubgpos-private.hh \ - hb-ot-layout-gsub-table.hh \ - hb-ot-layout-jstf-table.hh \ - hb-ot-layout-private.hh \ - hb-ot-color.cc \ - hb-ot-color-colr-table.hh \ - hb-ot-color-cpal-table.hh \ - hb-ot-color-sbix-table.hh \ - hb-ot-color-svg-table.hh \ - hb-ot-map.cc \ - hb-ot-map-private.hh \ - hb-ot-math.cc \ - hb-ot-math-table.hh \ - hb-ot-shape.cc \ - hb-ot-shape-complex-arabic.cc \ - hb-ot-shape-complex-arabic-fallback.hh \ - hb-ot-shape-complex-arabic-private.hh \ - hb-ot-shape-complex-arabic-table.hh \ - hb-ot-shape-complex-arabic-win1256.hh \ - hb-ot-shape-complex-default.cc \ - hb-ot-shape-complex-hangul.cc \ - hb-ot-shape-complex-hebrew.cc \ - hb-ot-shape-complex-indic.cc \ - hb-ot-shape-complex-indic-private.hh \ - hb-ot-shape-complex-indic-table.cc \ - hb-ot-shape-complex-khmer-private.hh \ - hb-ot-shape-complex-khmer.cc \ - hb-ot-shape-complex-myanmar-private.hh \ - hb-ot-shape-complex-myanmar.cc \ - hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-tibetan.cc \ - hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use-private.hh \ - hb-ot-shape-complex-use-table.cc \ - hb-ot-shape-complex-private.hh \ - hb-ot-shape-normalize-private.hh \ - hb-ot-shape-normalize.cc \ - hb-ot-shape-fallback-private.hh \ - hb-ot-shape-fallback.cc \ - hb-ot-shape-private.hh \ - hb-ot-var.cc \ - hb-ot-var-avar-table.hh \ - hb-ot-var-fvar-table.hh \ - hb-ot-var-hvar-table.hh \ - hb-ot-var-mvar-table.hh \ - $(NULL) - -HB_OT_RAGEL_GENERATED_sources = \ - hb-ot-shape-complex-indic-machine.hh \ - hb-ot-shape-complex-khmer-machine.hh \ - hb-ot-shape-complex-myanmar-machine.hh \ - hb-ot-shape-complex-use-machine.hh \ - $(NULL) - -HB_OT_RAGEL_sources = \ - hb-ot-shape-complex-indic-machine.rl \ - hb-ot-shape-complex-khmer-machine.rl \ - hb-ot-shape-complex-myanmar-machine.rl \ - hb-ot-shape-complex-use-machine.rl \ - $(NULL) - -HB_OT_headers = \ - hb-ot.h \ - hb-ot-font.h \ - hb-ot-layout.h \ - hb-ot-math.h \ - hb-ot-shape.h \ - hb-ot-tag.h \ - hb-ot-var.h \ - $(NULL) - # Optional Sources and Headers with external deps HB_FT_sources = hb-ft.cc @@ -1367,18 +1256,30 @@ HB_ICU_headers = hb-icu.h # Sources for libharfbuzz-subset HB_SUBSET_sources = \ + hb-ot-cff1-table.cc \ + hb-ot-cff2-table.cc \ hb-static.cc \ - hb-subset.cc \ + hb-subset-cff-common.cc \ + hb-subset-cff-common.hh \ + hb-subset-cff1.cc \ + hb-subset-cff1.hh \ + hb-subset-cff2.cc \ + hb-subset-cff2.hh \ hb-subset-glyf.cc \ + hb-subset-glyf.hh \ + hb-subset-glyf.hh \ hb-subset-input.cc \ + hb-subset-input.hh \ hb-subset-plan.cc \ + hb-subset-plan.hh \ + hb-subset-plan.hh \ + hb-subset.cc \ + hb-subset.hh \ + hb-subset.hh \ $(NULL) HB_SUBSET_headers = \ hb-subset.h \ - hb-subset-glyf.hh \ - hb-subset-plan.hh \ - hb-subset-private.hh \ $(NULL) HB_GOBJECT_DIST_sources = hb-gobject-structs.cc @@ -1389,24 +1290,23 @@ HB_GOBJECT_NODIST_sources = $(HB_GOBJECT_ENUM_sources) HB_GOBJECT_NODIST_headers = $(HB_GOBJECT_ENUM_headers) HB_GOBJECT_sources = $(HB_GOBJECT_DIST_sources) $(HB_GOBJECT_NODIST_sources) HB_GOBJECT_headers = $(HB_GOBJECT_DIST_headers) $(HB_GOBJECT_NODIST_headers) -HBCFLAGS = $(am__append_4) $(am__append_6) $(am__append_11) \ - $(am__append_15) $(am__append_20) $(am__append_24) \ - $(am__append_28) $(am__append_33) $(am__append_36) +HBCFLAGS = $(am__append_2) $(am__append_4) $(am__append_9) \ + $(am__append_13) $(am__append_18) $(am__append_22) \ + $(am__append_26) $(am__append_31) $(am__append_34) # Put the library together -HBLIBS = $(am__append_7) $(am__append_12) $(am__append_16) \ - $(am__append_34) $(HBNONPCLIBS) $(am__append_37) -HBNONPCLIBS = $(am__append_5) $(am__append_21) $(am__append_25) \ - $(am__append_29) -HBDEPS = $(am__append_8) $(am__append_17) +HBLIBS = $(am__append_5) $(am__append_10) $(am__append_14) \ + $(am__append_32) $(HBNONPCLIBS) $(am__append_35) +HBNONPCLIBS = $(am__append_3) $(am__append_19) $(am__append_23) \ + $(am__append_27) +HBDEPS = $(am__append_6) $(am__append_15) HBSOURCES = $(HB_BASE_sources) $(HB_BASE_RAGEL_GENERATED_sources) \ - $(am__append_1) $(am__append_3) $(am__append_9) \ - $(am__append_13) $(am__append_18) $(am__append_22) \ - $(am__append_26) $(am__append_30) $(am__append_35) \ - $(am__append_38) -HBHEADERS = $(HB_BASE_headers) $(am__append_2) $(am__append_10) \ - $(am__append_14) $(am__append_19) $(am__append_23) \ - $(am__append_27) $(am__append_31) $(am__append_39) + $(am__append_1) $(am__append_7) $(am__append_11) \ + $(am__append_16) $(am__append_20) $(am__append_24) \ + $(am__append_28) $(am__append_33) $(am__append_36) +HBHEADERS = $(HB_BASE_headers) $(am__append_8) $(am__append_12) \ + $(am__append_17) $(am__append_21) $(am__append_25) \ + $(am__append_29) $(am__append_37) @OS_WIN32_TRUE@export_symbols = -export-symbols harfbuzz.def @OS_WIN32_TRUE@harfbuzz_def_dependency = harfbuzz.def @OS_WIN32_TRUE@export_symbols_subset = -export-symbols harfbuzz-subset.def @@ -1428,11 +1328,11 @@ libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LD libharfbuzz_la_LIBADD = $(HBLIBS) EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency) pkginclude_HEADERS = $(HBHEADERS) $(HB_SUBSET_headers) \ - $(am__append_41) $(am__append_44) -nodist_pkginclude_HEADERS = $(am__append_45) + $(am__append_39) $(am__append_42) +nodist_pkginclude_HEADERS = $(am__append_43) pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = harfbuzz.pc harfbuzz-subset.pc $(am__append_42) \ - $(am__append_46) +pkgconfig_DATA = harfbuzz.pc harfbuzz-subset.pc $(am__append_40) \ + $(am__append_44) cmakedir = $(libdir)/cmake/harfbuzz cmake_DATA = harfbuzz-config.cmake libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources) @@ -1440,33 +1340,6 @@ libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS) libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS) libharfbuzz_subset_la_LIBADD = libharfbuzz.la EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency) -FUZZING_CPPFLAGS = \ - -DHB_NDEBUG \ - -DHB_MAX_NESTING_LEVEL=3 \ - -DHB_SANITIZE_MAX_EDITS=3 \ - -DHB_SANITIZE_MAX_OPS_FACTOR=3 \ - -DHB_SANITIZE_MAX_OPS_MIN=128 \ - -DHB_BUFFER_MAX_LEN_FACTOR=3 \ - -DHB_BUFFER_MAX_LEN_MIN=8 \ - -DHB_BUFFER_MAX_LEN_DEFAULT=128 \ - -DHB_BUFFER_MAX_OPS_FACTOR=8 \ - -DHB_BUFFER_MAX_OPS_MIN=64 \ - -DHB_BUFFER_MAX_OPS_DEFAULT=1024 \ - $(NULL) - -EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la -libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS) -libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES) -libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD) -EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES) -libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS) -libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES) -libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_subset_fuzzing_la_LIBADD = $(libharfbuzz_subset_la_LIBADD) -EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES) @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources) @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS) @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS) @@ -1480,17 +1353,20 @@ EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la @HAVE_GOBJECT_TRUE@libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la @HAVE_GOBJECT_TRUE@EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency) DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def \ - $(am__append_49) + harfbuzz-deprecated-symbols.txt $(am__append_47) GENERATORS = \ gen-arabic-table.py \ + gen-def.py \ + gen-emoji-table.py \ gen-indic-table.py \ + gen-os2-unicode-ranges.py \ + gen-tag-table.py \ gen-use-table.py \ - gen-def.py \ + gen-vowel-constraints.py \ $(NULL) RAGEL_GENERATED = \ $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ - $(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \ $(NULL) main_SOURCES = main.cc @@ -1499,21 +1375,24 @@ main_LDADD = libharfbuzz.la $(HBLIBS) test_SOURCES = test.cc test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) -test_would_substitute_SOURCES = test-would-substitute.cc -test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) -test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) -test_size_params_SOURCES = test-size-params.cc -test_size_params_CPPFLAGS = $(HBCFLAGS) -test_size_params_LDADD = libharfbuzz.la $(HBLIBS) test_buffer_serialize_SOURCES = test-buffer-serialize.cc test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) +test_name_table_SOURCES = test-name-table.cc +test_name_table_CPPFLAGS = $(HBCFLAGS) +test_name_table_LDADD = libharfbuzz.la $(HBLIBS) +test_size_params_SOURCES = test-size-params.cc +test_size_params_CPPFLAGS = $(HBCFLAGS) +test_size_params_LDADD = libharfbuzz.la $(HBLIBS) +test_would_substitute_SOURCES = test-would-substitute.cc +test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) +test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@test_ot_color_SOURCES = test-ot-color.cc +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) +@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS) dist_check_SCRIPTS = check-c-linkage-decls.sh check-externs.sh \ check-header-guards.sh check-includes.sh check-static-inits.sh \ - check-symbols.sh $(NULL) $(am__append_50) -dump_fon_SOURCES = dump-fon.cc -dump_fon_CPPFLAGS = $(HBCFLAGS) -dump_fon_LDADD = libharfbuzz.la $(HBLIBS) + check-symbols.sh $(NULL) $(am__append_49) dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc dump_indic_data_CPPFLAGS = $(HBCFLAGS) dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS) @@ -1526,14 +1405,18 @@ dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS) dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc dump_use_data_CPPFLAGS = $(HBCFLAGS) dump_use_data_LDADD = libharfbuzz.la $(HBLIBS) -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@dump_emoji_SOURCES = dump-emoji.cc -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@dump_emoji_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) -@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@dump_emoji_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS) +COMPILED_TESTS = test-iter test-ot-tag test-unicode-ranges +COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG +COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS) +test_iter_SOURCES = test-iter.cc hb-static.cc +test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_iter_LDADD = $(COMPILED_TESTS_LDADD) test_ot_tag_SOURCES = hb-ot-tag.cc -test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN -test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD) test_unicode_ranges_SOURCES = test-unicode-ranges.cc -test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS) +test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD) TESTS_ENVIRONMENT = \ srcdir="$(srcdir)" \ MAKE="$(MAKE) $(AM_MAKEFLAGS)" \ @@ -1553,6 +1436,8 @@ TESTS_ENVIRONMENT = \ @HAVE_INTROSPECTION_TRUE@ -DHB_H_IN \ @HAVE_INTROSPECTION_TRUE@ -DHB_OT_H \ @HAVE_INTROSPECTION_TRUE@ -DHB_OT_H_IN \ +@HAVE_INTROSPECTION_TRUE@ -DHB_AAT_H \ +@HAVE_INTROSPECTION_TRUE@ -DHB_AAT_H_IN \ @HAVE_INTROSPECTION_TRUE@ -DHB_GOBJECT_H \ @HAVE_INTROSPECTION_TRUE@ -DHB_GOBJECT_H_IN \ @HAVE_INTROSPECTION_TRUE@ -DHB_EXTERN= \ @@ -1647,18 +1532,12 @@ clean-libLTLIBRARIES: rm -f $${locs}; \ } -libharfbuzz-fuzzing.la: $(libharfbuzz_fuzzing_la_OBJECTS) $(libharfbuzz_fuzzing_la_DEPENDENCIES) $(EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES) - $(AM_V_GEN)$(libharfbuzz_fuzzing_la_LINK) $(libharfbuzz_fuzzing_la_OBJECTS) $(libharfbuzz_fuzzing_la_LIBADD) $(LIBS) - libharfbuzz-gobject.la: $(libharfbuzz_gobject_la_OBJECTS) $(libharfbuzz_gobject_la_DEPENDENCIES) $(EXTRA_libharfbuzz_gobject_la_DEPENDENCIES) $(AM_V_GEN)$(libharfbuzz_gobject_la_LINK) $(am_libharfbuzz_gobject_la_rpath) $(libharfbuzz_gobject_la_OBJECTS) $(libharfbuzz_gobject_la_LIBADD) $(LIBS) libharfbuzz-icu.la: $(libharfbuzz_icu_la_OBJECTS) $(libharfbuzz_icu_la_DEPENDENCIES) $(EXTRA_libharfbuzz_icu_la_DEPENDENCIES) $(AM_V_CXXLD)$(libharfbuzz_icu_la_LINK) $(am_libharfbuzz_icu_la_rpath) $(libharfbuzz_icu_la_OBJECTS) $(libharfbuzz_icu_la_LIBADD) $(LIBS) -libharfbuzz-subset-fuzzing.la: $(libharfbuzz_subset_fuzzing_la_OBJECTS) $(libharfbuzz_subset_fuzzing_la_DEPENDENCIES) $(EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES) - $(AM_V_GEN)$(libharfbuzz_subset_fuzzing_la_LINK) $(libharfbuzz_subset_fuzzing_la_OBJECTS) $(libharfbuzz_subset_fuzzing_la_LIBADD) $(LIBS) - libharfbuzz-subset.la: $(libharfbuzz_subset_la_OBJECTS) $(libharfbuzz_subset_la_DEPENDENCIES) $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES) $(AM_V_CXXLD)$(libharfbuzz_subset_la_LINK) -rpath $(libdir) $(libharfbuzz_subset_la_OBJECTS) $(libharfbuzz_subset_la_LIBADD) $(LIBS) @@ -1748,14 +1627,6 @@ clean-noinstPROGRAMS: echo " rm -f" $$list; \ rm -f $$list -dump-emoji$(EXEEXT): $(dump_emoji_OBJECTS) $(dump_emoji_DEPENDENCIES) $(EXTRA_dump_emoji_DEPENDENCIES) - @rm -f dump-emoji$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(dump_emoji_OBJECTS) $(dump_emoji_LDADD) $(LIBS) - -dump-fon$(EXEEXT): $(dump_fon_OBJECTS) $(dump_fon_DEPENDENCIES) $(EXTRA_dump_fon_DEPENDENCIES) - @rm -f dump-fon$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(dump_fon_OBJECTS) $(dump_fon_LDADD) $(LIBS) - dump-indic-data$(EXEEXT): $(dump_indic_data_OBJECTS) $(dump_indic_data_DEPENDENCIES) $(EXTRA_dump_indic_data_DEPENDENCIES) @rm -f dump-indic-data$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(dump_indic_data_OBJECTS) $(dump_indic_data_LDADD) $(LIBS) @@ -1784,6 +1655,18 @@ test-buffer-serialize$(EXEEXT): $(test_buffer_serialize_OBJECTS) $(test_buffer_s @rm -f test-buffer-serialize$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_buffer_serialize_OBJECTS) $(test_buffer_serialize_LDADD) $(LIBS) +test-iter$(EXEEXT): $(test_iter_OBJECTS) $(test_iter_DEPENDENCIES) $(EXTRA_test_iter_DEPENDENCIES) + @rm -f test-iter$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_iter_OBJECTS) $(test_iter_LDADD) $(LIBS) + +test-name-table$(EXEEXT): $(test_name_table_OBJECTS) $(test_name_table_DEPENDENCIES) $(EXTRA_test_name_table_DEPENDENCIES) + @rm -f test-name-table$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_name_table_OBJECTS) $(test_name_table_LDADD) $(LIBS) + +test-ot-color$(EXEEXT): $(test_ot_color_OBJECTS) $(test_ot_color_DEPENDENCIES) $(EXTRA_test_ot_color_DEPENDENCIES) + @rm -f test-ot-color$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_ot_color_OBJECTS) $(test_ot_color_LDADD) $(LIBS) + test-ot-tag$(EXEEXT): $(test_ot_tag_OBJECTS) $(test_ot_tag_DEPENDENCIES) $(EXTRA_test_ot_tag_DEPENDENCIES) @rm -f test-ot-tag$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_ot_tag_OBJECTS) $(test_ot_tag_LDADD) $(LIBS) @@ -1806,8 +1689,6 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_emoji-dump-emoji.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_fon-dump-fon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_indic_data-dump-indic-data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_indic_data-hb-ot-shape-complex-indic-table.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_khmer_data-dump-khmer-data.Po@am__quote@ @@ -1816,56 +1697,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_myanmar_data-hb-ot-shape-complex-indic-table.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_use_data-dump-use-data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_use_data-hb-ot-shape-complex-use-table.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-aat-layout.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-blob.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer-serialize.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-common.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-coretext.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-directwrite.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-face.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-fallback-shape.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-font.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ft.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-glib.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-graphite2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-icu.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-map.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-color.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-font.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-layout.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-map.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-math.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-fallback.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-normalize.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-tag.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-var.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-set.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape-plan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-shaper.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-static.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-ucdn.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-unicode.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-uniscribe.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_fuzzing_la-hb-warning.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_icu_la-hb-icu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-aat-layout.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-aat-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-blob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-buffer-serialize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-buffer.Plo@am__quote@ @@ -1880,11 +1716,16 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-graphite2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-icu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-map.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-cff1-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-cff2-table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-color.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-face.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-font.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-layout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-math.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-name-language.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo@am__quote@ @@ -1894,9 +1735,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-tibetan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo@am__quote@ @@ -1911,22 +1752,26 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-unicode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-uniscribe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-warning.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-static.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-glyf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-input.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-plan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-static.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff-common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-glyf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-input.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-test.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-unicode-ranges.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_buffer_serialize-test-buffer-serialize.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_iter-hb-static.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_iter-test-iter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_name_table-test-name-table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ot_color-test-ot-color.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ot_tag-hb-ot-tag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_size_params-test-size-params.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_would_substitute-test-would-substitute.Po@am__quote@ .cc.o: @@ -1950,328 +1795,6 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< -libharfbuzz_fuzzing_la-hb-blob.lo: hb-blob.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-blob.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-blob.Tpo -c -o libharfbuzz_fuzzing_la-hb-blob.lo `test -f 'hb-blob.cc' || echo '$(srcdir)/'`hb-blob.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-blob.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-blob.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-blob.cc' object='libharfbuzz_fuzzing_la-hb-blob.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-blob.lo `test -f 'hb-blob.cc' || echo '$(srcdir)/'`hb-blob.cc - -libharfbuzz_fuzzing_la-hb-buffer-serialize.lo: hb-buffer-serialize.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-buffer-serialize.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer-serialize.Tpo -c -o libharfbuzz_fuzzing_la-hb-buffer-serialize.lo `test -f 'hb-buffer-serialize.cc' || echo '$(srcdir)/'`hb-buffer-serialize.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer-serialize.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer-serialize.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-buffer-serialize.cc' object='libharfbuzz_fuzzing_la-hb-buffer-serialize.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-buffer-serialize.lo `test -f 'hb-buffer-serialize.cc' || echo '$(srcdir)/'`hb-buffer-serialize.cc - -libharfbuzz_fuzzing_la-hb-buffer.lo: hb-buffer.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-buffer.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer.Tpo -c -o libharfbuzz_fuzzing_la-hb-buffer.lo `test -f 'hb-buffer.cc' || echo '$(srcdir)/'`hb-buffer.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-buffer.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-buffer.cc' object='libharfbuzz_fuzzing_la-hb-buffer.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-buffer.lo `test -f 'hb-buffer.cc' || echo '$(srcdir)/'`hb-buffer.cc - -libharfbuzz_fuzzing_la-hb-common.lo: hb-common.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-common.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-common.Tpo -c -o libharfbuzz_fuzzing_la-hb-common.lo `test -f 'hb-common.cc' || echo '$(srcdir)/'`hb-common.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-common.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-common.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-common.cc' object='libharfbuzz_fuzzing_la-hb-common.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-common.lo `test -f 'hb-common.cc' || echo '$(srcdir)/'`hb-common.cc - -libharfbuzz_fuzzing_la-hb-face.lo: hb-face.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-face.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-face.Tpo -c -o libharfbuzz_fuzzing_la-hb-face.lo `test -f 'hb-face.cc' || echo '$(srcdir)/'`hb-face.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-face.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-face.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-face.cc' object='libharfbuzz_fuzzing_la-hb-face.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-face.lo `test -f 'hb-face.cc' || echo '$(srcdir)/'`hb-face.cc - -libharfbuzz_fuzzing_la-hb-font.lo: hb-font.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-font.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-font.Tpo -c -o libharfbuzz_fuzzing_la-hb-font.lo `test -f 'hb-font.cc' || echo '$(srcdir)/'`hb-font.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-font.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-font.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-font.cc' object='libharfbuzz_fuzzing_la-hb-font.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-font.lo `test -f 'hb-font.cc' || echo '$(srcdir)/'`hb-font.cc - -libharfbuzz_fuzzing_la-hb-map.lo: hb-map.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-map.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-map.Tpo -c -o libharfbuzz_fuzzing_la-hb-map.lo `test -f 'hb-map.cc' || echo '$(srcdir)/'`hb-map.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-map.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-map.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-map.cc' object='libharfbuzz_fuzzing_la-hb-map.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-map.lo `test -f 'hb-map.cc' || echo '$(srcdir)/'`hb-map.cc - -libharfbuzz_fuzzing_la-hb-ot-tag.lo: hb-ot-tag.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-tag.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-tag.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-tag.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-tag.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-tag.cc' object='libharfbuzz_fuzzing_la-hb-ot-tag.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc - -libharfbuzz_fuzzing_la-hb-set.lo: hb-set.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-set.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-set.Tpo -c -o libharfbuzz_fuzzing_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-set.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-set.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-set.cc' object='libharfbuzz_fuzzing_la-hb-set.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc - -libharfbuzz_fuzzing_la-hb-shape.lo: hb-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape.Tpo -c -o libharfbuzz_fuzzing_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape.cc' object='libharfbuzz_fuzzing_la-hb-shape.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc - -libharfbuzz_fuzzing_la-hb-shape-plan.lo: hb-shape-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-shape-plan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape-plan.Tpo -c -o libharfbuzz_fuzzing_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape-plan.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shape-plan.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape-plan.cc' object='libharfbuzz_fuzzing_la-hb-shape-plan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc - -libharfbuzz_fuzzing_la-hb-shaper.lo: hb-shaper.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-shaper.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shaper.Tpo -c -o libharfbuzz_fuzzing_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shaper.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-shaper.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shaper.cc' object='libharfbuzz_fuzzing_la-hb-shaper.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc - -libharfbuzz_fuzzing_la-hb-static.lo: hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-static.Tpo -c -o libharfbuzz_fuzzing_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-static.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-static.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='libharfbuzz_fuzzing_la-hb-static.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc - -libharfbuzz_fuzzing_la-hb-unicode.lo: hb-unicode.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-unicode.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-unicode.Tpo -c -o libharfbuzz_fuzzing_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-unicode.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-unicode.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-unicode.cc' object='libharfbuzz_fuzzing_la-hb-unicode.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc - -libharfbuzz_fuzzing_la-hb-warning.lo: hb-warning.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-warning.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-warning.Tpo -c -o libharfbuzz_fuzzing_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-warning.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-warning.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-warning.cc' object='libharfbuzz_fuzzing_la-hb-warning.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc - -libharfbuzz_fuzzing_la-hb-aat-layout.lo: hb-aat-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-aat-layout.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-aat-layout.Tpo -c -o libharfbuzz_fuzzing_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-aat-layout.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-aat-layout.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-aat-layout.cc' object='libharfbuzz_fuzzing_la-hb-aat-layout.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc - -libharfbuzz_fuzzing_la-hb-ot-font.lo: hb-ot-font.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-font.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-font.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-font.lo `test -f 'hb-ot-font.cc' || echo '$(srcdir)/'`hb-ot-font.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-font.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-font.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-font.cc' object='libharfbuzz_fuzzing_la-hb-ot-font.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-font.lo `test -f 'hb-ot-font.cc' || echo '$(srcdir)/'`hb-ot-font.cc - -libharfbuzz_fuzzing_la-hb-ot-layout.lo: hb-ot-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-layout.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-layout.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-layout.lo `test -f 'hb-ot-layout.cc' || echo '$(srcdir)/'`hb-ot-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-layout.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-layout.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-layout.cc' object='libharfbuzz_fuzzing_la-hb-ot-layout.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-layout.lo `test -f 'hb-ot-layout.cc' || echo '$(srcdir)/'`hb-ot-layout.cc - -libharfbuzz_fuzzing_la-hb-ot-color.lo: hb-ot-color.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-color.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-color.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-color.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-color.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-color.cc' object='libharfbuzz_fuzzing_la-hb-ot-color.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc - -libharfbuzz_fuzzing_la-hb-ot-map.lo: hb-ot-map.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-map.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-map.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-map.lo `test -f 'hb-ot-map.cc' || echo '$(srcdir)/'`hb-ot-map.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-map.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-map.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-map.cc' object='libharfbuzz_fuzzing_la-hb-ot-map.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-map.lo `test -f 'hb-ot-map.cc' || echo '$(srcdir)/'`hb-ot-map.cc - -libharfbuzz_fuzzing_la-hb-ot-math.lo: hb-ot-math.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-math.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-math.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-math.lo `test -f 'hb-ot-math.cc' || echo '$(srcdir)/'`hb-ot-math.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-math.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-math.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-math.cc' object='libharfbuzz_fuzzing_la-hb-ot-math.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-math.lo `test -f 'hb-ot-math.cc' || echo '$(srcdir)/'`hb-ot-math.cc - -libharfbuzz_fuzzing_la-hb-ot-shape.lo: hb-ot-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo: hb-ot-shape-complex-arabic.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo `test -f 'hb-ot-shape-complex-arabic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-arabic.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-arabic.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-arabic.lo `test -f 'hb-ot-shape-complex-arabic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-arabic.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo: hb-ot-shape-complex-default.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo `test -f 'hb-ot-shape-complex-default.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-default.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-default.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-default.lo `test -f 'hb-ot-shape-complex-default.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-default.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo: hb-ot-shape-complex-hangul.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo `test -f 'hb-ot-shape-complex-hangul.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-hangul.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-hangul.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-hangul.lo `test -f 'hb-ot-shape-complex-hangul.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-hangul.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo: hb-ot-shape-complex-hebrew.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo `test -f 'hb-ot-shape-complex-hebrew.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-hebrew.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-hebrew.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-hebrew.lo `test -f 'hb-ot-shape-complex-hebrew.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-hebrew.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo: hb-ot-shape-complex-indic.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-indic.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo: hb-ot-shape-complex-indic-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo `test -f 'hb-ot-shape-complex-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-indic-table.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-indic-table.lo `test -f 'hb-ot-shape-complex-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic-table.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo: hb-ot-shape-complex-khmer.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo `test -f 'hb-ot-shape-complex-khmer.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-khmer.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-khmer.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-khmer.lo `test -f 'hb-ot-shape-complex-khmer.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-khmer.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo: hb-ot-shape-complex-myanmar.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo `test -f 'hb-ot-shape-complex-myanmar.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-myanmar.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-myanmar.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-myanmar.lo `test -f 'hb-ot-shape-complex-myanmar.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-myanmar.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo: hb-ot-shape-complex-thai.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo `test -f 'hb-ot-shape-complex-thai.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-thai.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-thai.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-thai.lo `test -f 'hb-ot-shape-complex-thai.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-thai.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo: hb-ot-shape-complex-tibetan.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo `test -f 'hb-ot-shape-complex-tibetan.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-tibetan.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-tibetan.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-tibetan.lo `test -f 'hb-ot-shape-complex-tibetan.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-tibetan.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo: hb-ot-shape-complex-use.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo `test -f 'hb-ot-shape-complex-use.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-use.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-use.lo `test -f 'hb-ot-shape-complex-use.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo: hb-ot-shape-complex-use-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-use-table.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo: hb-ot-shape-normalize.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-normalize.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo `test -f 'hb-ot-shape-normalize.cc' || echo '$(srcdir)/'`hb-ot-shape-normalize.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-normalize.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-normalize.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-normalize.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-normalize.lo `test -f 'hb-ot-shape-normalize.cc' || echo '$(srcdir)/'`hb-ot-shape-normalize.cc - -libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo: hb-ot-shape-fallback.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-fallback.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-fallback.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-shape-fallback.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-fallback.cc' object='libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc - -libharfbuzz_fuzzing_la-hb-ot-var.lo: hb-ot-var.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ot-var.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-var.Tpo -c -o libharfbuzz_fuzzing_la-hb-ot-var.lo `test -f 'hb-ot-var.cc' || echo '$(srcdir)/'`hb-ot-var.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-var.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ot-var.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-var.cc' object='libharfbuzz_fuzzing_la-hb-ot-var.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ot-var.lo `test -f 'hb-ot-var.cc' || echo '$(srcdir)/'`hb-ot-var.cc - -libharfbuzz_fuzzing_la-hb-fallback-shape.lo: hb-fallback-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-fallback-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-fallback-shape.Tpo -c -o libharfbuzz_fuzzing_la-hb-fallback-shape.lo `test -f 'hb-fallback-shape.cc' || echo '$(srcdir)/'`hb-fallback-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-fallback-shape.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-fallback-shape.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-fallback-shape.cc' object='libharfbuzz_fuzzing_la-hb-fallback-shape.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-fallback-shape.lo `test -f 'hb-fallback-shape.cc' || echo '$(srcdir)/'`hb-fallback-shape.cc - -libharfbuzz_fuzzing_la-hb-glib.lo: hb-glib.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-glib.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-glib.Tpo -c -o libharfbuzz_fuzzing_la-hb-glib.lo `test -f 'hb-glib.cc' || echo '$(srcdir)/'`hb-glib.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-glib.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-glib.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-glib.cc' object='libharfbuzz_fuzzing_la-hb-glib.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-glib.lo `test -f 'hb-glib.cc' || echo '$(srcdir)/'`hb-glib.cc - -libharfbuzz_fuzzing_la-hb-ft.lo: hb-ft.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ft.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ft.Tpo -c -o libharfbuzz_fuzzing_la-hb-ft.lo `test -f 'hb-ft.cc' || echo '$(srcdir)/'`hb-ft.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ft.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ft.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ft.cc' object='libharfbuzz_fuzzing_la-hb-ft.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ft.lo `test -f 'hb-ft.cc' || echo '$(srcdir)/'`hb-ft.cc - -libharfbuzz_fuzzing_la-hb-graphite2.lo: hb-graphite2.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-graphite2.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-graphite2.Tpo -c -o libharfbuzz_fuzzing_la-hb-graphite2.lo `test -f 'hb-graphite2.cc' || echo '$(srcdir)/'`hb-graphite2.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-graphite2.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-graphite2.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-graphite2.cc' object='libharfbuzz_fuzzing_la-hb-graphite2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-graphite2.lo `test -f 'hb-graphite2.cc' || echo '$(srcdir)/'`hb-graphite2.cc - -libharfbuzz_fuzzing_la-hb-uniscribe.lo: hb-uniscribe.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-uniscribe.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-uniscribe.Tpo -c -o libharfbuzz_fuzzing_la-hb-uniscribe.lo `test -f 'hb-uniscribe.cc' || echo '$(srcdir)/'`hb-uniscribe.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-uniscribe.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-uniscribe.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-uniscribe.cc' object='libharfbuzz_fuzzing_la-hb-uniscribe.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-uniscribe.lo `test -f 'hb-uniscribe.cc' || echo '$(srcdir)/'`hb-uniscribe.cc - -libharfbuzz_fuzzing_la-hb-directwrite.lo: hb-directwrite.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-directwrite.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-directwrite.Tpo -c -o libharfbuzz_fuzzing_la-hb-directwrite.lo `test -f 'hb-directwrite.cc' || echo '$(srcdir)/'`hb-directwrite.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-directwrite.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-directwrite.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-directwrite.cc' object='libharfbuzz_fuzzing_la-hb-directwrite.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-directwrite.lo `test -f 'hb-directwrite.cc' || echo '$(srcdir)/'`hb-directwrite.cc - -libharfbuzz_fuzzing_la-hb-coretext.lo: hb-coretext.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-coretext.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-coretext.Tpo -c -o libharfbuzz_fuzzing_la-hb-coretext.lo `test -f 'hb-coretext.cc' || echo '$(srcdir)/'`hb-coretext.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-coretext.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-coretext.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-coretext.cc' object='libharfbuzz_fuzzing_la-hb-coretext.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-coretext.lo `test -f 'hb-coretext.cc' || echo '$(srcdir)/'`hb-coretext.cc - -libharfbuzz_fuzzing_la-hb-ucdn.lo: hb-ucdn.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-ucdn.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ucdn.Tpo -c -o libharfbuzz_fuzzing_la-hb-ucdn.lo `test -f 'hb-ucdn.cc' || echo '$(srcdir)/'`hb-ucdn.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ucdn.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-ucdn.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ucdn.cc' object='libharfbuzz_fuzzing_la-hb-ucdn.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-ucdn.lo `test -f 'hb-ucdn.cc' || echo '$(srcdir)/'`hb-ucdn.cc - -libharfbuzz_fuzzing_la-hb-icu.lo: hb-icu.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_fuzzing_la-hb-icu.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_fuzzing_la-hb-icu.Tpo -c -o libharfbuzz_fuzzing_la-hb-icu.lo `test -f 'hb-icu.cc' || echo '$(srcdir)/'`hb-icu.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_fuzzing_la-hb-icu.Tpo $(DEPDIR)/libharfbuzz_fuzzing_la-hb-icu.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-icu.cc' object='libharfbuzz_fuzzing_la-hb-icu.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_fuzzing_la-hb-icu.lo `test -f 'hb-icu.cc' || echo '$(srcdir)/'`hb-icu.cc - libharfbuzz_gobject_la-hb-gobject-structs.lo: hb-gobject-structs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_gobject_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_gobject_la-hb-gobject-structs.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Tpo -c -o libharfbuzz_gobject_la-hb-gobject-structs.lo `test -f 'hb-gobject-structs.cc' || echo '$(srcdir)/'`hb-gobject-structs.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Tpo $(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo @@ -2293,40 +1816,19 @@ libharfbuzz_icu_la-hb-icu.lo: hb-icu.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_icu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_icu_la-hb-icu.lo `test -f 'hb-icu.cc' || echo '$(srcdir)/'`hb-icu.cc -libharfbuzz_subset_fuzzing_la-hb-static.lo: hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_fuzzing_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-static.Tpo -c -o libharfbuzz_subset_fuzzing_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-static.Tpo $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-static.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='libharfbuzz_subset_fuzzing_la-hb-static.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_fuzzing_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc - -libharfbuzz_subset_fuzzing_la-hb-subset.lo: hb-subset.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_fuzzing_la-hb-subset.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset.Tpo -c -o libharfbuzz_subset_fuzzing_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset.Tpo $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset.cc' object='libharfbuzz_subset_fuzzing_la-hb-subset.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_fuzzing_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc - -libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo: hb-subset-glyf.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-glyf.Tpo -c -o libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo `test -f 'hb-subset-glyf.cc' || echo '$(srcdir)/'`hb-subset-glyf.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-glyf.Tpo $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-glyf.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-glyf.cc' object='libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_subset_la-hb-ot-cff1-table.lo: hb-ot-cff1-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-ot-cff1-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Tpo -c -o libharfbuzz_subset_la-hb-ot-cff1-table.lo `test -f 'hb-ot-cff1-table.cc' || echo '$(srcdir)/'`hb-ot-cff1-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-cff1-table.cc' object='libharfbuzz_subset_la-hb-ot-cff1-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_fuzzing_la-hb-subset-glyf.lo `test -f 'hb-subset-glyf.cc' || echo '$(srcdir)/'`hb-subset-glyf.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-ot-cff1-table.lo `test -f 'hb-ot-cff1-table.cc' || echo '$(srcdir)/'`hb-ot-cff1-table.cc -libharfbuzz_subset_fuzzing_la-hb-subset-input.lo: hb-subset-input.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_fuzzing_la-hb-subset-input.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-input.Tpo -c -o libharfbuzz_subset_fuzzing_la-hb-subset-input.lo `test -f 'hb-subset-input.cc' || echo '$(srcdir)/'`hb-subset-input.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-input.Tpo $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-input.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-input.cc' object='libharfbuzz_subset_fuzzing_la-hb-subset-input.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_subset_la-hb-ot-cff2-table.lo: hb-ot-cff2-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-ot-cff2-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Tpo -c -o libharfbuzz_subset_la-hb-ot-cff2-table.lo `test -f 'hb-ot-cff2-table.cc' || echo '$(srcdir)/'`hb-ot-cff2-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-cff2-table.cc' object='libharfbuzz_subset_la-hb-ot-cff2-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_fuzzing_la-hb-subset-input.lo `test -f 'hb-subset-input.cc' || echo '$(srcdir)/'`hb-subset-input.cc - -libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo: hb-subset-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-plan.Tpo -c -o libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo `test -f 'hb-subset-plan.cc' || echo '$(srcdir)/'`hb-subset-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-plan.Tpo $(DEPDIR)/libharfbuzz_subset_fuzzing_la-hb-subset-plan.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-plan.cc' object='libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_fuzzing_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_fuzzing_la-hb-subset-plan.lo `test -f 'hb-subset-plan.cc' || echo '$(srcdir)/'`hb-subset-plan.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-ot-cff2-table.lo `test -f 'hb-ot-cff2-table.cc' || echo '$(srcdir)/'`hb-ot-cff2-table.cc libharfbuzz_subset_la-hb-static.lo: hb-static.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-static.Tpo -c -o libharfbuzz_subset_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc @@ -2335,12 +1837,26 @@ libharfbuzz_subset_la-hb-static.lo: hb-static.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc -libharfbuzz_subset_la-hb-subset.lo: hb-subset.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Tpo -c -o libharfbuzz_subset_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset.cc' object='libharfbuzz_subset_la-hb-subset.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_subset_la-hb-subset-cff-common.lo: hb-subset-cff-common.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset-cff-common.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff-common.Tpo -c -o libharfbuzz_subset_la-hb-subset-cff-common.lo `test -f 'hb-subset-cff-common.cc' || echo '$(srcdir)/'`hb-subset-cff-common.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff-common.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff-common.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-cff-common.cc' object='libharfbuzz_subset_la-hb-subset-cff-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset-cff-common.lo `test -f 'hb-subset-cff-common.cc' || echo '$(srcdir)/'`hb-subset-cff-common.cc + +libharfbuzz_subset_la-hb-subset-cff1.lo: hb-subset-cff1.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset-cff1.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Tpo -c -o libharfbuzz_subset_la-hb-subset-cff1.lo `test -f 'hb-subset-cff1.cc' || echo '$(srcdir)/'`hb-subset-cff1.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-cff1.cc' object='libharfbuzz_subset_la-hb-subset-cff1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset-cff1.lo `test -f 'hb-subset-cff1.cc' || echo '$(srcdir)/'`hb-subset-cff1.cc + +libharfbuzz_subset_la-hb-subset-cff2.lo: hb-subset-cff2.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset-cff2.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Tpo -c -o libharfbuzz_subset_la-hb-subset-cff2.lo `test -f 'hb-subset-cff2.cc' || echo '$(srcdir)/'`hb-subset-cff2.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset-cff2.cc' object='libharfbuzz_subset_la-hb-subset-cff2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset-cff2.lo `test -f 'hb-subset-cff2.cc' || echo '$(srcdir)/'`hb-subset-cff2.cc libharfbuzz_subset_la-hb-subset-glyf.lo: hb-subset-glyf.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset-glyf.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-glyf.Tpo -c -o libharfbuzz_subset_la-hb-subset-glyf.lo `test -f 'hb-subset-glyf.cc' || echo '$(srcdir)/'`hb-subset-glyf.cc @@ -2363,6 +1879,27 @@ libharfbuzz_subset_la-hb-subset-plan.lo: hb-subset-plan.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset-plan.lo `test -f 'hb-subset-plan.cc' || echo '$(srcdir)/'`hb-subset-plan.cc +libharfbuzz_subset_la-hb-subset.lo: hb-subset.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Tpo -c -o libharfbuzz_subset_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-subset.cc' object='libharfbuzz_subset_la-hb-subset.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_subset_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_subset_la-hb-subset.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc + +libharfbuzz_la-hb-aat-layout.lo: hb-aat-layout.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-aat-layout.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Tpo -c -o libharfbuzz_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Tpo $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-aat-layout.cc' object='libharfbuzz_la-hb-aat-layout.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc + +libharfbuzz_la-hb-aat-map.lo: hb-aat-map.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-aat-map.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-aat-map.Tpo -c -o libharfbuzz_la-hb-aat-map.lo `test -f 'hb-aat-map.cc' || echo '$(srcdir)/'`hb-aat-map.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-aat-map.Tpo $(DEPDIR)/libharfbuzz_la-hb-aat-map.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-aat-map.cc' object='libharfbuzz_la-hb-aat-map.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-aat-map.lo `test -f 'hb-aat-map.cc' || echo '$(srcdir)/'`hb-aat-map.cc + libharfbuzz_la-hb-blob.lo: hb-blob.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-blob.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-blob.Tpo -c -o libharfbuzz_la-hb-blob.lo `test -f 'hb-blob.cc' || echo '$(srcdir)/'`hb-blob.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-blob.Tpo $(DEPDIR)/libharfbuzz_la-hb-blob.Plo @@ -2412,68 +1949,33 @@ libharfbuzz_la-hb-map.lo: hb-map.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-map.lo `test -f 'hb-map.cc' || echo '$(srcdir)/'`hb-map.cc -libharfbuzz_la-hb-ot-tag.lo: hb-ot-tag.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-tag.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Tpo -c -o libharfbuzz_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-tag.cc' object='libharfbuzz_la-hb-ot-tag.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc - -libharfbuzz_la-hb-set.lo: hb-set.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-set.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-set.Tpo -c -o libharfbuzz_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-set.Tpo $(DEPDIR)/libharfbuzz_la-hb-set.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-set.cc' object='libharfbuzz_la-hb-set.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc - -libharfbuzz_la-hb-shape.lo: hb-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shape.Tpo -c -o libharfbuzz_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-shape.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape.cc' object='libharfbuzz_la-hb-shape.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-cff1-table.lo: hb-ot-cff1-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-cff1-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-cff1-table.Tpo -c -o libharfbuzz_la-hb-ot-cff1-table.lo `test -f 'hb-ot-cff1-table.cc' || echo '$(srcdir)/'`hb-ot-cff1-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-cff1-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-cff1-table.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-cff1-table.cc' object='libharfbuzz_la-hb-ot-cff1-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-cff1-table.lo `test -f 'hb-ot-cff1-table.cc' || echo '$(srcdir)/'`hb-ot-cff1-table.cc -libharfbuzz_la-hb-shape-plan.lo: hb-shape-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shape-plan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Tpo -c -o libharfbuzz_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Tpo $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape-plan.cc' object='libharfbuzz_la-hb-shape-plan.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-cff2-table.lo: hb-ot-cff2-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-cff2-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-cff2-table.Tpo -c -o libharfbuzz_la-hb-ot-cff2-table.lo `test -f 'hb-ot-cff2-table.cc' || echo '$(srcdir)/'`hb-ot-cff2-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-cff2-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-cff2-table.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-cff2-table.cc' object='libharfbuzz_la-hb-ot-cff2-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-cff2-table.lo `test -f 'hb-ot-cff2-table.cc' || echo '$(srcdir)/'`hb-ot-cff2-table.cc -libharfbuzz_la-hb-shaper.lo: hb-shaper.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shaper.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shaper.Tpo -c -o libharfbuzz_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shaper.Tpo $(DEPDIR)/libharfbuzz_la-hb-shaper.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shaper.cc' object='libharfbuzz_la-hb-shaper.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc - -libharfbuzz_la-hb-static.lo: hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-static.Tpo -c -o libharfbuzz_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-static.Tpo $(DEPDIR)/libharfbuzz_la-hb-static.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='libharfbuzz_la-hb-static.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc - -libharfbuzz_la-hb-unicode.lo: hb-unicode.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-unicode.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-unicode.Tpo -c -o libharfbuzz_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-unicode.Tpo $(DEPDIR)/libharfbuzz_la-hb-unicode.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-unicode.cc' object='libharfbuzz_la-hb-unicode.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc - -libharfbuzz_la-hb-warning.lo: hb-warning.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-warning.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-warning.Tpo -c -o libharfbuzz_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-warning.Tpo $(DEPDIR)/libharfbuzz_la-hb-warning.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-warning.cc' object='libharfbuzz_la-hb-warning.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-color.lo: hb-ot-color.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-color.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-color.Tpo -c -o libharfbuzz_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-color.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-color.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-color.cc' object='libharfbuzz_la-hb-ot-color.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc -libharfbuzz_la-hb-aat-layout.lo: hb-aat-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-aat-layout.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Tpo -c -o libharfbuzz_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Tpo $(DEPDIR)/libharfbuzz_la-hb-aat-layout.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-aat-layout.cc' object='libharfbuzz_la-hb-aat-layout.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-face.lo: hb-ot-face.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-face.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-face.Tpo -c -o libharfbuzz_la-hb-ot-face.lo `test -f 'hb-ot-face.cc' || echo '$(srcdir)/'`hb-ot-face.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-face.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-face.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-face.cc' object='libharfbuzz_la-hb-ot-face.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-aat-layout.lo `test -f 'hb-aat-layout.cc' || echo '$(srcdir)/'`hb-aat-layout.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-face.lo `test -f 'hb-ot-face.cc' || echo '$(srcdir)/'`hb-ot-face.cc libharfbuzz_la-hb-ot-font.lo: hb-ot-font.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-font.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-font.Tpo -c -o libharfbuzz_la-hb-ot-font.lo `test -f 'hb-ot-font.cc' || echo '$(srcdir)/'`hb-ot-font.cc @@ -2489,13 +1991,6 @@ libharfbuzz_la-hb-ot-layout.lo: hb-ot-layout.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-layout.lo `test -f 'hb-ot-layout.cc' || echo '$(srcdir)/'`hb-ot-layout.cc -libharfbuzz_la-hb-ot-color.lo: hb-ot-color.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-color.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-color.Tpo -c -o libharfbuzz_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-color.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-color.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-color.cc' object='libharfbuzz_la-hb-ot-color.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-color.lo `test -f 'hb-ot-color.cc' || echo '$(srcdir)/'`hb-ot-color.cc - libharfbuzz_la-hb-ot-map.lo: hb-ot-map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-map.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-map.Tpo -c -o libharfbuzz_la-hb-ot-map.lo `test -f 'hb-ot-map.cc' || echo '$(srcdir)/'`hb-ot-map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-map.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-map.Plo @@ -2510,12 +2005,19 @@ libharfbuzz_la-hb-ot-math.lo: hb-ot-math.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-math.lo `test -f 'hb-ot-math.cc' || echo '$(srcdir)/'`hb-ot-math.cc -libharfbuzz_la-hb-ot-shape.lo: hb-ot-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Tpo -c -o libharfbuzz_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape.cc' object='libharfbuzz_la-hb-ot-shape.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-name-language.lo: hb-ot-name-language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-name-language.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-name-language.Tpo -c -o libharfbuzz_la-hb-ot-name-language.lo `test -f 'hb-ot-name-language.cc' || echo '$(srcdir)/'`hb-ot-name-language.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-name-language.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-name-language.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-name-language.cc' object='libharfbuzz_la-hb-ot-name-language.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-name-language.lo `test -f 'hb-ot-name-language.cc' || echo '$(srcdir)/'`hb-ot-name-language.cc + +libharfbuzz_la-hb-ot-name.lo: hb-ot-name.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-name.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-name.Tpo -c -o libharfbuzz_la-hb-ot-name.lo `test -f 'hb-ot-name.cc' || echo '$(srcdir)/'`hb-ot-name.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-name.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-name.cc' object='libharfbuzz_la-hb-ot-name.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-name.lo `test -f 'hb-ot-name.cc' || echo '$(srcdir)/'`hb-ot-name.cc libharfbuzz_la-hb-ot-shape-complex-arabic.lo: hb-ot-shape-complex-arabic.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-arabic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-arabic.lo `test -f 'hb-ot-shape-complex-arabic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-arabic.cc @@ -2545,13 +2047,6 @@ libharfbuzz_la-hb-ot-shape-complex-hebrew.lo: hb-ot-shape-complex-hebrew.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-hebrew.lo `test -f 'hb-ot-shape-complex-hebrew.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-hebrew.cc -libharfbuzz_la-hb-ot-shape-complex-indic.lo: hb-ot-shape-complex-indic.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-indic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-indic.cc' object='libharfbuzz_la-hb-ot-shape-complex-indic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc - libharfbuzz_la-hb-ot-shape-complex-indic-table.lo: hb-ot-shape-complex-indic-table.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-indic-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-indic-table.lo `test -f 'hb-ot-shape-complex-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic-table.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Plo @@ -2559,6 +2054,13 @@ libharfbuzz_la-hb-ot-shape-complex-indic-table.lo: hb-ot-shape-complex-indic-tab @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-indic-table.lo `test -f 'hb-ot-shape-complex-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic-table.cc +libharfbuzz_la-hb-ot-shape-complex-indic.lo: hb-ot-shape-complex-indic.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-indic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-indic.cc' object='libharfbuzz_la-hb-ot-shape-complex-indic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-indic.lo `test -f 'hb-ot-shape-complex-indic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-indic.cc + libharfbuzz_la-hb-ot-shape-complex-khmer.lo: hb-ot-shape-complex-khmer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-khmer.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-khmer.lo `test -f 'hb-ot-shape-complex-khmer.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-khmer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo @@ -2580,12 +2082,12 @@ libharfbuzz_la-hb-ot-shape-complex-thai.lo: hb-ot-shape-complex-thai.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-thai.lo `test -f 'hb-ot-shape-complex-thai.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-thai.cc -libharfbuzz_la-hb-ot-shape-complex-tibetan.lo: hb-ot-shape-complex-tibetan.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-tibetan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-tibetan.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-tibetan.lo `test -f 'hb-ot-shape-complex-tibetan.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-tibetan.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-tibetan.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-tibetan.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-tibetan.cc' object='libharfbuzz_la-hb-ot-shape-complex-tibetan.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-shape-complex-use-table.lo: hb-ot-shape-complex-use-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-use-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-use-table.cc' object='libharfbuzz_la-hb-ot-shape-complex-use-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-tibetan.lo `test -f 'hb-ot-shape-complex-tibetan.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-tibetan.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc libharfbuzz_la-hb-ot-shape-complex-use.lo: hb-ot-shape-complex-use.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-use.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-use.lo `test -f 'hb-ot-shape-complex-use.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use.cc @@ -2594,12 +2096,19 @@ libharfbuzz_la-hb-ot-shape-complex-use.lo: hb-ot-shape-complex-use.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-use.lo `test -f 'hb-ot-shape-complex-use.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use.cc -libharfbuzz_la-hb-ot-shape-complex-use-table.lo: hb-ot-shape-complex-use-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-use-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use-table.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-use-table.cc' object='libharfbuzz_la-hb-ot-shape-complex-use-table.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo: hb-ot-shape-complex-vowel-constraints.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo `test -f 'hb-ot-shape-complex-vowel-constraints.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-vowel-constraints.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-complex-vowel-constraints.cc' object='libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-use-table.lo `test -f 'hb-ot-shape-complex-use-table.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-use-table.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo `test -f 'hb-ot-shape-complex-vowel-constraints.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-vowel-constraints.cc + +libharfbuzz_la-hb-ot-shape-fallback.lo: hb-ot-shape-fallback.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-fallback.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Tpo -c -o libharfbuzz_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-fallback.cc' object='libharfbuzz_la-hb-ot-shape-fallback.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc libharfbuzz_la-hb-ot-shape-normalize.lo: hb-ot-shape-normalize.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-normalize.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Tpo -c -o libharfbuzz_la-hb-ot-shape-normalize.lo `test -f 'hb-ot-shape-normalize.cc' || echo '$(srcdir)/'`hb-ot-shape-normalize.cc @@ -2608,12 +2117,19 @@ libharfbuzz_la-hb-ot-shape-normalize.lo: hb-ot-shape-normalize.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-normalize.lo `test -f 'hb-ot-shape-normalize.cc' || echo '$(srcdir)/'`hb-ot-shape-normalize.cc -libharfbuzz_la-hb-ot-shape-fallback.lo: hb-ot-shape-fallback.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-fallback.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Tpo -c -o libharfbuzz_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape-fallback.cc' object='libharfbuzz_la-hb-ot-shape-fallback.lo' libtool=yes @AMDEPBACKSLASH@ +libharfbuzz_la-hb-ot-shape.lo: hb-ot-shape.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Tpo -c -o libharfbuzz_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-shape.cc' object='libharfbuzz_la-hb-ot-shape.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape-fallback.lo `test -f 'hb-ot-shape-fallback.cc' || echo '$(srcdir)/'`hb-ot-shape-fallback.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-shape.lo `test -f 'hb-ot-shape.cc' || echo '$(srcdir)/'`hb-ot-shape.cc + +libharfbuzz_la-hb-ot-tag.lo: hb-ot-tag.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-tag.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Tpo -c -o libharfbuzz_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-ot-tag.cc' object='libharfbuzz_la-hb-ot-tag.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-tag.lo `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc libharfbuzz_la-hb-ot-var.lo: hb-ot-var.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-var.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-var.Tpo -c -o libharfbuzz_la-hb-ot-var.lo `test -f 'hb-ot-var.cc' || echo '$(srcdir)/'`hb-ot-var.cc @@ -2622,6 +2138,55 @@ libharfbuzz_la-hb-ot-var.lo: hb-ot-var.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-ot-var.lo `test -f 'hb-ot-var.cc' || echo '$(srcdir)/'`hb-ot-var.cc +libharfbuzz_la-hb-set.lo: hb-set.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-set.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-set.Tpo -c -o libharfbuzz_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-set.Tpo $(DEPDIR)/libharfbuzz_la-hb-set.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-set.cc' object='libharfbuzz_la-hb-set.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-set.lo `test -f 'hb-set.cc' || echo '$(srcdir)/'`hb-set.cc + +libharfbuzz_la-hb-shape-plan.lo: hb-shape-plan.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shape-plan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Tpo -c -o libharfbuzz_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Tpo $(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape-plan.cc' object='libharfbuzz_la-hb-shape-plan.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shape-plan.lo `test -f 'hb-shape-plan.cc' || echo '$(srcdir)/'`hb-shape-plan.cc + +libharfbuzz_la-hb-shape.lo: hb-shape.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shape.Tpo -c -o libharfbuzz_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-shape.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shape.cc' object='libharfbuzz_la-hb-shape.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shape.lo `test -f 'hb-shape.cc' || echo '$(srcdir)/'`hb-shape.cc + +libharfbuzz_la-hb-shaper.lo: hb-shaper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-shaper.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-shaper.Tpo -c -o libharfbuzz_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-shaper.Tpo $(DEPDIR)/libharfbuzz_la-hb-shaper.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-shaper.cc' object='libharfbuzz_la-hb-shaper.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-shaper.lo `test -f 'hb-shaper.cc' || echo '$(srcdir)/'`hb-shaper.cc + +libharfbuzz_la-hb-static.lo: hb-static.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-static.Tpo -c -o libharfbuzz_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-static.Tpo $(DEPDIR)/libharfbuzz_la-hb-static.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='libharfbuzz_la-hb-static.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc + +libharfbuzz_la-hb-unicode.lo: hb-unicode.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-unicode.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-unicode.Tpo -c -o libharfbuzz_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-unicode.Tpo $(DEPDIR)/libharfbuzz_la-hb-unicode.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-unicode.cc' object='libharfbuzz_la-hb-unicode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-unicode.lo `test -f 'hb-unicode.cc' || echo '$(srcdir)/'`hb-unicode.cc + +libharfbuzz_la-hb-warning.lo: hb-warning.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-warning.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-warning.Tpo -c -o libharfbuzz_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-warning.Tpo $(DEPDIR)/libharfbuzz_la-hb-warning.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-warning.cc' object='libharfbuzz_la-hb-warning.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-warning.lo `test -f 'hb-warning.cc' || echo '$(srcdir)/'`hb-warning.cc + libharfbuzz_la-hb-fallback-shape.lo: hb-fallback-shape.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-fallback-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Tpo -c -o libharfbuzz_la-hb-fallback-shape.lo `test -f 'hb-fallback-shape.cc' || echo '$(srcdir)/'`hb-fallback-shape.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Plo @@ -2685,34 +2250,6 @@ libharfbuzz_la-hb-icu.lo: hb-icu.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_la-hb-icu.lo `test -f 'hb-icu.cc' || echo '$(srcdir)/'`hb-icu.cc -dump_emoji-dump-emoji.o: dump-emoji.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_emoji_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dump_emoji-dump-emoji.o -MD -MP -MF $(DEPDIR)/dump_emoji-dump-emoji.Tpo -c -o dump_emoji-dump-emoji.o `test -f 'dump-emoji.cc' || echo '$(srcdir)/'`dump-emoji.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dump_emoji-dump-emoji.Tpo $(DEPDIR)/dump_emoji-dump-emoji.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dump-emoji.cc' object='dump_emoji-dump-emoji.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_emoji_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dump_emoji-dump-emoji.o `test -f 'dump-emoji.cc' || echo '$(srcdir)/'`dump-emoji.cc - -dump_emoji-dump-emoji.obj: dump-emoji.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_emoji_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dump_emoji-dump-emoji.obj -MD -MP -MF $(DEPDIR)/dump_emoji-dump-emoji.Tpo -c -o dump_emoji-dump-emoji.obj `if test -f 'dump-emoji.cc'; then $(CYGPATH_W) 'dump-emoji.cc'; else $(CYGPATH_W) '$(srcdir)/dump-emoji.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dump_emoji-dump-emoji.Tpo $(DEPDIR)/dump_emoji-dump-emoji.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dump-emoji.cc' object='dump_emoji-dump-emoji.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_emoji_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dump_emoji-dump-emoji.obj `if test -f 'dump-emoji.cc'; then $(CYGPATH_W) 'dump-emoji.cc'; else $(CYGPATH_W) '$(srcdir)/dump-emoji.cc'; fi` - -dump_fon-dump-fon.o: dump-fon.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_fon_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dump_fon-dump-fon.o -MD -MP -MF $(DEPDIR)/dump_fon-dump-fon.Tpo -c -o dump_fon-dump-fon.o `test -f 'dump-fon.cc' || echo '$(srcdir)/'`dump-fon.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dump_fon-dump-fon.Tpo $(DEPDIR)/dump_fon-dump-fon.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dump-fon.cc' object='dump_fon-dump-fon.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_fon_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dump_fon-dump-fon.o `test -f 'dump-fon.cc' || echo '$(srcdir)/'`dump-fon.cc - -dump_fon-dump-fon.obj: dump-fon.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_fon_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dump_fon-dump-fon.obj -MD -MP -MF $(DEPDIR)/dump_fon-dump-fon.Tpo -c -o dump_fon-dump-fon.obj `if test -f 'dump-fon.cc'; then $(CYGPATH_W) 'dump-fon.cc'; else $(CYGPATH_W) '$(srcdir)/dump-fon.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dump_fon-dump-fon.Tpo $(DEPDIR)/dump_fon-dump-fon.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dump-fon.cc' object='dump_fon-dump-fon.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_fon_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dump_fon-dump-fon.obj `if test -f 'dump-fon.cc'; then $(CYGPATH_W) 'dump-fon.cc'; else $(CYGPATH_W) '$(srcdir)/dump-fon.cc'; fi` - dump_indic_data-dump-indic-data.o: dump-indic-data.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dump_indic_data_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dump_indic_data-dump-indic-data.o -MD -MP -MF $(DEPDIR)/dump_indic_data-dump-indic-data.Tpo -c -o dump_indic_data-dump-indic-data.o `test -f 'dump-indic-data.cc' || echo '$(srcdir)/'`dump-indic-data.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dump_indic_data-dump-indic-data.Tpo $(DEPDIR)/dump_indic_data-dump-indic-data.Po @@ -2867,6 +2404,62 @@ test_buffer_serialize-test-buffer-serialize.obj: test-buffer-serialize.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_buffer_serialize_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_buffer_serialize-test-buffer-serialize.obj `if test -f 'test-buffer-serialize.cc'; then $(CYGPATH_W) 'test-buffer-serialize.cc'; else $(CYGPATH_W) '$(srcdir)/test-buffer-serialize.cc'; fi` +test_iter-test-iter.o: test-iter.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_iter-test-iter.o -MD -MP -MF $(DEPDIR)/test_iter-test-iter.Tpo -c -o test_iter-test-iter.o `test -f 'test-iter.cc' || echo '$(srcdir)/'`test-iter.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_iter-test-iter.Tpo $(DEPDIR)/test_iter-test-iter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-iter.cc' object='test_iter-test-iter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_iter-test-iter.o `test -f 'test-iter.cc' || echo '$(srcdir)/'`test-iter.cc + +test_iter-test-iter.obj: test-iter.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_iter-test-iter.obj -MD -MP -MF $(DEPDIR)/test_iter-test-iter.Tpo -c -o test_iter-test-iter.obj `if test -f 'test-iter.cc'; then $(CYGPATH_W) 'test-iter.cc'; else $(CYGPATH_W) '$(srcdir)/test-iter.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_iter-test-iter.Tpo $(DEPDIR)/test_iter-test-iter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-iter.cc' object='test_iter-test-iter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_iter-test-iter.obj `if test -f 'test-iter.cc'; then $(CYGPATH_W) 'test-iter.cc'; else $(CYGPATH_W) '$(srcdir)/test-iter.cc'; fi` + +test_iter-hb-static.o: hb-static.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_iter-hb-static.o -MD -MP -MF $(DEPDIR)/test_iter-hb-static.Tpo -c -o test_iter-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_iter-hb-static.Tpo $(DEPDIR)/test_iter-hb-static.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='test_iter-hb-static.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_iter-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc + +test_iter-hb-static.obj: hb-static.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_iter-hb-static.obj -MD -MP -MF $(DEPDIR)/test_iter-hb-static.Tpo -c -o test_iter-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_iter-hb-static.Tpo $(DEPDIR)/test_iter-hb-static.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hb-static.cc' object='test_iter-hb-static.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_iter-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi` + +test_name_table-test-name-table.o: test-name-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_name_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_name_table-test-name-table.o -MD -MP -MF $(DEPDIR)/test_name_table-test-name-table.Tpo -c -o test_name_table-test-name-table.o `test -f 'test-name-table.cc' || echo '$(srcdir)/'`test-name-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_name_table-test-name-table.Tpo $(DEPDIR)/test_name_table-test-name-table.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-name-table.cc' object='test_name_table-test-name-table.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_name_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_name_table-test-name-table.o `test -f 'test-name-table.cc' || echo '$(srcdir)/'`test-name-table.cc + +test_name_table-test-name-table.obj: test-name-table.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_name_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_name_table-test-name-table.obj -MD -MP -MF $(DEPDIR)/test_name_table-test-name-table.Tpo -c -o test_name_table-test-name-table.obj `if test -f 'test-name-table.cc'; then $(CYGPATH_W) 'test-name-table.cc'; else $(CYGPATH_W) '$(srcdir)/test-name-table.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_name_table-test-name-table.Tpo $(DEPDIR)/test_name_table-test-name-table.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-name-table.cc' object='test_name_table-test-name-table.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_name_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_name_table-test-name-table.obj `if test -f 'test-name-table.cc'; then $(CYGPATH_W) 'test-name-table.cc'; else $(CYGPATH_W) '$(srcdir)/test-name-table.cc'; fi` + +test_ot_color-test-ot-color.o: test-ot-color.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_color_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_ot_color-test-ot-color.o -MD -MP -MF $(DEPDIR)/test_ot_color-test-ot-color.Tpo -c -o test_ot_color-test-ot-color.o `test -f 'test-ot-color.cc' || echo '$(srcdir)/'`test-ot-color.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_ot_color-test-ot-color.Tpo $(DEPDIR)/test_ot_color-test-ot-color.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-ot-color.cc' object='test_ot_color-test-ot-color.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_color_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_ot_color-test-ot-color.o `test -f 'test-ot-color.cc' || echo '$(srcdir)/'`test-ot-color.cc + +test_ot_color-test-ot-color.obj: test-ot-color.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_color_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_ot_color-test-ot-color.obj -MD -MP -MF $(DEPDIR)/test_ot_color-test-ot-color.Tpo -c -o test_ot_color-test-ot-color.obj `if test -f 'test-ot-color.cc'; then $(CYGPATH_W) 'test-ot-color.cc'; else $(CYGPATH_W) '$(srcdir)/test-ot-color.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_ot_color-test-ot-color.Tpo $(DEPDIR)/test_ot_color-test-ot-color.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-ot-color.cc' object='test_ot_color-test-ot-color.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_color_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_ot_color-test-ot-color.obj `if test -f 'test-ot-color.cc'; then $(CYGPATH_W) 'test-ot-color.cc'; else $(CYGPATH_W) '$(srcdir)/test-ot-color.cc'; fi` + test_ot_tag-hb-ot-tag.o: hb-ot-tag.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_tag_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_ot_tag-hb-ot-tag.o -MD -MP -MF $(DEPDIR)/test_ot_tag-hb-ot-tag.Tpo -c -o test_ot_tag-hb-ot-tag.o `test -f 'hb-ot-tag.cc' || echo '$(srcdir)/'`hb-ot-tag.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_ot_tag-hb-ot-tag.Tpo $(DEPDIR)/test_ot_tag-hb-ot-tag.Po @@ -2895,6 +2488,20 @@ test_size_params-test-size-params.obj: test-size-params.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_size_params_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_size_params-test-size-params.obj `if test -f 'test-size-params.cc'; then $(CYGPATH_W) 'test-size-params.cc'; else $(CYGPATH_W) '$(srcdir)/test-size-params.cc'; fi` +test_unicode_ranges-test-unicode-ranges.o: test-unicode-ranges.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_unicode_ranges_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_unicode_ranges-test-unicode-ranges.o -MD -MP -MF $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Tpo -c -o test_unicode_ranges-test-unicode-ranges.o `test -f 'test-unicode-ranges.cc' || echo '$(srcdir)/'`test-unicode-ranges.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Tpo $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-unicode-ranges.cc' object='test_unicode_ranges-test-unicode-ranges.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_unicode_ranges_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_unicode_ranges-test-unicode-ranges.o `test -f 'test-unicode-ranges.cc' || echo '$(srcdir)/'`test-unicode-ranges.cc + +test_unicode_ranges-test-unicode-ranges.obj: test-unicode-ranges.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_unicode_ranges_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_unicode_ranges-test-unicode-ranges.obj -MD -MP -MF $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Tpo -c -o test_unicode_ranges-test-unicode-ranges.obj `if test -f 'test-unicode-ranges.cc'; then $(CYGPATH_W) 'test-unicode-ranges.cc'; else $(CYGPATH_W) '$(srcdir)/test-unicode-ranges.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Tpo $(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test-unicode-ranges.cc' object='test_unicode_ranges-test-unicode-ranges.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_unicode_ranges_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_unicode_ranges-test-unicode-ranges.obj `if test -f 'test-unicode-ranges.cc'; then $(CYGPATH_W) 'test-unicode-ranges.cc'; else $(CYGPATH_W) '$(srcdir)/test-unicode-ranges.cc'; fi` + test_would_substitute-test-would-substitute.o: test-would-substitute.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_would_substitute_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_would_substitute-test-would-substitute.o -MD -MP -MF $(DEPDIR)/test_would_substitute-test-would-substitute.Tpo -c -o test_would_substitute-test-would-substitute.o `test -f 'test-would-substitute.cc' || echo '$(srcdir)/'`test-would-substitute.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_would_substitute-test-would-substitute.Tpo $(DEPDIR)/test_would_substitute-test-would-substitute.Po @@ -3330,6 +2937,13 @@ check-libstdc++.sh.log: check-libstdc++.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +test-iter.log: test-iter$(EXEEXT) + @p='test-iter$(EXEEXT)'; \ + b='test-iter'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) test-ot-tag.log: test-ot-tag$(EXEEXT) @p='test-ot-tag$(EXEEXT)'; \ b='test-ot-tag'; \ @@ -3573,8 +3187,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-cmakeDATA \ # Convenience targets: -lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la -fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la +lib: $(BUILT_SOURCES) libharfbuzz.la +libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) @HAVE_UCDN_TRUE@hb-ucdn/libhb-ucdn.la: ucdn @HAVE_UCDN_TRUE@ucdn: @HAVE_UCDN_TRUE@ @$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn @@ -3608,15 +3222,17 @@ $(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac || ($(RM) "$@"; false) check: $(DEF_FILES) # For check-symbols.sh harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-subset.def: $(HB_SUBSET_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-icu.def: $(HB_ICU_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-gobject.def: $(HB_GOBJECT_headers) - $(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@" + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ +harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h + $(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^ -unicode-tables: arabic-table indic-table use-table +unicode-tables: arabic-table indic-table tag-table use-table emoji-table arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \ @@ -3626,13 +3242,25 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategor $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false) +tag-table: gen-tag-table.py languagetags language-subtag-registry + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \ + || ($(RM) $(srcdir)/hb-ot-tag-table.hh; false) + use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false) +vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \ + || ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false) + +emoji-table: gen-emoji-table.py emoji-data.txt + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ + || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) + built-sources: $(BUILT_SOURCES) -.PHONY: unicode-tables arabic-table indic-table use-table built-sources +.PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-table built-sources # We decided to add ragel-generated files to git... #MAINTAINERCLEANFILES += $(RAGEL_GENERATED) $(srcdir)/%.hh: $(srcdir)/%.rl diff --git a/src/Makefile.sources b/src/Makefile.sources index 0bc9e58..0da4abe 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -1,70 +1,173 @@ # Base and default-included sources and headers HB_BASE_sources = \ - hb-atomic-private.hh \ - hb-blob-private.hh \ + hb-aat-fdsc-table.hh \ + hb-aat-layout-ankr-table.hh \ + hb-aat-layout-bsln-table.hh \ + hb-aat-layout-common.hh \ + hb-aat-layout-feat-table.hh \ + hb-aat-layout-just-table.hh \ + hb-aat-layout-kerx-table.hh \ + hb-aat-layout-lcar-table.hh \ + hb-aat-layout-morx-table.hh \ + hb-aat-layout-trak-table.hh \ + hb-aat-layout.cc \ + hb-aat-layout.hh \ + hb-aat-ltag-table.hh \ + hb-aat-map.cc \ + hb-aat-map.hh \ + hb-array.hh \ + hb-atomic.hh \ hb-blob.cc \ - hb-buffer-private.hh \ + hb-blob.hh \ hb-buffer-serialize.cc \ hb-buffer.cc \ + hb-buffer.hh \ + hb-cache.hh \ + hb-cff-interp-common.hh \ + hb-cff-interp-cs-common.hh \ + hb-cff-interp-dict-common.hh \ + hb-cff1-interp-cs.hh \ + hb-cff2-interp-cs.hh \ hb-common.cc \ hb-debug.hh \ hb-dsalgs.hh \ - hb-face-private.hh \ hb-face.cc \ - hb-font-private.hh \ + hb-face.hh \ hb-font.cc \ - hb-map-private.hh \ + hb-font.hh \ + hb-iter.hh \ + hb-kern.hh \ + hb-machinery.hh \ hb-map.cc \ - hb-mutex-private.hh \ - hb-object-private.hh \ - hb-open-file-private.hh \ - hb-open-type-private.hh \ - hb-ot-color-cbdt-table.hh \ + hb-map.hh \ + hb-mutex.hh \ + hb-null.hh \ + hb-object.hh \ + hb-open-file.hh \ + hb-open-type.hh \ + hb-ot-cff-common.hh \ + hb-ot-cff1-table.cc \ + hb-ot-cff1-table.hh \ + hb-ot-cff2-table.cc \ + hb-ot-cff2-table.hh \ hb-ot-cmap-table.hh \ + hb-ot-color-cbdt-table.hh \ + hb-ot-color-colr-table.hh \ + hb-ot-color-cpal-table.hh \ + hb-ot-color-sbix-table.hh \ + hb-ot-color-svg-table.hh \ + hb-ot-color.cc \ + hb-ot-face.cc \ + hb-ot-face.hh \ + hb-ot-font.cc \ + hb-ot-gasp-table.hh \ hb-ot-glyf-table.hh \ hb-ot-hdmx-table.hh \ hb-ot-head-table.hh \ hb-ot-hhea-table.hh \ hb-ot-hmtx-table.hh \ hb-ot-kern-table.hh \ + hb-ot-layout-base-table.hh \ + hb-ot-layout-common.hh \ + hb-ot-layout-gdef-table.hh \ + hb-ot-layout-gpos-table.hh \ + hb-ot-layout-gsub-table.hh \ + hb-ot-layout-gsubgpos.hh \ + hb-ot-layout-jstf-table.hh \ + hb-ot-layout.cc \ + hb-ot-layout.hh \ + hb-ot-map.cc \ + hb-ot-map.hh \ + hb-ot-math-table.hh \ + hb-ot-math.cc \ hb-ot-maxp-table.hh \ + hb-ot-name-language.cc \ + hb-ot-name-language.hh \ hb-ot-name-table.hh \ + hb-ot-name.cc \ hb-ot-os2-table.hh \ hb-ot-os2-unicode-ranges.hh \ hb-ot-post-macroman.hh \ hb-ot-post-table.hh \ + hb-ot-shape-complex-arabic-fallback.hh \ + hb-ot-shape-complex-arabic-table.hh \ + hb-ot-shape-complex-arabic-win1256.hh \ + hb-ot-shape-complex-arabic.cc \ + hb-ot-shape-complex-arabic.hh \ + hb-ot-shape-complex-default.cc \ + hb-ot-shape-complex-hangul.cc \ + hb-ot-shape-complex-hebrew.cc \ + hb-ot-shape-complex-indic-table.cc \ + hb-ot-shape-complex-indic.cc \ + hb-ot-shape-complex-indic.hh \ + hb-ot-shape-complex-khmer.cc \ + hb-ot-shape-complex-khmer.hh \ + hb-ot-shape-complex-myanmar.cc \ + hb-ot-shape-complex-myanmar.hh \ + hb-ot-shape-complex-thai.cc \ + hb-ot-shape-complex-use-table.cc \ + hb-ot-shape-complex-use.cc \ + hb-ot-shape-complex-use.hh \ + hb-ot-shape-complex-vowel-constraints.cc \ + hb-ot-shape-complex-vowel-constraints.hh \ + hb-ot-shape-complex.hh \ + hb-ot-shape-fallback.cc \ + hb-ot-shape-fallback.hh \ + hb-ot-shape-normalize.cc \ + hb-ot-shape-normalize.hh \ + hb-ot-shape.cc \ + hb-ot-shape.hh \ + hb-ot-stat-table.hh \ + hb-ot-tag-table.hh \ hb-ot-tag.cc \ - hb-private.hh \ - hb-set-digest-private.hh \ - hb-set-private.hh \ + hb-ot-var-avar-table.hh \ + hb-ot-var-fvar-table.hh \ + hb-ot-var-hvar-table.hh \ + hb-ot-var-mvar-table.hh \ + hb-ot-var.cc \ + hb-ot-vorg-table.hh \ + hb-set-digest.hh \ hb-set.cc \ - hb-shape.cc \ - hb-shape-plan-private.hh \ + hb-set.hh \ hb-shape-plan.cc \ + hb-shape-plan.hh \ + hb-shape.cc \ + hb-shaper-impl.hh \ hb-shaper-list.hh \ - hb-shaper-impl-private.hh \ - hb-shaper-private.hh \ hb-shaper.cc \ + hb-shaper.hh \ hb-static.cc \ hb-string-array.hh \ - hb-unicode-private.hh \ + hb-unicode-emoji-table.hh \ hb-unicode.cc \ - hb-utf-private.hh \ + hb-unicode.hh \ + hb-utf.hh \ + hb-vector.hh \ hb-warning.cc \ + hb.hh \ $(NULL) HB_BASE_RAGEL_GENERATED_sources = \ hb-buffer-deserialize-json.hh \ hb-buffer-deserialize-text.hh \ + hb-ot-shape-complex-indic-machine.hh \ + hb-ot-shape-complex-khmer-machine.hh \ + hb-ot-shape-complex-myanmar-machine.hh \ + hb-ot-shape-complex-use-machine.hh \ $(NULL) HB_BASE_RAGEL_sources = \ hb-buffer-deserialize-json.rl \ hb-buffer-deserialize-text.rl \ + hb-ot-shape-complex-indic-machine.rl \ + hb-ot-shape-complex-khmer-machine.rl \ + hb-ot-shape-complex-myanmar-machine.rl \ + hb-ot-shape-complex-use-machine.rl \ $(NULL) HB_BASE_headers = \ - hb.h \ + hb-aat-layout.h \ + hb-aat.h \ hb-blob.h \ hb-buffer.h \ hb-common.h \ @@ -72,106 +175,27 @@ HB_BASE_headers = \ hb-face.h \ hb-font.h \ hb-map.h \ + hb-ot-color.h \ + hb-ot-deprecated.h \ + hb-ot-font.h \ + hb-ot-layout.h \ + hb-ot-math.h \ + hb-ot-name.h \ + hb-ot-shape.h \ + hb-ot-var.h \ + hb-ot.h \ hb-set.h \ - hb-shape.h \ hb-shape-plan.h \ + hb-shape.h \ hb-unicode.h \ hb-version.h \ + hb.h \ $(NULL) HB_FALLBACK_sources = \ hb-fallback-shape.cc \ $(NULL) -HB_OT_sources = \ - hb-aat-layout.cc \ - hb-aat-layout-common-private.hh \ - hb-aat-layout-ankr-table.hh \ - hb-aat-layout-bsln-table.hh \ - hb-aat-layout-feat-table.hh \ - hb-aat-layout-kerx-table.hh \ - hb-aat-layout-morx-table.hh \ - hb-aat-layout-trak-table.hh \ - hb-aat-layout-private.hh \ - hb-aat-fmtx-table.hh \ - hb-aat-gcid-table.hh \ - hb-aat-ltag-table.hh \ - hb-ot-font.cc \ - hb-ot-layout.cc \ - hb-ot-layout-base-table.hh \ - hb-ot-layout-common-private.hh \ - hb-ot-layout-gdef-table.hh \ - hb-ot-layout-gpos-table.hh \ - hb-ot-layout-gsubgpos-private.hh \ - hb-ot-layout-gsub-table.hh \ - hb-ot-layout-jstf-table.hh \ - hb-ot-layout-private.hh \ - hb-ot-color.cc \ - hb-ot-color-colr-table.hh \ - hb-ot-color-cpal-table.hh \ - hb-ot-color-sbix-table.hh \ - hb-ot-color-svg-table.hh \ - hb-ot-map.cc \ - hb-ot-map-private.hh \ - hb-ot-math.cc \ - hb-ot-math-table.hh \ - hb-ot-shape.cc \ - hb-ot-shape-complex-arabic.cc \ - hb-ot-shape-complex-arabic-fallback.hh \ - hb-ot-shape-complex-arabic-private.hh \ - hb-ot-shape-complex-arabic-table.hh \ - hb-ot-shape-complex-arabic-win1256.hh \ - hb-ot-shape-complex-default.cc \ - hb-ot-shape-complex-hangul.cc \ - hb-ot-shape-complex-hebrew.cc \ - hb-ot-shape-complex-indic.cc \ - hb-ot-shape-complex-indic-private.hh \ - hb-ot-shape-complex-indic-table.cc \ - hb-ot-shape-complex-khmer-private.hh \ - hb-ot-shape-complex-khmer.cc \ - hb-ot-shape-complex-myanmar-private.hh \ - hb-ot-shape-complex-myanmar.cc \ - hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-tibetan.cc \ - hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use-private.hh \ - hb-ot-shape-complex-use-table.cc \ - hb-ot-shape-complex-private.hh \ - hb-ot-shape-normalize-private.hh \ - hb-ot-shape-normalize.cc \ - hb-ot-shape-fallback-private.hh \ - hb-ot-shape-fallback.cc \ - hb-ot-shape-private.hh \ - hb-ot-var.cc \ - hb-ot-var-avar-table.hh \ - hb-ot-var-fvar-table.hh \ - hb-ot-var-hvar-table.hh \ - hb-ot-var-mvar-table.hh \ - $(NULL) - -HB_OT_RAGEL_GENERATED_sources = \ - hb-ot-shape-complex-indic-machine.hh \ - hb-ot-shape-complex-khmer-machine.hh \ - hb-ot-shape-complex-myanmar-machine.hh \ - hb-ot-shape-complex-use-machine.hh \ - $(NULL) -HB_OT_RAGEL_sources = \ - hb-ot-shape-complex-indic-machine.rl \ - hb-ot-shape-complex-khmer-machine.rl \ - hb-ot-shape-complex-myanmar-machine.rl \ - hb-ot-shape-complex-use-machine.rl \ - $(NULL) - -HB_OT_headers = \ - hb-ot.h \ - hb-ot-font.h \ - hb-ot-layout.h \ - hb-ot-math.h \ - hb-ot-shape.h \ - hb-ot-tag.h \ - hb-ot-var.h \ - $(NULL) - # Optional Sources and Headers with external deps HB_FT_sources = hb-ft.cc @@ -203,18 +227,30 @@ HB_ICU_headers = hb-icu.h # Sources for libharfbuzz-subset HB_SUBSET_sources = \ + hb-ot-cff1-table.cc \ + hb-ot-cff2-table.cc \ hb-static.cc \ - hb-subset.cc \ + hb-subset-cff-common.cc \ + hb-subset-cff-common.hh \ + hb-subset-cff1.cc \ + hb-subset-cff1.hh \ + hb-subset-cff2.cc \ + hb-subset-cff2.hh \ hb-subset-glyf.cc \ + hb-subset-glyf.hh \ + hb-subset-glyf.hh \ hb-subset-input.cc \ + hb-subset-input.hh \ hb-subset-plan.cc \ + hb-subset-plan.hh \ + hb-subset-plan.hh \ + hb-subset.cc \ + hb-subset.hh \ + hb-subset.hh \ $(NULL) HB_SUBSET_headers = \ hb-subset.h \ - hb-subset-glyf.hh \ - hb-subset-plan.hh \ - hb-subset-private.hh \ $(NULL) HB_GOBJECT_DIST_sources = hb-gobject-structs.cc diff --git a/src/check-includes.sh b/src/check-includes.sh index fd565da..f938f70 100755 --- a/src/check-includes.sh +++ b/src/check-includes.sh @@ -23,14 +23,14 @@ grep -v 'hb[.]h:' | grep . >&2 && stat=1 -echo 'Checking that source files #include "hb-*private.hh" first (or none)' +echo 'Checking that source files #include a private header first (or none)' for x in $HBSOURCES; do test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1 + grep '#.*\<include\>' "$x" /dev/null | head -n 1 done | -grep -v '"hb-.*private[.]hh"' | -grep -v 'hb-private[.]hh:' | +grep -v '"hb-.*[.]hh"' | +grep -v 'hb[.]hh' | grep . >&2 && stat=1 diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh index 71551cb..def25c7 100755 --- a/src/check-static-inits.sh +++ b/src/check-static-inits.sh @@ -7,7 +7,6 @@ test -z "$srcdir" && srcdir=. test -z "$libs" && libs=.libs stat=0 - if which objdump 2>/dev/null >/dev/null; then : else @@ -31,7 +30,8 @@ done echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff" for obj in $OBJS; do - if objdump -t "$obj" | grep '__cxa_'; then + if objdump -t "$obj" | grep -q '__cxa_' && ! objdump -t "$obj" | grep -q __ubsan_handle; then + objdump -t "$obj" | grep '__cxa_' echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff" stat=1 fi diff --git a/src/check-symbols.sh b/src/check-symbols.sh index d4eca50..cea8684 100755 --- a/src/check-symbols.sh +++ b/src/check-symbols.sh @@ -26,7 +26,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do symprefix= if test $suffix = dylib; then symprefix=_; fi - EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`" + EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`" prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'` diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc deleted file mode 100644 index 99e8ef9..0000000 --- a/src/dump-emoji.cc +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * 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. - */ - -#include "hb-static.cc" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" - -#include "hb-ft.h" - -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#include <cairo.h> -#include <cairo-ft.h> -#include <cairo-svg.h> - -#ifdef HAVE_GLIB -#include <glib.h> -#endif -#include <stdlib.h> -#include <stdio.h> - -void cbdt_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) -{ - char output_path[255]; - sprintf (output_path, "out/cbdt-%d-%d.png", group, gid); - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); -} - -void sbix_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) -{ - char output_path[255]; - sprintf (output_path, "out/sbix-%d-%d.png", group, gid); - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); -} - -void svg_callback (const uint8_t* data, unsigned int length, - unsigned int start_glyph, unsigned int end_glyph) -{ - char output_path[255]; - if (start_glyph == end_glyph) - sprintf (output_path, "out/svg-%d.svg", start_glyph); - else - sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph); - - // append "z" if the content is gzipped - if ((data[0] == 0x1F) && (data[1] == 0x8B)) - strcat (output_path, "z"); - - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); -} - -void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs, - const OT::COLR *colr, const OT::CPAL *cpal) -{ - for (unsigned int i = 0; i < num_glyphs; ++i) - { - unsigned int first_layer_index, num_layers; - if (colr->get_base_glyph_record (i, &first_layer_index, &num_layers)) - { - // Measure - cairo_text_extents_t extents; - { - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t)); - for (unsigned int j = 0; j < num_layers; ++j) - { - hb_codepoint_t glyph_id; - unsigned int color_index; - colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index); - glyphs[j].index = glyph_id; - } - cairo_glyph_extents (cr, glyphs, num_layers, &extents); - free (glyphs); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - - // Add a slight margin - extents.width += extents.width / 10; - extents.height += extents.height / 10; - extents.x_bearing -= extents.width / 20; - extents.y_bearing -= extents.height / 20; - - // Render - unsigned int pallet_count = cpal->get_palette_count (); - for (unsigned int pallet = 0; pallet < pallet_count; ++pallet) { - char output_path[255]; - - // If we have more than one pallet, use a better namin - if (pallet_count == 1) - sprintf (output_path, "out/colr-%d.svg", i); - else - sprintf (output_path, "out/colr-%d-%d.svg", i, pallet); - - cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - for (unsigned int j = 0; j < num_layers; ++j) - { - hb_codepoint_t glyph_id; - unsigned int color_index; - colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index); - - uint32_t color = cpal->get_color_record_argb (color_index, pallet); - int alpha = color & 0xFF; - int r = (color >> 8) & 0xFF; - int g = (color >> 16) & 0xFF; - int b = (color >> 24) & 0xFF; - cairo_set_source_rgba (cr, r / 255.f, g / 255.f, b / 255.f, alpha); - - cairo_glyph_t glyph; - glyph.index = glyph_id; - glyph.x = -extents.x_bearing; - glyph.y = -extents.y_bearing; - cairo_show_glyphs (cr, &glyph, 1); - } - - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - } - } -} - -void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs) -{ - // Dump every glyph available on the font - return; // disabled for now - for (unsigned int i = 0; i < num_glyphs; ++i) - { - cairo_text_extents_t extents; - cairo_glyph_t glyph = {0}; - glyph.index = i; - - // Measure - { - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - cairo_glyph_extents (cr, &glyph, 1, &extents); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - - // Add a slight margin - extents.width += extents.width / 10; - extents.height += extents.height / 10; - extents.x_bearing -= extents.width / 20; - extents.y_bearing -= extents.height / 20; - - // Render - { - char output_path[255]; - sprintf (output_path, "out/%d.svg", i); - cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - glyph.x = -extents.x_bearing; - glyph.y = -extents.y_bearing; - cairo_show_glyphs (cr, &glyph, 1); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - } -} - -int main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); - exit (1); - } - - hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - hb_face_t *face = hb_face_create (blob, 0); - hb_font_t *font = hb_font_create (face); - - OT::CBDT::accelerator_t cbdt; - cbdt.init (face); - cbdt.dump (cbdt_callback); - cbdt.fini (); - - OT::sbix::accelerator_t sbix; - sbix.init (face); - sbix.dump (sbix_callback); - sbix.fini (); - - OT::SVG::accelerator_t svg; - svg.init (face); - svg.dump (svg_callback); - svg.fini (); - - OT::Sanitizer<OT::COLR> sanitizerCOLR; - hb_blob_t* colr_blob = sanitizerCOLR.sanitize (face->reference_table (HB_OT_TAG_COLR)); - const OT::COLR *colr = colr_blob->as<OT::COLR> (); - - OT::Sanitizer<OT::CPAL> sanitizerCPAL; - hb_blob_t* cpal_blob = sanitizerCPAL.sanitize (face->reference_table (HB_OT_TAG_CPAL)); - const OT::CPAL *cpal = cpal_blob->as<OT::CPAL> (); - - cairo_font_face_t *cairo_face; - { - FT_Library library; - FT_Init_FreeType (&library); - FT_Face ftface; - FT_New_Face (library, argv[1], 0, &ftface); - cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0); - } - unsigned int num_glyphs = hb_face_get_glyph_count (face); - unsigned int upem = hb_face_get_upem (face); - colr_cpal_rendering (cairo_face, upem, num_glyphs, colr, cpal); - dump_glyphs (cairo_face, upem, num_glyphs); - - - hb_font_destroy (font); - hb_face_destroy (face); - hb_blob_destroy (blob); - - return 0; -} diff --git a/src/dump-fon.cc b/src/dump-fon.cc deleted file mode 100644 index 4015409..0000000 --- a/src/dump-fon.cc +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * 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. - */ - -#include "hb-static.cc" -#include <stdio.h> -#include <stdlib.h> -#include "hb-open-type-private.hh" - -template <typename Type, int Bytes> struct LEInt; - -template <typename Type> -struct LEInt<Type, 1> -{ - public: - inline void set (Type V) - { - v = V; - } - inline operator Type (void) const - { - return v; - } - private: uint8_t v; -}; -template <typename Type> -struct LEInt<Type, 2> -{ - public: - inline void set (Type V) - { - v[1] = (V >> 8) & 0xFF; - v[0] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[1] << 8) - + (v[0] ); - } - private: uint8_t v[2]; -}; -template <typename Type> -struct LEInt<Type, 3> -{ - public: - inline void set (Type V) - { - v[2] = (V >> 16) & 0xFF; - v[1] = (V >> 8) & 0xFF; - v[0] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[2] << 16) - + (v[1] << 8) - + (v[0] ); - } - private: uint8_t v[3]; -}; -template <typename Type> -struct LEInt<Type, 4> -{ - public: - inline void set (Type V) - { - v[3] = (V >> 24) & 0xFF; - v[2] = (V >> 16) & 0xFF; - v[1] = (V >> 8) & 0xFF; - v[0] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[3] << 24) - + (v[2] << 16) - + (v[1] << 8) - + (v[0] ); - } - private: uint8_t v[4]; -}; - -template <typename Type, unsigned int Size> -struct LEIntType -{ - inline void set (Type i) { v.set (i); } - inline operator Type(void) const { return v; } - inline bool sanitize (OT::hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); - } - protected: - LEInt<Type, Size> v; - public: - DEFINE_SIZE_STATIC (Size); -}; - -typedef LEIntType<uint8_t, 1> LEUINT8; /* 8-bit unsigned integer. */ -typedef LEIntType<int8_t, 1> LEINT8; /* 8-bit signed integer. */ -typedef LEIntType<uint16_t, 2> LEUINT16; /* 16-bit unsigned integer. */ -typedef LEIntType<int16_t, 2> LEINT16; /* 16-bit signed integer. */ -typedef LEIntType<uint32_t, 4> LEUINT32; /* 32-bit unsigned integer. */ -typedef LEIntType<int32_t, 4> LEINT32; /* 32-bit signed integer. */ -typedef LEIntType<uint32_t, 3> LEUINT24; /* 24-bit unsigned integer. */ - - -struct LE_FONTINFO16 -{ - inline bool sanitize (OT::hb_sanitize_context_t *c, unsigned int length) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && c->check_range (this, length))); - } - - // https://msdn.microsoft.com/en-us/library/cc194829.aspx - enum charset_t - { - // dfCharSet possible values and the codepage they are indicating to - ANSI = 0x00, // 1252 - DEFAULT = 0x01, // - SYMBOL = 0x02, // - SHIFTJIS = 0x80, // 932 - HANGUL = 0x81, // 949 - GB2312 = 0x86, // 936 - CHINESEBIG5 = 0x88, // 950 - GREEK = 0xA1, // 1253 - TURKISH = 0xA2, // 1254 - HEBREW = 0xB1, // 1255 - ARABIC = 0xB2, // 1256 - BALTIC = 0xBA, // 1257 - RUSSIAN = 0xCC, // 1251 - THAI = 0xDE, // 874 - EE = 0xEE, // 1250 - OEM = 0xFF // - }; - - inline const char* get_charset() const - { - switch (dfCharSet) { - case ANSI: return "ISO8859"; - case DEFAULT: return "WinDefault"; - case SYMBOL: return "Symbol"; - case SHIFTJIS: return "JISX0208.1983"; - case HANGUL: return "MSHangul"; - case GB2312: return "GB2312.1980"; - case CHINESEBIG5: return "Big5"; - case GREEK: return "CP1253"; - case TURKISH: return "CP1254"; - case HEBREW: return "CP1255"; - case ARABIC: return "CP1256"; - case BALTIC: return "CP1257"; - case RUSSIAN: return "CP1251"; - case THAI: return "CP874"; - case EE: return "CP1250"; - case OEM: return "OEM"; - default: return "Unknown"; - } - } - - inline unsigned int get_version () const - { - return dfVersion; - } - - inline unsigned int get_weight () const - { - return dfWeight; - } - - enum weight_t { - DONTCARE = 0, - THIN = 100, - EXTRALIGHT = 200, - ULTRALIGHT = 200, - LIGHT = 300, - NORMAL = 400, - REGULAR = 400, - MEDIUM = 500, - SEMIBOLD = 600, - DEMIBOLD = 600, - BOLD = 700, - EXTRABOLD = 800, - ULTRABOLD = 800, - HEAVY = 900, - BLACK = 900 - }; - - inline void dump () const - { - // With https://github.com/juanitogan/mkwinfont/blob/master/python/dewinfont.py help - // Should be implemented differently eventually, but for now - unsigned int ctstart; - unsigned int ctsize; - if (dfVersion == 0x200) - { - ctstart = 0x76; - ctsize = 4; - } - else - { - return; // must of ".fon"s are version 2 and even dewinfont V1 implmentation doesn't seem correct - ctstart = 0x94; - ctsize = 6; - } - // unsigned int maxwidth = 0; - for (unsigned int i = dfFirstChar; i < dfLastChar; ++i) - { - unsigned int entry = ctstart + ctsize * (i-dfFirstChar); - unsigned int w = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry); - - unsigned int off; - if (ctsize == 4) - off = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry+2); - else - off = (uint32_t) OT::StructAtOffset<LEUINT32> (this, entry+2); - - unsigned int widthbytes = (w + 7) / 8; - for (unsigned int j = 0; j < dfPixHeight; ++j) - { - for (unsigned int k = 0; k < widthbytes; ++k) - { - unsigned int bytepos = off + k * dfPixHeight + j; - const uint8_t b = (uint8_t) OT::StructAtOffset<LEINT8> (this, bytepos); - for (unsigned int a = 128; a > 0; a >>= 1) - printf (b & a ? "x" : "."); - } - printf ("\n"); - } - printf ("\n\n"); - } - } - - protected: - LEUINT16 dfVersion; - LEUINT32 dfSize; - LEUINT8 dfCopyright[60]; - LEUINT16 dfType; - LEUINT16 dfPoints; - LEUINT16 dfVertRes; - LEUINT16 dfHorizRes; - LEUINT16 dfAscent; - LEUINT16 dfInternalLeading; - LEUINT16 dfExternalLeading; - LEUINT8 dfItalic; - LEUINT8 dfUnderline; - LEUINT8 dfStrikeOut; - LEUINT16 dfWeight; // see weight_t - LEUINT8 dfCharSet; // see charset_t - LEUINT16 dfPixWidth; - LEUINT16 dfPixHeight; - LEUINT8 dfPitchAndFamily; - LEUINT16 dfAvgWidth; - LEUINT16 dfMaxWidth; - LEUINT8 dfFirstChar; - LEUINT8 dfLastChar; - LEUINT8 dfDefaultChar; - LEUINT8 dfBreakChar; - LEUINT16 dfWidthBytes; - LEUINT32 dfDevice; - LEUINT32 dfFace; - LEUINT32 dfBitsPointer; - LEUINT32 dfBitsOffset; - LEUINT8 dfReserved; -// LEUINT32 dfFlags; -// LEUINT16 dfAspace; -// LEUINT16 dfBspace; -// LEUINT16 dfCspace; -// LEUINT32 dfColorPointer; -// LEUINT32 dfReserved1[4]; - OT::UnsizedArrayOf<LEUINT8> - dataZ; - public: - DEFINE_SIZE_ARRAY (118, dataZ); -}; - -struct NE_NAMEINFO -{ - friend struct NE_TYPEINFO; - - inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - get_font (base, shift).sanitize (c, length << shift))); - } - - inline const LE_FONTINFO16& get_font (const void *base, int shift) const - { - return OT::StructAtOffset<LE_FONTINFO16> (base, offset << shift); - } - - enum resource_type_flag_t { - NONE = 0x0000, - MOVEABLE = 0x0010, - PURE = 0x0020, - PRELOAD = 0x0040 - }; - - protected: - LEUINT16 offset; // Should be shifted with alignmentShiftCount before use - LEUINT16 length; // Should be shifted with alignmentShiftCount before use - LEUINT16 flags; // resource_type_flag_t - LEUINT16 id; - LEUINT16 handle; - LEUINT16 usage; - public: - DEFINE_SIZE_STATIC (12); -}; - -struct NE_TYPEINFO -{ - inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && resources.sanitize (c, count, base, shift)); - } - - inline unsigned int get_size (void) const - { return 8 + count * NE_NAMEINFO::static_size; } - - inline const NE_TYPEINFO& next () const - { - const NE_TYPEINFO& next = OT::StructAfter<NE_TYPEINFO> (*this); - if (type_id == 0) - return Null(NE_TYPEINFO); - return next; - } - - inline const LE_FONTINFO16& get_font (unsigned int idx, const void *base, int shift) const - { - if (idx < count) - return resources[idx].get_font (base, shift); - return Null(LE_FONTINFO16); - } - - inline unsigned int get_count () const - { - return count; - } - - inline unsigned int get_type_id () const - { - return type_id; - } - - enum type_id_t { - CURSOR = 0x8001, - BITMAP = 0x8002, - ICON = 0x8003, - MENU = 0x8004, - DIALOG = 0x8005, - STRING = 0x8006, - FONT_DIRECTORY = 0x8007, - FONT = 0x8008, - ACCELERATOR_TABLE = 0x8009, - RESOURCE_DATA = 0x800a, - GROUP_CURSOR = 0x800c, - GROUP_ICON = 0x800e, - VERSION = 0x8010 - }; - - protected: - LEUINT16 type_id; // see type_id_t - LEUINT16 count; - LEUINT32 resloader; - OT::UnsizedArrayOf<NE_NAMEINFO> - resources; - public: - DEFINE_SIZE_ARRAY (8, resources); -}; - -struct NE_RESOURCE_TABLE -{ - inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - - if (!c->check_struct (this)) - return_trace (false); - - const NE_TYPEINFO* n = &chain; - while (n != &Null(NE_TYPEINFO) && c->check_struct (n) && n->get_type_id () != 0) - { - if (n->get_type_id () == NE_TYPEINFO::FONT) - return_trace (n->sanitize (c, base, alignmentShiftCount)); - n = &n->next(); - } - return_trace (false); - } - - inline unsigned int get_shift_value () const - { - return alignmentShiftCount; - } - - inline const NE_TYPEINFO& get_fonts_entry () const - { - const NE_TYPEINFO* n = &chain; - while (n != &Null(NE_TYPEINFO) && n->get_type_id () != 0) - { - if (n->get_type_id () == NE_TYPEINFO::FONT) - return *n; - n = &n->next(); - } - return Null(NE_TYPEINFO); - } - - protected: - LEUINT16 alignmentShiftCount; - NE_TYPEINFO chain; - // It is followed by an array of OT::ArrayOf<LEUINT8, LEUINT8> chars; - public: - DEFINE_SIZE_MIN (2); -}; - -// https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L2467 -struct LE_IMAGE_OS2_HEADER -{ - inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && (this+rsrctab).sanitize (c, base))); - } - - inline const NE_RESOURCE_TABLE& get_resource_table () const - { - if (magic != 0x454E) // Only NE containers are support for now, NE == 0x454E - return Null(NE_RESOURCE_TABLE); - return this+rsrctab; - } - - protected: - LEUINT16 magic; /* 00 NE signature 'NE' */ - LEUINT8 ver; /* 02 Linker version number */ - LEUINT8 rev; /* 03 Linker revision number */ - LEUINT16 enttab; /* 04 Offset to entry table relative to NE */ - LEUINT16 cbenttab; /* 06 Length of entry table in bytes */ - LEUINT32 crc; /* 08 Checksum */ - LEUINT16 flags; /* 0c Flags about segments in this file */ - LEUINT16 autodata; /* 0e Automatic data segment number */ - LEUINT16 heap; /* 10 Initial size of local heap */ - LEUINT16 stack; /* 12 Initial size of stack */ - LEUINT32 csip; /* 14 Initial CS:IP */ - LEUINT32 sssp; /* 18 Initial SS:SP */ - LEUINT16 cseg; /* 1c # of entries in segment table */ - LEUINT16 cmod; /* 1e # of entries in module reference tab. */ - LEUINT16 cbnrestab; /* 20 Length of nonresident-name table */ - LEUINT16 segtab; /* 22 Offset to segment table */ - OT::OffsetTo<NE_RESOURCE_TABLE, LEUINT16> - rsrctab; /* 24 Offset to resource table */ - LEUINT16 restab; /* 26 Offset to resident-name table */ - LEUINT16 modtab; /* 28 Offset to module reference table */ - LEUINT16 imptab; /* 2a Offset to imported name table */ - LEUINT32 nrestab; /* 2c Offset to nonresident-name table */ - LEUINT16 cmovent; /* 30 # of movable entry points */ - LEUINT16 align; /* 32 Logical sector alignment shift count */ - LEUINT16 cres; /* 34 # of resource segments */ - LEUINT8 exetyp; /* 36 Flags indicating target OS */ - LEUINT8 flagsothers; /* 37 Additional information flags */ - LEUINT16 pretthunks; /* 38 Offset to return thunks */ - LEUINT16 psegrefbytes; /* 3a Offset to segment ref. bytes */ - LEUINT16 swaparea; /* 3c Reserved by Microsoft */ - LEUINT16 expver; /* 3e Expected Windows version number */ - public: - DEFINE_SIZE_STATIC (64); -}; - -struct LE_IMAGE_DOS_HEADER { - inline bool sanitize (OT::hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - get_os2_header ().sanitize (c, this))); - } - - inline const LE_IMAGE_OS2_HEADER& get_os2_header () const - { - return this+e_lfanew; - } - - protected: - LEUINT16 e_magic; // Magic number - LEUINT16 e_cblp; // Bytes on last page of file - LEUINT16 e_cp; // Pages in file - LEUINT16 e_crlc; // Relocations - LEUINT16 e_cparhdr; // Size of header in paragraphs - LEUINT16 e_minalloc; // Minimum extra paragraphs needed - LEUINT16 e_maxalloc; // Maximum extra paragraphs needed - LEUINT16 e_ss; // Initial (relative) SS value - LEUINT16 e_sp; // Initial SP value - LEUINT16 e_csum; // Checksum - LEUINT16 e_ip; // Initial IP value - LEUINT16 e_cs; // Initial (relative) CS value - LEUINT16 e_lfarlc; // File address of relocation table - LEUINT16 e_ovno; // Overlay number - LEUINT16 e_res_0; // Reserved words - LEUINT16 e_res_1; // Reserved words - LEUINT16 e_res_2; // Reserved words - LEUINT16 e_res_3; // Reserved words - LEUINT16 e_oemid; // OEM identifier (for e_oeminfo) - LEUINT16 e_oeminfo; // OEM information; e_oemid specific - LEUINT16 e_res2_0; // Reserved words - LEUINT16 e_res2_1; // Reserved words - LEUINT16 e_res2_2; // Reserved words - LEUINT16 e_res2_3; // Reserved words - LEUINT16 e_res2_4; // Reserved words - LEUINT16 e_res2_5; // Reserved words - LEUINT16 e_res2_6; // Reserved words - LEUINT16 e_res2_7; // Reserved words - LEUINT16 e_res2_8; // Reserved words - LEUINT16 e_res2_9; // Reserved words - OT::OffsetTo<LE_IMAGE_OS2_HEADER, LEUINT32> - e_lfanew; // File address of new exe header - public: - DEFINE_SIZE_STATIC (64); -}; - -int main (int argc, char** argv) { - hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - - OT::Sanitizer<LE_IMAGE_DOS_HEADER> sanitizer; - hb_blob_t *font_blob = sanitizer.sanitize (blob); - const LE_IMAGE_DOS_HEADER* dos_header = font_blob->as<LE_IMAGE_DOS_HEADER> (); - - const NE_RESOURCE_TABLE &rtable = dos_header->get_os2_header ().get_resource_table (); - int shift = rtable.get_shift_value (); - const NE_TYPEINFO& entry = rtable.get_fonts_entry (); - for (unsigned int i = 0; i < entry.get_count (); ++i) - { - const LE_FONTINFO16& font = entry.get_font (i, dos_header, shift); - printf ("version: %x, weight: %d, charset: %s\n", font.get_version (), - font.get_weight (), font.get_charset ()); - // font.dump (); - } - return 0; -} diff --git a/src/dump-indic-data.cc b/src/dump-indic-data.cc index d574138..8ddc9d5 100644 --- a/src/dump-indic-data.cc +++ b/src/dump-indic-data.cc @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" int -main (void) +main () { for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) { diff --git a/src/dump-khmer-data.cc b/src/dump-khmer-data.cc index 7dd09b2..cffbb92 100644 --- a/src/dump-khmer-data.cc +++ b/src/dump-khmer-data.cc @@ -24,20 +24,18 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-khmer-private.hh" +#include "hb-ot-shape-complex-khmer.hh" int -main (void) +main () { for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) { hb_glyph_info_t info; info.codepoint = u; set_khmer_properties (info); - if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER || - info.khmer_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE) - printf("U+%04X %u %u\n", u, - info.khmer_category(), - info.khmer_position()); + if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER) + printf("U+%04X %u\n", u, + info.khmer_category()); } } diff --git a/src/dump-myanmar-data.cc b/src/dump-myanmar-data.cc index 2df9cd9..c1a303f 100644 --- a/src/dump-myanmar-data.cc +++ b/src/dump-myanmar-data.cc @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-myanmar-private.hh" +#include "hb-ot-shape-complex-myanmar.hh" int -main (void) +main () { for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) { diff --git a/src/dump-use-data.cc b/src/dump-use-data.cc index 0e64688..d639426 100644 --- a/src/dump-use-data.cc +++ b/src/dump-use-data.cc @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-use-private.hh" +#include "hb-ot-shape-complex-use.hh" int -main (void) +main () { for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) { diff --git a/src/gen-def.py b/src/gen-def.py index 9a997d6..9111c69 100755 --- a/src/gen-def.py +++ b/src/gen-def.py @@ -4,16 +4,21 @@ from __future__ import print_function, division, absolute_import import io, os, re, sys +if len (sys.argv) < 3: + sys.exit("usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]") + +output_file = sys.argv[1] +header_paths = sys.argv[2:] + headers_content = [] -for h in os.environ["headers"].split (' '): +for h in header_paths: if h.endswith (".h"): with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ()) -result = """EXPORTS +symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))) + +result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS %s -LIBRARY lib%s-0.dll""" % ( - "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))), - sys.argv[1].replace ('.def', '') -) +LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', '')) -with open (sys.argv[1], "w") as f: f.write (result) +with open (output_file, "w") as f: f.write (result) diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py new file mode 100755 index 0000000..9afe747 --- /dev/null +++ b/src/gen-emoji-table.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +from __future__ import print_function, division, absolute_import +import sys +import os.path +from collections import OrderedDict + +if len (sys.argv) != 2: + print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr) + sys.exit (1) + +f = open(sys.argv[1]) +header = [f.readline () for _ in range(10)] + +ranges = OrderedDict() +for line in f.readlines(): + line = line.strip() + if not line or line[0] == '#': + continue + rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]] + + rang = [int(s, 16) for s in rang.split('..')] + if len(rang) > 1: + start, end = rang + else: + start = end = rang[0] + + if typ not in ranges: + ranges[typ] = [] + if ranges[typ] and ranges[typ][-1][1] == start - 1: + ranges[typ][-1] = (ranges[typ][-1][0], end) + else: + ranges[typ].append((start, end)) + + + +print ("/* == Start of generated table == */") +print ("/*") +print (" * The following tables are generated by running:") +print (" *") +print (" * ./gen-emoji-table.py emoji-data.txt") +print (" *") +print (" * on file with this header:") +print (" *") +for l in header: + print (" * %s" % (l.strip())) +print (" */") +print () +print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH") +print ("#define HB_UNICODE_EMOJI_TABLE_HH") +print () +print ('#include "hb-unicode.hh"') +print () + +for typ,s in ranges.items(): + if typ != "Extended_Pictographic": continue + print() + print("static const struct hb_unicode_range_t _hb_unicode_emoji_%s_table[] =" % typ) + print("{") + for pair in sorted(s): + print(" {0x%04X, 0x%04X}," % pair) + print("};") + +print () +print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */") +print () +print ("/* == End of generated table == */") diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py index 6252664..6532ee7 100755 --- a/src/gen-indic-table.py +++ b/src/gen-indic-table.py @@ -102,7 +102,7 @@ for h in headers: print (" * %s" % (l.strip())) print (" */") print () -print ('#include "hb-ot-shape-complex-indic-private.hh"') +print ('#include "hb-ot-shape-complex-indic.hh"') print () # Shorten values @@ -131,6 +131,8 @@ for i in range (2): what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"] what_short = ["ISC", "IMC"] +print ('#pragma GCC diagnostic push') +print ('#pragma GCC diagnostic ignored "-Wunused-macros"') for i in range (2): print () vv = sorted (values[i].keys ()) @@ -148,6 +150,7 @@ for i in range (2): (what_short[i], s, what[i], v.upper (), ' '* ((48-1 - len (what[i]) - 1 - len (v)) // 8), values[i][v], v)) +print ('#pragma GCC diagnostic pop') print () print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)") print () diff --git a/src/gen-os2-unicode-ranges.py b/src/gen-os2-unicode-ranges.py new file mode 100644 index 0000000..8cf5985 --- /dev/null +++ b/src/gen-os2-unicode-ranges.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh +# Input is a tab seperated list of unicode ranges from the otspec +# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1). + +from __future__ import print_function, division, absolute_import + +import io +import re +import sys + +try: + reload(sys) + sys.setdefaultencoding('utf-8') +except NameError: + pass # Python 3 + +print ("""static OS2Range _hb_os2_unicode_ranges[] = +{""") + +args = sys.argv[1:] +input_file = args[0] + +with io.open(input_file, mode="r", encoding="utf-8") as f: + + all_ranges = []; + current_bit = 0 + while True: + line = f.readline().strip() + if not line: + break + fields = re.split(r'\t+', line) + if len(fields) == 3: + current_bit = fields[0] + fields = fields[1:] + elif len(fields) > 3: + raise Exception("bad input :(.") + + name = fields[0] + ranges = re.split("-", fields[1]) + if len(ranges) != 2: + raise Exception("bad input :(.") + + v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name)) + all_ranges.append(v) + +all_ranges = sorted(all_ranges, key=lambda t: t[0]) + +for ranges in all_ranges: + start = ("0x%X" % ranges[0]).rjust(8) + end = ("0x%X" % ranges[1]).rjust(8) + bit = ("%s" % ranges[2]).rjust(3) + + print (" {%s, %s, %s}, // %s" % (start, end, bit, ranges[3])) + +print ("""};""") diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py new file mode 100755 index 0000000..1300462 --- /dev/null +++ b/src/gen-tag-table.py @@ -0,0 +1,1126 @@ +#!/usr/bin/python + +"""Generator of the mapping from OpenType tags to BCP 47 tags and vice +versa. + +It creates a ``const LangTag[]``, matching the tags from the OpenType +languages system tag list to the language subtags of the BCP 47 language +subtag registry, with some manual adjustments. The mappings are +supplemented with macrolanguages' sublanguages and retired codes' +replacements, according to BCP 47 and some manual additions where BCP 47 +omits a retired code entirely. + +Also generated is a function, ``hb_ot_ambiguous_tag_to_language``, +intended for use by ``hb_ot_tag_to_language``. It maps OpenType tags +back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to +multiple BCP 47 tags) are listed here, except when the alphabetically +first BCP 47 tag happens to be the chosen disambiguated tag. In that +case, the fallback behavior will choose the right tag anyway. +""" + +from __future__ import absolute_import, division, print_function, unicode_literals + +import collections +try: + from HTMLParser import HTMLParser + def write (s): + print (s.encode ('utf-8'), end='') +except ImportError: + from html.parser import HTMLParser + def write (s): + sys.stdout.flush () + sys.stdout.buffer.write (s.encode ('utf-8')) +import io +import itertools +import re +import sys +import unicodedata + +if len (sys.argv) != 3: + print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr) + sys.exit (1) + +try: + from html import unescape + def html_unescape (parser, entity): + return unescape (entity) +except ImportError: + def html_unescape (parser, entity): + return parser.unescape (entity) + +def expect (condition, message=None): + if not condition: + if message is None: + raise AssertionError + raise AssertionError (message) + +# from http://www-01.sil.org/iso639-3/iso-639-3.tab +ISO_639_3_TO_1 = { + 'aar': 'aa', + 'abk': 'ab', + 'afr': 'af', + 'aka': 'ak', + 'amh': 'am', + 'ara': 'ar', + 'arg': 'an', + 'asm': 'as', + 'ava': 'av', + 'ave': 'ae', + 'aym': 'ay', + 'aze': 'az', + 'bak': 'ba', + 'bam': 'bm', + 'bel': 'be', + 'ben': 'bn', + 'bis': 'bi', + 'bod': 'bo', + 'bos': 'bs', + 'bre': 'br', + 'bul': 'bg', + 'cat': 'ca', + 'ces': 'cs', + 'cha': 'ch', + 'che': 'ce', + 'chu': 'cu', + 'chv': 'cv', + 'cor': 'kw', + 'cos': 'co', + 'cre': 'cr', + 'cym': 'cy', + 'dan': 'da', + 'deu': 'de', + 'div': 'dv', + 'dzo': 'dz', + 'ell': 'el', + 'eng': 'en', + 'epo': 'eo', + 'est': 'et', + 'eus': 'eu', + 'ewe': 'ee', + 'fao': 'fo', + 'fas': 'fa', + 'fij': 'fj', + 'fin': 'fi', + 'fra': 'fr', + 'fry': 'fy', + 'ful': 'ff', + 'gla': 'gd', + 'gle': 'ga', + 'glg': 'gl', + 'glv': 'gv', + 'grn': 'gn', + 'guj': 'gu', + 'hat': 'ht', + 'hau': 'ha', + 'hbs': 'sh', + 'heb': 'he', + 'her': 'hz', + 'hin': 'hi', + 'hmo': 'ho', + 'hrv': 'hr', + 'hun': 'hu', + 'hye': 'hy', + 'ibo': 'ig', + 'ido': 'io', + 'iii': 'ii', + 'iku': 'iu', + 'ile': 'ie', + 'ina': 'ia', + 'ind': 'id', + 'ipk': 'ik', + 'isl': 'is', + 'ita': 'it', + 'jav': 'jv', + 'jpn': 'ja', + 'kal': 'kl', + 'kan': 'kn', + 'kas': 'ks', + 'kat': 'ka', + 'kau': 'kr', + 'kaz': 'kk', + 'khm': 'km', + 'kik': 'ki', + 'kin': 'rw', + 'kir': 'ky', + 'kom': 'kv', + 'kon': 'kg', + 'kor': 'ko', + 'kua': 'kj', + 'kur': 'ku', + 'lao': 'lo', + 'lat': 'la', + 'lav': 'lv', + 'lim': 'li', + 'lin': 'ln', + 'lit': 'lt', + 'ltz': 'lb', + 'lub': 'lu', + 'lug': 'lg', + 'mah': 'mh', + 'mal': 'ml', + 'mar': 'mr', + 'mkd': 'mk', + 'mlg': 'mg', + 'mlt': 'mt', + 'mol': 'mo', + 'mon': 'mn', + 'mri': 'mi', + 'msa': 'ms', + 'mya': 'my', + 'nau': 'na', + 'nav': 'nv', + 'nbl': 'nr', + 'nde': 'nd', + 'ndo': 'ng', + 'nep': 'ne', + 'nld': 'nl', + 'nno': 'nn', + 'nob': 'nb', + 'nor': 'no', + 'nya': 'ny', + 'oci': 'oc', + 'oji': 'oj', + 'ori': 'or', + 'orm': 'om', + 'oss': 'os', + 'pan': 'pa', + 'pli': 'pi', + 'pol': 'pl', + 'por': 'pt', + 'pus': 'ps', + 'que': 'qu', + 'roh': 'rm', + 'ron': 'ro', + 'run': 'rn', + 'rus': 'ru', + 'sag': 'sg', + 'san': 'sa', + 'sin': 'si', + 'slk': 'sk', + 'slv': 'sl', + 'sme': 'se', + 'smo': 'sm', + 'sna': 'sn', + 'snd': 'sd', + 'som': 'so', + 'sot': 'st', + 'spa': 'es', + 'sqi': 'sq', + 'srd': 'sc', + 'srp': 'sr', + 'ssw': 'ss', + 'sun': 'su', + 'swa': 'sw', + 'swe': 'sv', + 'tah': 'ty', + 'tam': 'ta', + 'tat': 'tt', + 'tel': 'te', + 'tgk': 'tg', + 'tgl': 'tl', + 'tha': 'th', + 'tir': 'ti', + 'ton': 'to', + 'tsn': 'tn', + 'tso': 'ts', + 'tuk': 'tk', + 'tur': 'tr', + 'twi': 'tw', + 'uig': 'ug', + 'ukr': 'uk', + 'urd': 'ur', + 'uzb': 'uz', + 'ven': 've', + 'vie': 'vi', + 'vol': 'vo', + 'wln': 'wa', + 'wol': 'wo', + 'xho': 'xh', + 'yid': 'yi', + 'yor': 'yo', + 'zha': 'za', + 'zho': 'zh', + 'zul': 'zu', +} + +class LanguageTag (object): + """A BCP 47 language tag. + + Attributes: + subtags (List[str]): The list of subtags in this tag. + grandfathered (bool): Whether this tag is grandfathered. If + ``true``, the entire lowercased tag is the ``language`` + and the other subtag fields are empty. + language (str): The language subtag. + script (str): The script subtag. + region (str): The region subtag. + variant (str): The variant subtag. + + Args: + tag (str): A BCP 47 language tag. + + """ + def __init__ (self, tag): + global bcp_47 + self.subtags = tag.lower ().split ('-') + self.grandfathered = tag.lower () in bcp_47.grandfathered + if self.grandfathered: + self.language = tag.lower () + self.script = '' + self.region = '' + self.variant = '' + else: + self.language = self.subtags[0] + self.script = self._find_first (lambda s: len (s) == 4 and s[0] > '9', self.subtags) + self.region = self._find_first (lambda s: len (s) == 2 and s[0] > '9' or len (s) == 3 and s[0] <= '9', self.subtags[1:]) + self.variant = self._find_first (lambda s: len (s) > 4 or len (s) == 4 and s[0] <= '9', self.subtags) + + def __str__(self): + return '-'.join(self.subtags) + + def __repr__ (self): + return 'LanguageTag(%r)' % str(self) + + @staticmethod + def _find_first (function, sequence): + try: + return next (iter (filter (function, sequence))) + except StopIteration: + return None + + def is_complex (self): + """Return whether this tag is too complex to represent as a + ``LangTag`` in the generated code. + + Complex tags need to be handled in + ``hb_ot_tags_from_complex_language``. + + Returns: + Whether this tag is complex. + """ + return not (len (self.subtags) == 1 + or self.grandfathered + and len (self.subtags[1]) != 3 + and ot.from_bcp_47[self.subtags[0]] == ot.from_bcp_47[self.language]) + + def get_group (self): + """Return the group into which this tag should be categorized in + ``hb_ot_tags_from_complex_language``. + + The group is the first letter of the tag, or ``'und'`` if this tag + should not be matched in a ``switch`` statement in the generated + code. + + Returns: + This tag's group. + """ + return ('und' + if (self.language == 'und' + or self.variant in bcp_47.prefixes and len (bcp_47.prefixes[self.variant]) == 1) + else self.language[0]) + +class OpenTypeRegistryParser (HTMLParser): + """A parser for the OpenType language system tag registry. + + Attributes: + header (str): The "last updated" line of the registry. + names (Mapping[str, str]): A map of language system tags to the + names they are given in the registry. + ranks (DefaultDict[str, int]): A map of language system tags to + numbers. If a single BCP 47 tag corresponds to multiple + OpenType tags, the tags are ordered in increasing order by + rank. The rank is based on the number of BCP 47 tags + associated with a tag, though it may be manually modified. + to_bcp_47 (DefaultDict[str, AbstractSet[str]]): A map of + OpenType language system tags to sets of BCP 47 tags. + from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47`` + inverted. Its values start as unsorted sets; + ``sort_languages`` converts them to sorted lists. + + """ + def __init__ (self): + HTMLParser.__init__ (self) + self.header = '' + self.names = {} + self.ranks = collections.defaultdict (int) + self.to_bcp_47 = collections.defaultdict (set) + self.from_bcp_47 = collections.defaultdict (set) + # Whether the parser is in a <td> element + self._td = False + # The text of the <td> elements of the current <tr> element. + self._current_tr = [] + + def handle_starttag (self, tag, attrs): + if tag == 'meta': + for attr, value in attrs: + if attr == 'name' and value == 'updated_at': + self.header = self.get_starttag_text () + break + elif tag == 'td': + self._td = True + self._current_tr.append ('') + elif tag == 'tr': + self._current_tr = [] + + def handle_endtag (self, tag): + if tag == 'td': + self._td = False + elif tag == 'tr' and self._current_tr: + expect (2 <= len (self._current_tr) <= 3) + name = self._current_tr[0].strip () + tag = self._current_tr[1].strip ("\t\n\v\f\r '") + rank = 0 + if len (tag) > 4: + expect (tag.endswith (' (deprecated)'), 'ill-formed OpenType tag: %s' % tag) + name += ' (deprecated)' + tag = tag.split (' ')[0] + rank = 1 + self.names[tag] = re.sub (' languages$', '', name) + if not self._current_tr[2]: + return + iso_codes = self._current_tr[2].strip () + self.to_bcp_47[tag].update (ISO_639_3_TO_1.get (code, code) for code in iso_codes.replace (' ', '').split (',')) + rank += 2 * len (self.to_bcp_47[tag]) + self.ranks[tag] = rank + + def handle_data (self, data): + if self._td: + self._current_tr[-1] += data + + def handle_charref (self, name): + self.handle_data (html_unescape (self, '&#%s;' % name)) + + def handle_entityref (self, name): + self.handle_data (html_unescape (self, '&%s;' % name)) + + def parse (self, filename): + """Parse the OpenType language system tag registry. + + Args: + filename (str): The file name of the registry. + """ + with io.open (filename, encoding='utf-8') as f: + self.feed (f.read ()) + expect (self.header) + for tag, iso_codes in self.to_bcp_47.items (): + for iso_code in iso_codes: + self.from_bcp_47[iso_code].add (tag) + + def add_language (self, bcp_47_tag, ot_tag): + """Add a language as if it were in the registry. + + Args: + bcp_47_tag (str): A BCP 47 tag. If the tag is more than just + a language subtag, and if the language subtag is a + macrolanguage, then new languages are added corresponding + to the macrolanguages' individual languages with the + remainder of the tag appended. + ot_tag (str): An OpenType language system tag. + """ + global bcp_47 + self.to_bcp_47[ot_tag].add (bcp_47_tag) + self.from_bcp_47[bcp_47_tag].add (ot_tag) + if bcp_47_tag.lower () not in bcp_47.grandfathered: + try: + [macrolanguage, suffix] = bcp_47_tag.split ('-', 1) + if macrolanguage in bcp_47.macrolanguages: + s = set () + for language in bcp_47.macrolanguages[macrolanguage]: + if language.lower () not in bcp_47.grandfathered: + s.add ('%s-%s' % (language, suffix)) + bcp_47.macrolanguages['%s-%s' % (macrolanguage, suffix)] = s + except ValueError: + pass + + @staticmethod + def _remove_language (tag_1, dict_1, dict_2): + for tag_2 in dict_1.pop (tag_1): + dict_2[tag_2].remove (tag_1) + if not dict_2[tag_2]: + del dict_2[tag_2] + + def remove_language_ot (self, ot_tag): + """Remove an OpenType tag from the registry. + + Args: + ot_tag (str): An OpenType tag. + """ + self._remove_language (ot_tag, self.to_bcp_47, self.from_bcp_47) + + def remove_language_bcp_47 (self, bcp_47_tag): + """Remove a BCP 47 tag from the registry. + + Args: + bcp_47_tag (str): A BCP 47 tag. + """ + self._remove_language (bcp_47_tag, self.from_bcp_47, self.to_bcp_47) + + def inherit_from_macrolanguages (self): + """Copy mappings from macrolanguages to individual languages. + + If a BCP 47 tag for an individual mapping has no OpenType + mapping but its macrolanguage does, the mapping is copied to + the individual language. For example, als (Tosk Albanian) has no + explicit mapping, so it inherits from sq (Albanian) the mapping + to SQI. + + If a BCP 47 tag for a macrolanguage has no OpenType mapping but + all of its individual languages do and they all map to the same + tags, the mapping is copied to the macrolanguage. + """ + global bcp_47 + original_ot_from_bcp_47 = dict (self.from_bcp_47) + for macrolanguage, languages in dict (bcp_47.macrolanguages).items (): + ot_macrolanguages = set (original_ot_from_bcp_47.get (macrolanguage, set ())) + if ot_macrolanguages: + for ot_macrolanguage in ot_macrolanguages: + for language in languages: + # Remove the following condition if e.g. nn should map to NYN,NOR + # instead of just NYN. + if language not in original_ot_from_bcp_47: + self.add_language (language, ot_macrolanguage) + self.ranks[ot_macrolanguage] += 1 + else: + for language in languages: + if language in original_ot_from_bcp_47: + if ot_macrolanguages: + ml = original_ot_from_bcp_47[language] + if ml: + ot_macrolanguages &= ml + else: + pass + else: + ot_macrolanguages |= original_ot_from_bcp_47[language] + else: + ot_macrolanguages.clear () + if not ot_macrolanguages: + break + for ot_macrolanguage in ot_macrolanguages: + self.add_language (macrolanguage, ot_macrolanguage) + + def sort_languages (self): + """Sort the values of ``from_bcp_47`` in ascending rank order.""" + for language, tags in self.from_bcp_47.items (): + self.from_bcp_47[language] = sorted (tags, + key=lambda t: (self.ranks[t] + rank_delta (language, t), t)) + +ot = OpenTypeRegistryParser () + +class BCP47Parser (object): + """A parser for the BCP 47 subtag registry. + + Attributes: + header (str): The "File-Date" line of the registry. + names (Mapping[str, str]): A map of subtags to the names they + are given in the registry. Each value is a + ``'\\n'``-separated list of names. + scopes (Mapping[str, str]): A map of language subtags to strings + suffixed to language names, including suffixes to explain + language scopes. + macrolanguages (DefaultDict[str, AbstractSet[str]]): A map of + language subtags to the sets of language subtags which + inherit from them. See + ``OpenTypeRegistryParser.inherit_from_macrolanguages``. + prefixes (DefaultDict[str, AbstractSet[str]]): A map of variant + subtags to their prefixes. + grandfathered (AbstractSet[str]): The set of grandfathered tags, + normalized to lowercase. + + """ + def __init__ (self): + self.header = '' + self.names = {} + self.scopes = {} + self.macrolanguages = collections.defaultdict (set) + self.prefixes = collections.defaultdict (set) + self.grandfathered = set () + + def parse (self, filename): + """Parse the BCP 47 subtag registry. + + Args: + filename (str): The file name of the registry. + """ + with io.open (filename, encoding='utf-8') as f: + subtag_type = None + subtag = None + deprecated = False + has_preferred_value = False + line_buffer = '' + for line in itertools.chain (f, ['']): + line = line.rstrip () + if line.startswith (' '): + line_buffer += line[1:] + continue + line, line_buffer = line_buffer, line + if line.startswith ('Type: '): + subtag_type = line.split (' ')[1] + deprecated = False + has_preferred_value = False + elif line.startswith ('Subtag: ') or line.startswith ('Tag: '): + subtag = line.split (' ')[1] + if subtag_type == 'grandfathered': + self.grandfathered.add (subtag.lower ()) + elif line.startswith ('Description: '): + description = line.split (' ', 1)[1].replace (' (individual language)', '') + description = re.sub (' (\((individual |macro)language\)|languages)$', '', + description) + if subtag in self.names: + self.names[subtag] += '\n' + description + else: + self.names[subtag] = description + elif subtag_type == 'language' or subtag_type == 'grandfathered': + if line.startswith ('Scope: '): + scope = line.split (' ')[1] + if scope == 'macrolanguage': + scope = ' [macrolanguage]' + elif scope == 'collection': + scope = ' [family]' + else: + continue + self.scopes[subtag] = scope + elif line.startswith ('Deprecated: '): + self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '') + deprecated = True + elif deprecated and line.startswith ('Comments: see '): + # If a subtag is split into multiple replacement subtags, + # it essentially represents a macrolanguage. + for language in line.replace (',', '').split (' ')[2:]: + self._add_macrolanguage (subtag, language) + elif line.startswith ('Preferred-Value: '): + # If a subtag is deprecated in favor of a single replacement subtag, + # it is either a dialect or synonym of the preferred subtag. Either + # way, it is close enough to the truth to consider the replacement + # the macrolanguage of the deprecated language. + has_preferred_value = True + macrolanguage = line.split (' ')[1] + self._add_macrolanguage (macrolanguage, subtag) + elif not has_preferred_value and line.startswith ('Macrolanguage: '): + self._add_macrolanguage (line.split (' ')[1], subtag) + elif subtag_type == 'variant': + if line.startswith ('Prefix: '): + self.prefixes[subtag].add (line.split (' ')[1]) + elif line.startswith ('File-Date: '): + self.header = line + expect (self.header) + + def _add_macrolanguage (self, macrolanguage, language): + global ot + if language not in ot.from_bcp_47: + for l in self.macrolanguages.get (language, set ()): + self._add_macrolanguage (macrolanguage, l) + if macrolanguage not in ot.from_bcp_47: + for ls in list (self.macrolanguages.values ()): + if macrolanguage in ls: + ls.add (language) + return + self.macrolanguages[macrolanguage].add (language) + + def remove_extra_macrolanguages (self): + """Make every language have at most one macrolanguage.""" + inverted = collections.defaultdict (list) + for macrolanguage, languages in self.macrolanguages.items (): + for language in languages: + inverted[language].append (macrolanguage) + for language, macrolanguages in inverted.items (): + if len (macrolanguages) > 1: + macrolanguages.sort (key=lambda ml: len (self.macrolanguages[ml])) + biggest_macrolanguage = macrolanguages.pop () + for macrolanguage in macrolanguages: + self._add_macrolanguage (biggest_macrolanguage, macrolanguage) + + def get_name (self, lt): + """Return the names of the subtags in a language tag. + + Args: + lt (LanguageTag): A BCP 47 language tag. + + Returns: + The name form of ``lt``. + """ + name = self.names[lt.language].split ('\n')[0] + if lt.script: + name += '; ' + self.names[lt.script.title ()].split ('\n')[0] + if lt.region: + name += '; ' + self.names[lt.region.upper ()].split ('\n')[0] + if lt.variant: + name += '; ' + self.names[lt.variant].split ('\n')[0] + return name + +bcp_47 = BCP47Parser () + +ot.parse (sys.argv[1]) +bcp_47.parse (sys.argv[2]) + +ot.add_language ('ary', 'MOR') + +ot.add_language ('ath', 'ATH') + +ot.add_language ('bai', 'BML') + +ot.ranks['BAL'] = ot.ranks['KAR'] + 1 + +ot.add_language ('ber', 'BBR') + +ot.remove_language_ot ('PGR') +ot.add_language ('el-polyton', 'PGR') + +bcp_47.macrolanguages['et'] = {'ekk'} + +bcp_47.names['flm'] = 'Falam Chin' +bcp_47.scopes['flm'] = ' (retired code)' +bcp_47.macrolanguages['flm'] = {'cfm'} + +ot.ranks['FNE'] = ot.ranks['TNE'] + 1 + +ot.add_language ('und-fonipa', 'IPPH') + +ot.add_language ('und-fonnapa', 'APPH') + +ot.remove_language_ot ('IRT') +ot.add_language ('ga-Latg', 'IRT') + +ot.remove_language_ot ('KGE') +ot.add_language ('und-Geok', 'KGE') + +ot.add_language ('guk', 'GUK') +ot.names['GUK'] = 'Gumuz (SIL fonts)' +ot.ranks['GUK'] = ot.ranks['GMZ'] + 1 + +bcp_47.macrolanguages['id'] = {'in'} + +bcp_47.macrolanguages['ijo'] = {'ijc'} + +ot.add_language ('kht', 'KHN') +ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)' +ot.names['KHT'] = ot.names['KHT'] + ' (OpenType spec and SIL fonts)' +ot.ranks['KHN'] = ot.ranks['KHT'] +ot.ranks['KHT'] += 1 + +ot.ranks['LCR'] = ot.ranks['MCR'] + 1 + +ot.names['MAL'] = 'Malayalam Traditional' +ot.ranks['MLR'] += 1 + +bcp_47.names['mhv'] = 'Arakanese' +bcp_47.scopes['mhv'] = ' (retired code)' + +ot.add_language ('no', 'NOR') + +ot.add_language ('oc-provenc', 'PRO') + +ot.add_language ('qu', 'QUZ') +ot.add_language ('qub', 'QWH') +ot.add_language ('qud', 'QVI') +ot.add_language ('qug', 'QVI') +ot.add_language ('qup', 'QVI') +ot.add_language ('qur', 'QWH') +ot.add_language ('qus', 'QUH') +ot.add_language ('quw', 'QVI') +ot.add_language ('qux', 'QWH') +ot.add_language ('qva', 'QWH') +ot.add_language ('qvh', 'QWH') +ot.add_language ('qvj', 'QVI') +ot.add_language ('qvl', 'QWH') +ot.add_language ('qvm', 'QWH') +ot.add_language ('qvn', 'QWH') +ot.add_language ('qvo', 'QVI') +ot.add_language ('qvp', 'QWH') +ot.add_language ('qvw', 'QWH') +ot.add_language ('qvz', 'QVI') +ot.add_language ('qwa', 'QWH') +ot.add_language ('qws', 'QWH') +ot.add_language ('qxa', 'QWH') +ot.add_language ('qxc', 'QWH') +ot.add_language ('qxh', 'QWH') +ot.add_language ('qxl', 'QVI') +ot.add_language ('qxn', 'QWH') +ot.add_language ('qxo', 'QWH') +ot.add_language ('qxr', 'QVI') +ot.add_language ('qxt', 'QWH') +ot.add_language ('qxw', 'QWH') + +bcp_47.macrolanguages['ro'].remove ('mo') +bcp_47.macrolanguages['ro-MD'].add ('mo') + +ot.add_language ('sgw', 'SGW') +ot.names['SGW'] = ot.names['CHG'] + ' (SIL fonts)' +ot.ranks['SGW'] = ot.ranks['CHG'] + 1 + +ot.remove_language_ot ('SYRE') +ot.remove_language_ot ('SYRJ') +ot.remove_language_ot ('SYRN') +ot.add_language ('und-Syre', 'SYRE') +ot.add_language ('und-Syrj', 'SYRJ') +ot.add_language ('und-Syrn', 'SYRN') + +bcp_47.names['xst'] = u"Silt'e" +bcp_47.scopes['xst'] = ' (retired code)' +bcp_47.macrolanguages['xst'] = {'stv', 'wle'} + +ot.add_language ('xwo', 'TOD') + +ot.remove_language_ot ('ZHH') +ot.remove_language_ot ('ZHP') +ot.remove_language_ot ('ZHT') +bcp_47.macrolanguages['zh'].remove ('lzh') +bcp_47.macrolanguages['zh'].remove ('yue') +ot.add_language ('zh-Hant-MO', 'ZHH') +ot.add_language ('zh-Hant-HK', 'ZHH') +ot.add_language ('zh-Hans', 'ZHS') +ot.add_language ('zh-Hant', 'ZHT') +ot.add_language ('zh-HK', 'ZHH') +ot.add_language ('zh-MO', 'ZHH') +ot.add_language ('zh-TW', 'ZHT') +ot.add_language ('lzh', 'ZHT') +ot.add_language ('lzh-Hans', 'ZHS') +ot.add_language ('yue', 'ZHH') +ot.add_language ('yue-Hans', 'ZHS') + +bcp_47.macrolanguages['zom'] = {'yos'} + +def rank_delta (bcp_47, ot): + """Return a delta to apply to a BCP 47 tag's rank. + + Most OpenType tags have a constant rank, but a few have ranks that + depend on the BCP 47 tag. + + Args: + bcp_47 (str): A BCP 47 tag. + ot (str): An OpenType tag to. + + Returns: + A number to add to ``ot``'s rank when sorting ``bcp_47``'s + OpenType equivalents. + """ + if bcp_47 == 'ak' and ot == 'AKA': + return -1 + if bcp_47 == 'tw' and ot == 'TWI': + return -1 + return 0 + +disambiguation = { + 'ALT': 'alt', + 'ARK': 'rki', + 'BHI': 'bhb', + 'BLN': 'bjt', + 'BTI': 'beb', + 'CCHN': 'cco', + 'CMR': 'swb', + 'CPP': 'crp', + 'CRR': 'crx', + 'DUJ': 'dwu', + 'ECR': 'crj', + 'HAL': 'cfm', + 'HND': 'hnd', + 'KIS': 'kqs', + 'LRC': 'bqi', + 'NDB': 'nd', + 'NIS': 'njz', + 'PLG': 'pce', + 'PRO': 'pro', + 'QIN': 'bgr', + 'QUH': 'quh', + 'QVI': 'qvi', + 'QWH': 'qwh', + 'SIG': 'stv', + 'TNE': 'yrk', + 'ZHH': 'zh-HK', + 'ZHS': 'zh-Hans', + 'ZHT': 'zh-Hant', +} + +ot.inherit_from_macrolanguages () +bcp_47.remove_extra_macrolanguages () +ot.inherit_from_macrolanguages () +ot.sort_languages () + +print ('/* == Start of generated table == */') +print ('/*') +print (' * The following table is generated by running:') +print (' *') +print (' * %s languagetags language-subtag-registry' % sys.argv[0]) +print (' *') +print (' * on files with these headers:') +print (' *') +print (' * %s' % ot.header.strip ()) +print (' * %s' % bcp_47.header) +print (' */') +print () +print ('#ifndef HB_OT_TAG_TABLE_HH') +print ('#define HB_OT_TAG_TABLE_HH') +print () +print ('static const LangTag ot_languages[] = {') + +def hb_tag (tag): + """Convert a tag to ``HB_TAG`` form. + + Args: + tag (str): An OpenType tag. + + Returns: + A snippet of C++ representing ``tag``. + """ + return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4]) + +def get_variant_set (name): + """Return a set of variant language names from a name. + + Args: + name (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + + Returns: + A set of normalized language names. + """ + return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'")) + .encode ('ASCII', 'ignore') + .strip () + for n in re.split ('[\n(),]', name) if n) + +def language_name_intersection (a, b): + """Return the names in common between two language names. + + Args: + a (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + b (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + + Returns: + The normalized language names shared by ``a`` and ``b``. + """ + return get_variant_set (a).intersection (get_variant_set (b)) + +def get_matching_language_name (intersection, candidates): + return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c)))) + +maximum_tags = 0 +for language, tags in sorted (ot.from_bcp_47.items ()): + if language == '' or '-' in language: + continue + print (' {\"%s\",\t{' % language, end='') + maximum_tags = max (maximum_tags, len (tags)) + tag_count = len (tags) + for i, tag in enumerate (tags, start=1): + if i > 1: + print ('\t\t ', end='') + print (hb_tag (tag), end='') + if i == tag_count: + print ('}}', end='') + print (',\t/* ', end='') + bcp_47_name = bcp_47.names.get (language, '') + bcp_47_name_candidates = bcp_47_name.split ('\n') + intersection = language_name_intersection (bcp_47_name, ot.names[tag]) + scope = bcp_47.scopes.get (language, '') + if not intersection: + write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot.names[tag])) + else: + name = get_matching_language_name (intersection, bcp_47_name_candidates) + bcp_47.names[language] = name + write ('%s%s' % (name if len (name) > len (ot.names[tag]) else ot.names[tag], scope)) + print (' */') + +print ('};') +print () +print ('static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == %iu, "");' % maximum_tags) +print () + +print ('/**') +print (' * hb_ot_tags_from_complex_language:') +print (' * @lang_str: a BCP 47 language tag to convert.') +print (' * @limit: a pointer to the end of the substring of @lang_str to consider for') +print (' * conversion.') +print (' * @count: maximum number of language tags to retrieve (IN) and actual number of') +print (' * language tags retrieved (OUT). If no tags are retrieved, it is not modified.') +print (' * @tags: array of size at least @language_count to store the language tag') +print (' * results') +print (' *') +print (' * Converts a multi-subtag BCP 47 language tag to language tags.') +print (' *') +print (' * Return value: Whether any language systems were retrieved.') +print (' **/') +print ('static bool') +print ('hb_ot_tags_from_complex_language (const char *lang_str,') +print ('\t\t\t\t const char *limit,') +print ('\t\t\t\t unsigned int *count /* IN/OUT */,') +print ('\t\t\t\t hb_tag_t *tags /* OUT */)') +print ('{') + +def print_subtag_matches (subtag, new_line): + if subtag: + if new_line: + print () + print ('\t&& ', end='') + print ('subtag_matches (lang_str, limit, "-%s")' % subtag, end='') + +complex_tags = collections.defaultdict (list) +for initial, group in itertools.groupby ((lt_tags for lt_tags in [ + (LanguageTag (language), tags) + for language, tags in sorted (ot.from_bcp_47.items (), + key=lambda i: (-len (i[0]), i[0])) + ] if lt_tags[0].is_complex ()), + key=lambda lt_tags: lt_tags[0].get_group ()): + complex_tags[initial] += group + +for initial, items in sorted (complex_tags.items ()): + if initial != 'und': + continue + for lt, tags in items: + if lt.variant in bcp_47.prefixes: + expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language, + '%s is not a valid prefix of %s' % (lt.language, lt.variant)) + print (' if (', end='') + print_subtag_matches (lt.script, False) + print_subtag_matches (lt.region, False) + print_subtag_matches (lt.variant, False) + print (')') + print (' {') + write (' /* %s */' % bcp_47.get_name (lt)) + print () + if len (tags) == 1: + write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]])) + print () + print (' *count = 1;') + else: + print (' hb_tag_t possible_tags[] = {') + for tag in tags: + write (' %s, /* %s */' % (hb_tag (tag), ot.names[tag])) + print () + print (' };') + print (' for (i = 0; i < %s && i < *count; i++)' % len (tags)) + print (' tags[i] = possible_tags[i];') + print (' *count = i;') + print (' return true;') + print (' }') + +print (' switch (lang_str[0])') +print (' {') +for initial, items in sorted (complex_tags.items ()): + if initial == 'und': + continue + print (" case '%s':" % initial) + for lt, tags in items: + print (' if (', end='') + if lt.grandfathered: + print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='') + else: + string_literal = lt.language[1:] + '-' + if lt.script: + string_literal += lt.script + lt.script = None + if lt.region: + string_literal += '-' + lt.region + lt.region = None + if string_literal[-1] == '-': + print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='') + else: + print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='') + print_subtag_matches (lt.script, True) + print_subtag_matches (lt.region, True) + print_subtag_matches (lt.variant, True) + print (')') + print (' {') + write (' /* %s */' % bcp_47.get_name (lt)) + print () + if len (tags) == 1: + write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]])) + print () + print (' *count = 1;') + else: + print (' unsigned int i;') + print (' hb_tag_t possible_tags[] = {') + for tag in tags: + write ('\t%s, /* %s */' % (hb_tag (tag), ot.names[tag])) + print () + print (' };') + print (' for (i = 0; i < %s && i < *count; i++)' % len (tags)) + print ('\ttags[i] = possible_tags[i];') + print (' *count = i;') + print (' return true;') + print (' }') + print (' break;') + +print (' }') +print (' return false;') +print ('}') +print () +print ('/**') +print (' * hb_ot_ambiguous_tag_to_language') +print (' * @tag: A language tag.') +print (' *') +print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to') +print (' * many language tags) and the best tag is not the alphabetically first, or if') +print (' * the best tag consists of multiple subtags.') +print (' *') +print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,') +print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.') +print (' **/') +print ('static hb_language_t') +print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)') +print ('{') +print (' switch (tag)') +print (' {') + +def verify_disambiguation_dict (): + """Verify and normalize ``disambiguation``. + + ``disambiguation`` is a map of ambiguous OpenType language system + tags to the particular BCP 47 tags they correspond to. This function + checks that all its keys really are ambiguous and that each key's + value is valid for that key. It checks that no ambiguous tag is + missing, except when it can figure out which BCP 47 tag is the best + by itself. + + It modifies ``disambiguation`` to remove keys whose values are the + same as those that the fallback would return anyway, and to add + ambiguous keys whose disambiguations it determined automatically. + + Raises: + AssertionError: Verification failed. + """ + global bcp_47 + global disambiguation + global ot + for ot_tag, bcp_47_tags in ot.to_bcp_47.items (): + primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag) + if len (primary_tags) == 1: + expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag) + if '-' in primary_tags[0]: + disambiguation[ot_tag] = primary_tags[0] + elif len (primary_tags) == 0: + expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag) + else: + macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]') + if len (macrolanguages) != 1: + macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [family]') + if len (macrolanguages) != 1: + macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, '')) + if len (macrolanguages) != 1: + expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages))) + expect (disambiguation[ot_tag] in bcp_47_tags, + '%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag)) + elif ot_tag not in disambiguation: + disambiguation[ot_tag] = macrolanguages[0] + if disambiguation[ot_tag] == sorted (primary_tags)[0] and '-' not in disambiguation[ot_tag]: + del disambiguation[ot_tag] + for ot_tag in disambiguation.keys (): + expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag) + +verify_disambiguation_dict () +for ot_tag, bcp_47_tag in sorted (disambiguation.items ()): + write (' case %s: /* %s */' % (hb_tag (ot_tag), ot.names[ot_tag])) + print () + write (' return hb_language_from_string (\"%s\", -1); /* %s */' % (bcp_47_tag, bcp_47.get_name (LanguageTag (bcp_47_tag)))) + print () + +print (' default:') +print (' return HB_LANGUAGE_INVALID;') +print (' }') +print ('}') + +print () +print ('#endif /* HB_OT_TAG_TABLE_HH */') +print () +print ('/* == End of generated table == */') + diff --git a/src/gen-use-table.py b/src/gen-use-table.py index 6aa5f88..be204b6 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -1,14 +1,16 @@ #!/usr/bin/env python +# flake8: noqa from __future__ import print_function, division, absolute_import -import io, sys +import io +import sys if len (sys.argv) != 5: print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr) sys.exit (1) -BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"] +BLACKLISTED_BLOCKS = ["Thai", "Lao"] files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]] @@ -47,6 +49,11 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block') data[0][0x034F] = defaults[0] data[0][0x2060] = defaults[0] data[0][0x20F0] = defaults[0] +# TODO https://github.com/roozbehp/unicode-data/issues/9 +data[0][0x11C44] = 'Consonant_Placeholder' +data[0][0x11C45] = 'Consonant_Placeholder' +# TODO https://github.com/harfbuzz/harfbuzz/pull/1399 +data[0][0x111C8] = 'Consonant_Placeholder' for u in range (0xFE00, 0xFE0F + 1): data[0][u] = defaults[0] @@ -165,7 +172,7 @@ def is_BASE(U, UISC, UGC): def is_BASE_IND(U, UISC, UGC): #SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po) return (UISC in [Consonant_Dead, Modifying_Letter] or - (UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45]) or + (UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or False # SPEC-DRAFT-OUTDATED! U == 0x002D ) def is_BASE_NUM(U, UISC, UGC): @@ -194,7 +201,11 @@ def is_CONS_SUB(U, UISC, UGC): def is_CONS_WITH_STACKER(U, UISC, UGC): return UISC == Consonant_With_Stacker def is_HALANT(U, UISC, UGC): - return UISC in [Virama, Invisible_Stacker] + return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC) +def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC): + # https://github.com/harfbuzz/harfbuzz/issues/1102 + # https://github.com/harfbuzz/harfbuzz/issues/1379 + return U in [0x11046, 0x1134D] def is_HALANT_NUM(U, UISC, UGC): return UISC == Number_Joiner def is_ZWNJ(U, UISC, UGC): @@ -245,6 +256,7 @@ use_mapping = { 'SUB': is_CONS_SUB, 'CS': is_CONS_WITH_STACKER, 'H': is_HALANT, + 'HVM': is_HALANT_OR_VOWEL_MODIFIER, 'HN': is_HALANT_NUM, 'ZWNJ': is_ZWNJ, 'ZWJ': is_ZWJ, @@ -278,8 +290,8 @@ use_positions = { 'V': { 'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right], 'Blw': [Bottom, Overstruck, Bottom_And_Right], - 'Pst': [Right], - 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], + 'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], + 'Pre': [Left], }, 'VM': { 'Abv': [Top], @@ -292,6 +304,7 @@ use_positions = { 'Blw': [Bottom], }, 'H': None, + 'HVM': None, 'B': None, 'FM': None, 'SUB': None, @@ -304,11 +317,28 @@ def map_to_use(data): # Resolve Indic_Syllabic_Category - # TODO: These don't have UISC assigned in Unicode 8.0, but - # have UIPC + # TODO: These don't have UISC assigned in Unicode 8.0, but have UIPC if U == 0x17DD: UISC = Vowel_Dependent if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark + # Tibetan: + # TODO: These don't have UISC assigned in Unicode 11.0, but have UIPC + if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent + if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark + # Overrides to allow NFC order matching syllable + # https://github.com/harfbuzz/harfbuzz/issues/1012 + if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC): + if UIPC == Top: + UIPC = Bottom + + # TODO: https://github.com/harfbuzz/harfbuzz/pull/982 + # also https://github.com/harfbuzz/harfbuzz/issues/1012 + if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC): + if UIPC == Top: + UIPC = Bottom + elif UIPC == Bottom: + UIPC = Top + # TODO: https://github.com/harfbuzz/harfbuzz/pull/627 if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom @@ -325,6 +355,12 @@ def map_to_use(data): # TODO: https://github.com/harfbuzz/harfbuzz/pull/626 if U == 0xA8B4: UISC = Consonant_Medial + # TODO: https://github.com/harfbuzz/harfbuzz/issues/1105 + if U == 0x11134: UISC = Gemination_Mark + + # TODO: https://github.com/harfbuzz/harfbuzz/pull/1399 + if U == 0x111C9: UISC = Consonant_Final + values = [k for k,v in items if v(U,UISC,UGC)] assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values) USE = values[0] @@ -344,6 +380,9 @@ def map_to_use(data): if 0xA926 <= U <= 0xA92A: UIPC = Top if U == 0x111CA: UIPC = Bottom if U == 0x11300: UIPC = Top + # TODO: https://github.com/harfbuzz/harfbuzz/pull/1037 + if U == 0x11302: UIPC = Top + if U == 0x1133C: UIPC = Bottom if U == 0x1171E: UIPC = Left # Correct?! if 0x1CF2 <= U <= 0x1CF3: UIPC = Right if 0x1CF8 <= U <= 0x1CF9: UIPC = Top @@ -378,7 +417,7 @@ for h in headers: print (" * %s" % (l.strip())) print (" */") print () -print ('#include "hb-ot-shape-complex-use-private.hh"') +print ('#include "hb-ot-shape-complex-use.hh"') print () total = 0 @@ -416,6 +455,8 @@ num = 0 offset = 0 starts = [] ends = [] +print ('#pragma GCC diagnostic push') +print ('#pragma GCC diagnostic ignored "-Wunused-macros"') for k,v in sorted(use_mapping.items()): if k in use_positions and use_positions[k]: continue print ("#define %s USE_%s /* %s */" % (k, k, v.__name__[3:])) @@ -424,6 +465,7 @@ for k,v in sorted(use_positions.items()): for suf in v.keys(): tag = k + suf print ("#define %s USE_%s" % (tag, tag)) +print ('#pragma GCC diagnostic pop') print ("") print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {") for u in uu: diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py new file mode 100755 index 0000000..b7f6be2 --- /dev/null +++ b/src/gen-vowel-constraints.py @@ -0,0 +1,219 @@ +#!/usr/bin/python + +"""Generator of the function to prohibit certain vowel sequences. + +It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted +circles into sequences prohibited by the USE script development spec. +This function should be used as the ``preprocess_text`` of an +``hb_ot_complex_shaper_t``. +""" + +from __future__ import absolute_import, division, print_function, unicode_literals + +import collections +try: + from HTMLParser import HTMLParser + def write (s): + print (s.encode ('utf-8'), end='') +except ImportError: + from html.parser import HTMLParser + def write (s): + sys.stdout.flush () + sys.stdout.buffer.write (s.encode ('utf-8')) +import itertools +import io +import sys + +if len (sys.argv) != 3: + print ('usage: ./gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt', file=sys.stderr) + sys.exit (1) + +with io.open (sys.argv[2], encoding='utf-8') as f: + scripts_header = [f.readline () for i in range (2)] + scripts = {} + script_order = {} + for line in f: + j = line.find ('#') + if j >= 0: + line = line[:j] + fields = [x.strip () for x in line.split (';')] + if len (fields) == 1: + continue + uu = fields[0].split ('..') + start = int (uu[0], 16) + if len (uu) == 1: + end = start + else: + end = int (uu[1], 16) + script = fields[1] + for u in range (start, end + 1): + scripts[u] = script + if script not in script_order: + script_order[script] = start + +class ConstraintSet (object): + """A set of prohibited code point sequences. + + Args: + constraint (List[int]): A prohibited code point sequence. + + """ + def __init__ (self, constraint): + # Either a list or a dictionary. As a list of code points, it + # represents a prohibited code point sequence. As a dictionary, + # it represents a set of prohibited sequences, where each item + # represents the set of prohibited sequences starting with the + # key (a code point) concatenated with any of the values + # (ConstraintSets). + self._c = constraint + + def add (self, constraint): + """Add a constraint to this set.""" + if not constraint: + return + first = constraint[0] + rest = constraint[1:] + if isinstance (self._c, list): + if constraint == self._c[:len (constraint)]: + self._c = constraint + elif self._c != constraint[:len (self._c)]: + self._c = {self._c[0]: ConstraintSet (self._c[1:])} + if isinstance (self._c, dict): + if first in self._c: + self._c[first].add (rest) + else: + self._c[first] = ConstraintSet (rest) + + def _indent (self, depth): + return (' ' * depth).replace (' ', '\t') + + def __str__ (self, index=0, depth=4): + s = [] + indent = self._indent (depth) + if isinstance (self._c, list): + if len (self._c) == 0: + s.append ('{}matched = true;\n'.format (indent)) + elif len (self._c) == 1: + s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or '')) + else: + s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index)) + s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c))) + for i, cp in enumerate (self._c[1:], start=1): + s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format ( + self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&')) + s.append ('{}{{\n'.format (indent)) + for i in range (len (self._c)): + s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1))) + s.append ('{}_output_dotted_circle (buffer);\n'.format (self._indent (depth + 1))) + s.append ('{}}}\n'.format (indent)) + else: + s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or '')) + s.append ('{}{{\n'.format (indent)) + cases = collections.defaultdict (set) + for first, rest in sorted (self._c.items ()): + cases[rest.__str__ (index + 1, depth + 2)].add (first) + for body, labels in sorted (cases.items (), key=lambda b_ls: sorted (b_ls[1])[0]): + for i, cp in enumerate (sorted (labels)): + if i % 4 == 0: + s.append (self._indent (depth + 1)) + else: + s.append (' ') + s.append ('case 0x{:04X}u:{}'.format (cp, '\n' if i % 4 == 3 else '')) + if len (labels) % 4 != 0: + s.append ('\n') + s.append (body) + s.append ('{}break;\n'.format (self._indent (depth + 2))) + s.append ('{}}}\n'.format (indent)) + return ''.join (s) + +constraints = {} +with io.open (sys.argv[1], encoding='utf-8') as f: + constraints_header = [f.readline ().strip () for i in range (2)] + for line in f: + j = line.find ('#') + if j >= 0: + line = line[:j] + constraint = [int (cp, 16) for cp in line.split (';')[0].split ()] + if not constraint: continue + assert 2 <= len (constraint), 'Prohibited sequence is too short: {}'.format (constraint) + script = scripts[constraint[0]] + if script in constraints: + constraints[script].add (constraint) + else: + constraints[script] = ConstraintSet (constraint) + assert constraints, 'No constraints found' + +print ('/* == Start of generated functions == */') +print ('/*') +print (' * The following functions are generated by running:') +print (' *') +print (' * %s use Scripts.txt' % sys.argv[0]) +print (' *') +print (' * on files with these headers:') +print (' *') +for line in constraints_header: + print (' * %s' % line.strip ()) +print (' *') +for line in scripts_header: + print (' * %s' % line.strip ()) +print (' */') +print () +print ('#include "hb-ot-shape-complex-vowel-constraints.hh"') +print () +print ('static void') +print ('_output_dotted_circle (hb_buffer_t *buffer)') +print ('{') +print (' hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);') +print (' _hb_glyph_info_reset_continuation (&dottedcircle);') +print ('}') +print () +print ('static void') +print ('_output_with_dotted_circle (hb_buffer_t *buffer)') +print ('{') +print (' _output_dotted_circle (buffer);') +print (' buffer->next_glyph ();') +print ('}') +print () + +print ('void') +print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,') +print ('\t\t\t\t hb_buffer_t *buffer,') +print ('\t\t\t\t hb_font_t *font HB_UNUSED)') +print ('{') +print (' /* UGLY UGLY UGLY business of adding dotted-circle in the middle of') +print (' * vowel-sequences that look like another vowel. Data for each script') +print (' * collected from the USE script development spec.') +print (' *') +print (' * https://github.com/harfbuzz/harfbuzz/issues/1019') +print (' */') +print (' bool processed = false;') +print (' buffer->clear_output ();') +print (' unsigned int count = buffer->len;') +print (' switch ((unsigned) buffer->props.script)') +print (' {') + +for script, constraints in sorted (constraints.items (), key=lambda s_c: script_order[s_c[0]]): + print (' case HB_SCRIPT_{}:'.format (script.upper ())) + print (' for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)') + print (' {') + print ('\tbool matched = false;') + write (str (constraints)) + print ('\tbuffer->next_glyph ();') + print ('\tif (matched) _output_with_dotted_circle (buffer);') + print (' }') + print (' processed = true;') + print (' break;') + print () + +print (' default:') +print (' break;') +print (' }') +print (' if (processed)') +print (' {') +print (' if (buffer->idx < count)') +print (' buffer->next_glyph ();') +print (' }') +print ('}') + +print () +print ('/* == End of generated functions == */') diff --git a/src/harfbuzz-config.cmake.in b/src/harfbuzz-config.cmake.in index 87b1572..304410d 100644 --- a/src/harfbuzz-config.cmake.in +++ b/src/harfbuzz-config.cmake.in @@ -12,7 +12,11 @@ set(_harfbuzz_libdir "@libdir@") string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}") set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}") while (_harfbuzz_libdir_iter) + set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}") get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY) + if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter) + break() + endif () get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY) endwhile () unset(_harfbuzz_libdir_iter) diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh new file mode 100644 index 0000000..1188e35 --- /dev/null +++ b/src/hb-aat-fdsc-table.hh @@ -0,0 +1,126 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#ifndef HB_AAT_FDSC_TABLE_HH +#define HB_AAT_FDSC_TABLE_HH + +#include "hb-aat-layout-common.hh" +#include "hb-open-type.hh" + +/* + * fdsc -- Font descriptors + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html + */ +#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c') + + +namespace AAT { + + +struct FontDescriptor +{ + bool has_data () const { return tag; } + + int cmp (hb_tag_t a) const { return tag.cmp (a); } + + float get_value () const { return u.value.to_float (); } + + enum non_alphabetic_value_t { + Alphabetic = 0, + Dingbats = 1, + PiCharacters = 2, + Fleurons = 3, + DecorativeBorders = 4, + InternationalSymbols= 5, + MathSymbols = 6 + }; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + Tag tag; /* The 4-byte table tag name. */ + union { + Fixed value; /* The value for the descriptor tag. */ + HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */ + } u; + public: + DEFINE_SIZE_STATIC (8); +}; + +struct fdsc +{ + static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc; + + enum { + Weight = HB_TAG ('w','g','h','t'), + /* Percent weight relative to regular weight. + * (defaul value: 1.0) */ + Width = HB_TAG ('w','d','t','h'), + /* Percent width relative to regular width. + * (default value: 1.0) */ + Slant = HB_TAG ('s','l','n','t'), + /* Angle of slant in degrees, where positive + * is clockwise from straight up. + * (default value: 0.0) */ + OpticalSize = HB_TAG ('o','p','s','z'), + /* Point size the font was designed for. + * (default value: 12.0) */ + NonAlphabetic= HB_TAG ('n','a','l','f') + /* These values are treated as integers, + * not fixed32s. 0 means alphabetic, and greater + * integers mean the font is non-alphabetic (e.g. symbols). + * (default value: 0) */ + }; + + const FontDescriptor &get_descriptor (hb_tag_t style) const + { return descriptors.lsearch (style); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + descriptors.sanitize (c)); + } + + protected: + Fixed version; /* Version number of the font descriptors + * table (0x00010000 for the current version). */ + LArrayOf<FontDescriptor> + descriptors; /* List of tagged-coordinate pairs style descriptors + * that will be included to characterize this font. + * Each descriptor consists of a <tag, value> pair. + * These pairs are located in the gxFontDescriptor + * array that follows. */ + public: + DEFINE_SIZE_ARRAY (8, descriptors); +}; + +} /* namespace AAT */ + + +#endif /* HB_AAT_FDSC_TABLE_HH */ diff --git a/src/hb-aat-fmtx-table.hh b/src/hb-aat-fmtx-table.hh deleted file mode 100644 index aa82c88..0000000 --- a/src/hb-aat-fmtx-table.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * 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. - */ - -#ifndef HB_AAT_FMTX_TABLE_HH -#define HB_AAT_FMTX_TABLE_HH - -#include "hb-aat-layout-common-private.hh" - -/* - * fmtx -- Font Metrics - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fmtx.html - */ -#define HB_AAT_TAG_fmtx HB_TAG('f','m','t','x') - - -namespace AAT { - - -struct fmtx -{ - static const hb_tag_t tableTag = HB_AAT_TAG_fmtx; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); - } - - FixedVersion<>version; /* Version (set to 0x00020000). */ - HBUINT32 glyphIndex; /* The glyph whose points represent the metrics. */ - HBUINT8 horizontalBefore; /* Point number for the horizontal ascent. */ - HBUINT8 horizontalAfter; /* Point number for the horizontal descent. */ - HBUINT8 horizontalCaretHead; /* Point number for the horizontal caret head. */ - HBUINT8 horizontalCaretBase; /* Point number for the horizontal caret base. */ - HBUINT8 verticalBefore; /* Point number for the vertical ascent. */ - HBUINT8 verticalAfter; /* Point number for the vertical descent. */ - HBUINT8 verticalCaretHead; /* Point number for the vertical caret head. */ - HBUINT8 verticalCaretBase; /* Point number for the vertical caret base. */ - public: - DEFINE_SIZE_STATIC (16); -}; - -} /* namespace AAT */ - - -#endif /* HB_AAT_FMTX_TABLE_HH */ diff --git a/src/hb-aat-gcid-table.hh b/src/hb-aat-gcid-table.hh deleted file mode 100644 index b48a279..0000000 --- a/src/hb-aat-gcid-table.hh +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * 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. - */ - -#ifndef HB_AAT_GCID_TABLE_HH -#define HB_AAT_GCID_TABLE_HH - -#include "hb-aat-layout-common-private.hh" - -/* - * gcid -- Glyphs CIDs - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gcid.html - */ -#define HB_AAT_TAG_gcid HB_TAG('g','c','i','d') - - -namespace AAT { - - -struct gcid -{ - static const hb_tag_t tableTag = HB_AAT_TAG_gcid; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && CIDs.sanitize (c))); - } - - protected: - HBUINT16 version; /* Version number (set to 0) */ - HBUINT16 format; /* Data format (set to 0) */ - HBUINT32 size; /* Size of the table, including header */ - HBUINT16 registry; /* The registry ID */ - HBUINT8 registryName[64]; - /* The registry name in ASCII */ - HBUINT16 order; /* The order ID */ - HBUINT8 orderName[64]; /* The order name in ASCII */ - HBUINT16 supplementVersion; - /* The supplement version */ - ArrayOf<HBUINT16> - CIDs; /* The CIDs for the glyphs in the font, - * starting with glyph 0. If a glyph does not correspond - * to a CID in the identified collection, 0xFFFF is used. - * This should not exceed the number of glyphs in the font. */ - public: - DEFINE_SIZE_ARRAY (144, CIDs); -}; - -} /* namespace AAT */ - - -#endif /* HB_AAT_GCID_TABLE_HH */ diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh index 3b7912b..236e4aa 100644 --- a/src/hb-aat-layout-ankr-table.hh +++ b/src/hb-aat-layout-ankr-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH #define HB_AAT_LAYOUT_ANKR_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * ankr -- Anchor Point @@ -36,41 +36,56 @@ namespace AAT { +using namespace OT; + struct Anchor { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } + public: FWORD xCoordinate; FWORD yCoordinate; public: DEFINE_SIZE_STATIC (4); }; +typedef LArrayOf<Anchor> GlyphAnchors; + struct ankr { - static const hb_tag_t tableTag = HB_AAT_TAG_ankr; + static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr; + + const Anchor &get_anchor (hb_codepoint_t glyph_id, + unsigned int i, + unsigned int num_glyphs) const + { + const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs); + if (!offset) + return Null(Anchor); + const GlyphAnchors &anchors = &(this+anchorData) + *offset; + return anchors[i]; + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && version == 0 && - lookupTable.sanitize (c, this) && - anchors.sanitize (c, this))); + lookupTable.sanitize (c, this, &(this+anchorData)))); } protected: HBUINT16 version; /* Version number (set to zero) */ HBUINT16 flags; /* Flags (currently unused; set to zero) */ - LOffsetTo<Lookup<HBUINT16> > + LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > > lookupTable; /* Offset to the table's lookup table */ - LOffsetTo<LArrayOf<Anchor> > - anchors; /* Offset to the glyph data table */ + LNNOffsetTo<HBUINT8> + anchorData; /* Offset to the glyph data table */ public: DEFINE_SIZE_STATIC (12); diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh index df2bf5b..9139d28 100644 --- a/src/hb-aat-layout-bsln-table.hh +++ b/src/hb-aat-layout-bsln-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH #define HB_AAT_LAYOUT_BSLN_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * bsln -- Baseline @@ -39,7 +39,7 @@ namespace AAT { struct BaselineTableFormat0Part { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this))); @@ -57,7 +57,7 @@ struct BaselineTableFormat0Part struct BaselineTableFormat1Part { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && @@ -75,7 +75,7 @@ struct BaselineTableFormat1Part struct BaselineTableFormat2Part { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this))); @@ -98,7 +98,7 @@ struct BaselineTableFormat2Part struct BaselineTableFormat3Part { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && lookupTable.sanitize (c)); @@ -116,15 +116,16 @@ struct BaselineTableFormat3Part struct bsln { - static const hb_tag_t tableTag = HB_AAT_TAG_bsln; + static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && defaultBaseline < 32))) return_trace (false); - switch (format) { + switch (format) + { case 0: return_trace (parts.format0.sanitize (c)); case 1: return_trace (parts.format1.sanitize (c)); case 2: return_trace (parts.format2.sanitize (c)); diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common-private.hh deleted file mode 100644 index 2825b18..0000000 --- a/src/hb-aat-layout-common-private.hh +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Copyright © 2017 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): Behdad Esfahbod - */ - -#ifndef HB_AAT_LAYOUT_COMMON_PRIVATE_HH -#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH - -#include "hb-aat-layout-private.hh" - - -namespace AAT { - -using namespace OT; - - -/* - * Binary Searching Tables - */ - -struct BinSearchHeader -{ - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ - HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ - HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 - * that is less than or equal to the value of nUnits. */ - HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than - * or equal to the value of nUnits. */ - HBUINT16 rangeShift; /* The value of unitSize times the difference of the - * value of nUnits minus the largest power of 2 less - * than or equal to the value of nUnits. */ - public: - DEFINE_SIZE_STATIC (10); -}; - -template <typename Type> -struct BinSearchArrayOf -{ - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= header.nUnits)) return Null(Type); - return StructAtOffset<Type> (bytesZ, i * header.unitSize); - } - inline Type& operator [] (unsigned int i) - { - return StructAtOffset<Type> (bytesZ, i * header.unitSize); - } - inline unsigned int get_size (void) const - { return header.static_size + header.nUnits * header.unitSize; } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && StructAtOffset<Type> (bytesZ, 0).sanitize (c)); - - return_trace (true); - } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = header.nUnits; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - - template <typename T> - inline const Type *bsearch (const T &key) const - { - unsigned int size = header.unitSize; - int min = 0, max = (int) header.nUnits - 1; - while (min <= max) - { - int mid = (min + max) / 2; - const Type *p = (const Type *) (((const char *) bytesZ) + (mid * size)); - int c = p->cmp (key); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - return p; - } - return nullptr; - } - - private: - inline bool sanitize_shallow (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (header.sanitize (c) && - Type::static_size >= header.unitSize && - c->check_array (bytesZ, header.unitSize, header.nUnits)); - } - - protected: - BinSearchHeader header; - HBUINT8 bytesZ[VAR]; - public: - DEFINE_SIZE_ARRAY (10, bytesZ); -}; - - -/* - * Lookup Table - */ - -template <typename T> struct Lookup; - -template <typename T> -struct LookupFormat0 -{ - friend struct Lookup<T>; - - private: - inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const - { - if (unlikely (glyph_id >= num_glyphs)) return nullptr; - return &arrayZ[glyph_id]; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (arrayZ.sanitize (c, c->num_glyphs)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 0 */ - UnsizedArrayOf<T> - arrayZ; /* Array of lookup values, indexed by glyph index. */ - public: - DEFINE_SIZE_ARRAY (2, arrayZ); -}; - - -template <typename T> -struct LookupSegmentSingle -{ - inline int cmp (hb_codepoint_t g) const { - return g < first ? -1 : g <= last ? 0 : +1 ; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && value.sanitize (c)); - } - - GlyphID last; /* Last GlyphID in this segment */ - GlyphID first; /* First GlyphID in this segment */ - T value; /* The lookup value (only one) */ - public: - DEFINE_SIZE_STATIC (4 + T::static_size); -}; - -template <typename T> -struct LookupFormat2 -{ - friend struct Lookup<T>; - - private: - inline const T* get_value (hb_codepoint_t glyph_id) const - { - const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id); - return v ? &v->value : nullptr; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (segments.sanitize (c)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - BinSearchArrayOf<LookupSegmentSingle<T> > - segments; /* The actual segments. These must already be sorted, - * according to the first word in each one (the last - * glyph in each segment). */ - public: - DEFINE_SIZE_ARRAY (8, segments); -}; - -template <typename T> -struct LookupSegmentArray -{ - inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const - { - return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; - } - - inline int cmp (hb_codepoint_t g) const { - return g < first ? -1 : g <= last ? 0 : +1 ; - } - - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - first <= last && - valuesZ.sanitize (c, base, last - first + 1)); - } - - GlyphID last; /* Last GlyphID in this segment */ - GlyphID first; /* First GlyphID in this segment */ - OffsetTo<UnsizedArrayOf<T> > - valuesZ; /* A 16-bit offset from the start of - * the table to the data. */ - public: - DEFINE_SIZE_STATIC (6); -}; - -template <typename T> -struct LookupFormat4 -{ - friend struct Lookup<T>; - - private: - inline const T* get_value (hb_codepoint_t glyph_id) const - { - const LookupSegmentArray<T> *v = segments.bsearch (glyph_id); - return v ? v->get_value (glyph_id, this) : nullptr; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (segments.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - BinSearchArrayOf<LookupSegmentArray<T> > - segments; /* The actual segments. These must already be sorted, - * according to the first word in each one (the last - * glyph in each segment). */ - public: - DEFINE_SIZE_ARRAY (8, segments); -}; - -template <typename T> -struct LookupSingle -{ - inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && value.sanitize (c)); - } - - GlyphID glyph; /* Last GlyphID */ - T value; /* The lookup value (only one) */ - public: - DEFINE_SIZE_STATIC (4 + T::static_size); -}; - -template <typename T> -struct LookupFormat6 -{ - friend struct Lookup<T>; - - private: - inline const T* get_value (hb_codepoint_t glyph_id) const - { - const LookupSingle<T> *v = entries.bsearch (glyph_id); - return v ? &v->value : nullptr; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (entries.sanitize (c)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 6 */ - BinSearchArrayOf<LookupSingle<T> > - entries; /* The actual entries, sorted by glyph index. */ - public: - DEFINE_SIZE_ARRAY (8, entries); -}; - -template <typename T> -struct LookupFormat8 -{ - friend struct Lookup<T>; - - private: - inline const T* get_value (hb_codepoint_t glyph_id) const - { - return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 6 */ - GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ - HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last - * glyph minus the value of firstGlyph plus 1). */ - UnsizedArrayOf<T> - valueArrayZ; /* The lookup values (indexed by the glyph index - * minus the value of firstGlyph). */ - public: - DEFINE_SIZE_ARRAY (6, valueArrayZ); -}; - -template <typename T> -struct Lookup -{ - inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const - { - switch (u.format) { - case 0: return u.format0.get_value (glyph_id, num_glyphs); - case 2: return u.format2.get_value (glyph_id); - case 4: return u.format4.get_value (glyph_id); - case 6: return u.format6.get_value (glyph_id); - case 8: return u.format8.get_value (glyph_id); - default:return nullptr; - } - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); - switch (u.format) { - case 0: return_trace (u.format0.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 4: return_trace (u.format4.sanitize (c)); - case 6: return_trace (u.format6.sanitize (c)); - case 8: return_trace (u.format8.sanitize (c)); - default:return_trace (true); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - LookupFormat0<T> format0; - LookupFormat2<T> format2; - LookupFormat4<T> format4; - LookupFormat6<T> format6; - LookupFormat8<T> format8; - } u; - public: - DEFINE_SIZE_UNION (2, format); -}; - - -/* - * Extended State Table - */ - -template <typename T> -struct Entry -{ - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - /* Note, we don't recurse-sanitize data because we don't access it. - * That said, in our DEFINE_SIZE_STATIC we access T::static_size, - * which ensures that data has a simple sanitize(). To be determined - * if I need to remove that as well. */ - return_trace (c->check_struct (this)); - } - - public: - HBUINT16 newState; /* Byte offset from beginning of state table - * to the new state. Really?!?! Or just state - * number? The latter in morx for sure. */ - HBUINT16 flags; /* Table specific. */ - T data; /* Optional offsets to per-glyph tables. */ - public: - DEFINE_SIZE_STATIC (4 + T::static_size); -}; - -template <> -struct Entry<void> -{ - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - public: - HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ - HBUINT16 flags; /* Table specific. */ - public: - DEFINE_SIZE_STATIC (4); -}; - -template <typename Extra> -struct StateTable -{ - inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const - { - const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs); - return v ? *v : 1; - } - - inline const Entry<Extra> *get_entries () const - { - return (this+entryTable).arrayZ; - } - - inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const - { - if (unlikely (klass >= nClasses)) return nullptr; - - const HBUINT16 *states = (this+stateArrayTable).arrayZ; - const Entry<Extra> *entries = (this+entryTable).arrayZ; - - unsigned int entry = states[state * nClasses + klass]; - - return &entries[entry]; - } - - inline bool sanitize (hb_sanitize_context_t *c, - unsigned int *num_entries_out = nullptr) const - { - TRACE_SANITIZE (this); - if (unlikely (!(c->check_struct (this) && - classTable.sanitize (c, this)))) return_trace (false); - - const HBUINT16 *states = (this+stateArrayTable).arrayZ; - const Entry<Extra> *entries = (this+entryTable).arrayZ; - - unsigned int num_states = 1; - unsigned int num_entries = 0; - - unsigned int state = 0; - unsigned int entry = 0; - while (state < num_states) - { - if (unlikely (!c->check_array (states, - states[0].static_size * nClasses, - num_states))) - return_trace (false); - { /* Sweep new states. */ - const HBUINT16 *stop = &states[num_states * nClasses]; - for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++) - num_entries = MAX<unsigned int> (num_entries, *p + 1); - state = num_states; - } - - if (unlikely (!c->check_array (entries, - entries[0].static_size, - num_entries))) - return_trace (false); - { /* Sweep new entries. */ - const Entry<Extra> *stop = &entries[num_entries]; - for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) - num_states = MAX<unsigned int> (num_states, p->newState + 1); - entry = num_entries; - } - } - - if (num_entries_out) - *num_entries_out = num_entries; - - return_trace (true); - } - - protected: - HBUINT32 nClasses; /* Number of classes, which is the number of indices - * in a single line in the state array. */ - LOffsetTo<Lookup<HBUINT16> > - classTable; /* Offset to the class table. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > - stateArrayTable;/* Offset to the state array. */ - LOffsetTo<UnsizedArrayOf<Entry<Extra> > > - entryTable; /* Offset to the entry array. */ - - public: - DEFINE_SIZE_STATIC (16); -}; - -template <typename EntryData> -struct StateTableDriver -{ - inline StateTableDriver (const StateTable<EntryData> &machine_, - hb_buffer_t *buffer_, - hb_face_t *face_) : - machine (machine_), - buffer (buffer_), - num_glyphs (face_->get_num_glyphs ()) {} - - template <typename context_t> - inline void drive (context_t *c) - { - hb_glyph_info_t *info = buffer->info; - - if (!c->in_place) - buffer->clear_output (); - - unsigned int state = 0; - bool last_was_dont_advance = false; - for (buffer->idx = 0;;) - { - unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (info[buffer->idx].codepoint, num_glyphs) : - 0 /* End of text */; - const Entry<EntryData> *entry = machine.get_entryZ (state, klass); - if (unlikely (!entry)) - break; - - /* Unsafe-to-break before this if not in state 0, as things might - * go differently if we start from state 0 here. */ - if (state && buffer->idx) - { - /* If there's no action and we're just epsilon-transitioning to state 0, - * safe to break. */ - if (c->is_actionable (this, entry) || - !(entry->newState == 0 && entry->flags == context_t::DontAdvance)) - buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1); - } - - /* Unsafe-to-break if end-of-text would kick in here. */ - if (buffer->idx + 2 <= buffer->len) - { - const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0); - if (c->is_actionable (this, end_entry)) - buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); - } - - if (unlikely (!c->transition (this, entry))) - break; - - last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0; - - state = entry->newState; - - if (buffer->idx == buffer->len) - break; - - if (!last_was_dont_advance) - buffer->next_glyph (); - } - - if (!c->in_place) - { - for (; buffer->idx < buffer->len;) - buffer->next_glyph (); - buffer->swap_buffers (); - } - } - - public: - const StateTable<EntryData> &machine; - hb_buffer_t *buffer; - unsigned int num_glyphs; -}; - - - -struct hb_aat_apply_context_t : - hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> -{ - inline const char *get_name (void) { return "APPLY"; } - template <typename T> - inline return_t dispatch (const T &obj) { return obj.apply (this); } - static return_t default_return_value (void) { return false; } - bool stop_sublookup_iteration (return_t r) const { return r; } - - hb_font_t *font; - hb_face_t *face; - hb_buffer_t *buffer; - hb_sanitize_context_t sanitizer; - - /* Unused. For debug tracing only. */ - unsigned int lookup_index; - unsigned int debug_depth; - - inline hb_aat_apply_context_t (hb_font_t *font_, - hb_buffer_t *buffer_, - hb_blob_t *table) : - font (font_), face (font->face), buffer (buffer_), - sanitizer (), lookup_index (0), debug_depth (0) - { - sanitizer.init (table); - sanitizer.num_glyphs = face->get_num_glyphs (); - sanitizer.start_processing (); - } - - inline void set_lookup_index (unsigned int i) { lookup_index = i; } - - inline ~hb_aat_apply_context_t (void) - { - sanitizer.end_processing (); - } -}; - - -} /* namespace AAT */ - - -#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */ diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh new file mode 100644 index 0000000..27ade28 --- /dev/null +++ b/src/hb-aat-layout-common.hh @@ -0,0 +1,845 @@ +/* + * Copyright © 2017 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): Behdad Esfahbod + */ + +#ifndef HB_AAT_LAYOUT_COMMON_HH +#define HB_AAT_LAYOUT_COMMON_HH + +#include "hb-aat-layout.hh" +#include "hb-open-type.hh" + + +namespace AAT { + +using namespace OT; + + +/* + * Lookup Table + */ + +template <typename T> struct Lookup; + +template <typename T> +struct LookupFormat0 +{ + friend struct Lookup<T>; + + private: + const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + if (unlikely (glyph_id >= num_glyphs)) return nullptr; + return &arrayZ[glyph_id]; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (arrayZ.sanitize (c, c->get_num_glyphs ())); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 0 */ + UnsizedArrayOf<T> + arrayZ; /* Array of lookup values, indexed by glyph index. */ + public: + DEFINE_SIZE_UNBOUNDED (2); +}; + + +template <typename T> +struct LookupSegmentSingle +{ + static constexpr unsigned TerminationWordCount = 2u; + + int cmp (hb_codepoint_t g) const + { return g < first ? -1 : g <= last ? 0 : +1 ; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c, base)); + } + + GlyphID last; /* Last GlyphID in this segment */ + GlyphID first; /* First GlyphID in this segment */ + T value; /* The lookup value (only one) */ + public: + DEFINE_SIZE_STATIC (4 + T::static_size); +}; + +template <typename T> +struct LookupFormat2 +{ + friend struct Lookup<T>; + + private: + const T* get_value (hb_codepoint_t glyph_id) const + { + const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id); + return v ? &v->value : nullptr; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c, base)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + VarSizedBinSearchArrayOf<LookupSegmentSingle<T> > + segments; /* The actual segments. These must already be sorted, + * according to the first word in each one (the last + * glyph in each segment). */ + public: + DEFINE_SIZE_ARRAY (8, segments); +}; + +template <typename T> +struct LookupSegmentArray +{ + static constexpr unsigned TerminationWordCount = 2u; + + const T* get_value (hb_codepoint_t glyph_id, const void *base) const + { + return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; + } + + int cmp (hb_codepoint_t g) const + { return g < first ? -1 : g <= last ? 0 : +1; } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + first <= last && + valuesZ.sanitize (c, base, last - first + 1)); + } + template <typename T2> + bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + first <= last && + valuesZ.sanitize (c, base, last - first + 1, user_data)); + } + + GlyphID last; /* Last GlyphID in this segment */ + GlyphID first; /* First GlyphID in this segment */ + NNOffsetTo<UnsizedArrayOf<T> > + valuesZ; /* A 16-bit offset from the start of + * the table to the data. */ + public: + DEFINE_SIZE_STATIC (6); +}; + +template <typename T> +struct LookupFormat4 +{ + friend struct Lookup<T>; + + private: + const T* get_value (hb_codepoint_t glyph_id) const + { + const LookupSegmentArray<T> *v = segments.bsearch (glyph_id); + return v ? v->get_value (glyph_id, this) : nullptr; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c, this)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c, this, base)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 4 */ + VarSizedBinSearchArrayOf<LookupSegmentArray<T> > + segments; /* The actual segments. These must already be sorted, + * according to the first word in each one (the last + * glyph in each segment). */ + public: + DEFINE_SIZE_ARRAY (8, segments); +}; + +template <typename T> +struct LookupSingle +{ + static constexpr unsigned TerminationWordCount = 1u; + + int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c, base)); + } + + GlyphID glyph; /* Last GlyphID */ + T value; /* The lookup value (only one) */ + public: + DEFINE_SIZE_STATIC (2 + T::static_size); +}; + +template <typename T> +struct LookupFormat6 +{ + friend struct Lookup<T>; + + private: + const T* get_value (hb_codepoint_t glyph_id) const + { + const LookupSingle<T> *v = entries.bsearch (glyph_id); + return v ? &v->value : nullptr; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (entries.sanitize (c)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (entries.sanitize (c, base)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 6 */ + VarSizedBinSearchArrayOf<LookupSingle<T> > + entries; /* The actual entries, sorted by glyph index. */ + public: + DEFINE_SIZE_ARRAY (8, entries); +}; + +template <typename T> +struct LookupFormat8 +{ + friend struct Lookup<T>; + + private: + const T* get_value (hb_codepoint_t glyph_id) const + { + return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? + &valueArrayZ[glyph_id - firstGlyph] : nullptr; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 8 */ + GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last + * glyph minus the value of firstGlyph plus 1). */ + UnsizedArrayOf<T> + valueArrayZ; /* The lookup values (indexed by the glyph index + * minus the value of firstGlyph). */ + public: + DEFINE_SIZE_ARRAY (6, valueArrayZ); +}; + +template <typename T> +struct LookupFormat10 +{ + friend struct Lookup<T>; + + private: + const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const + { + if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) + return Null(T); + + const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; + + unsigned int v = 0; + unsigned int count = valueSize; + for (unsigned int i = 0; i < count; i++) + v = (v << 8) | *p++; + + return v; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + valueSize <= 4 && + valueArrayZ.sanitize (c, glyphCount * valueSize)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 8 */ + HBUINT16 valueSize; /* Byte size of each value. */ + GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last + * glyph minus the value of firstGlyph plus 1). */ + UnsizedArrayOf<HBUINT8> + valueArrayZ; /* The lookup values (indexed by the glyph index + * minus the value of firstGlyph). */ + public: + DEFINE_SIZE_ARRAY (8, valueArrayZ); +}; + +template <typename T> +struct Lookup +{ + const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + switch (u.format) { + case 0: return u.format0.get_value (glyph_id, num_glyphs); + case 2: return u.format2.get_value (glyph_id); + case 4: return u.format4.get_value (glyph_id); + case 6: return u.format6.get_value (glyph_id); + case 8: return u.format8.get_value (glyph_id); + default:return nullptr; + } + } + + const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + switch (u.format) { + /* Format 10 cannot return a pointer. */ + case 10: return u.format10.get_value_or_null (glyph_id); + default: + const T *v = get_value (glyph_id, num_glyphs); + return v ? *v : Null(T); + } + } + + typename T::type get_class (hb_codepoint_t glyph_id, + unsigned int num_glyphs, + unsigned int outOfRange) const + { + const T *v = get_value (glyph_id, num_glyphs); + return v ? *v : outOfRange; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 0: return_trace (u.format0.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 4: return_trace (u.format4.sanitize (c)); + case 6: return_trace (u.format6.sanitize (c)); + case 8: return_trace (u.format8.sanitize (c)); + case 10: return_trace (u.format10.sanitize (c)); + default:return_trace (true); + } + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 0: return_trace (u.format0.sanitize (c, base)); + case 2: return_trace (u.format2.sanitize (c, base)); + case 4: return_trace (u.format4.sanitize (c, base)); + case 6: return_trace (u.format6.sanitize (c, base)); + case 8: return_trace (u.format8.sanitize (c, base)); + case 10: return_trace (false); /* We don't support format10 here currently. */ + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + LookupFormat0<T> format0; + LookupFormat2<T> format2; + LookupFormat4<T> format4; + LookupFormat6<T> format6; + LookupFormat8<T> format8; + LookupFormat10<T> format10; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; +/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined + * special NULL objects for Lookup<> objects, but since it's template our macros + * don't work. So we have to hand-code them here. UGLY. */ +} /* Close namespace. */ +/* Ugly hand-coded null objects for template Lookup<> :(. */ +extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2]; +template <> +/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > () +{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); } +template <> +/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > () +{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); } +template <> +/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > () +{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); } +namespace AAT { + +enum { DELETED_GLYPH = 0xFFFF }; + +/* + * (Extended) State Table + */ + +template <typename T> +struct Entry +{ + bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + { + TRACE_SANITIZE (this); + /* Note, we don't recurse-sanitize data because we don't access it. + * That said, in our DEFINE_SIZE_STATIC we access T::static_size, + * which ensures that data has a simple sanitize(). To be determined + * if I need to remove that as well. + * + * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC + * assertion wouldn't be checked, hence the line below. */ + static_assert (T::static_size, ""); + + return_trace (c->check_struct (this)); + } + + public: + HBUINT16 newState; /* Byte offset from beginning of state table + * to the new state. Really?!?! Or just state + * number? The latter in morx for sure. */ + HBUINT16 flags; /* Table specific. */ + T data; /* Optional offsets to per-glyph tables. */ + public: + DEFINE_SIZE_STATIC (4 + T::static_size); +}; + +template <> +struct Entry<void> +{ + bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ + HBUINT16 flags; /* Table specific. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +template <typename Types, typename Extra> +struct StateTable +{ + typedef typename Types::HBUINT HBUINT; + typedef typename Types::HBUSHORT HBUSHORT; + typedef typename Types::ClassTypeNarrow ClassType; + + enum State + { + STATE_START_OF_TEXT = 0, + STATE_START_OF_LINE = 1, + }; + enum Class + { + CLASS_END_OF_TEXT = 0, + CLASS_OUT_OF_BOUNDS = 1, + CLASS_DELETED_GLYPH = 2, + CLASS_END_OF_LINE = 3, + }; + + int new_state (unsigned int newState) const + { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } + + unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; + return (this+classTable).get_class (glyph_id, num_glyphs, 1); + } + + const Entry<Extra> *get_entries () const + { return (this+entryTable).arrayZ; } + + const Entry<Extra> &get_entry (int state, unsigned int klass) const + { + if (unlikely (klass >= nClasses)) + klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS; + + const HBUSHORT *states = (this+stateArrayTable).arrayZ; + const Entry<Extra> *entries = (this+entryTable).arrayZ; + + unsigned int entry = states[state * nClasses + klass]; + DEBUG_MSG (APPLY, nullptr, "e%u", entry); + + return entries[entry]; + } + + bool sanitize (hb_sanitize_context_t *c, + unsigned int *num_entries_out = nullptr) const + { + TRACE_SANITIZE (this); + if (unlikely (!(c->check_struct (this) && + nClasses >= 4 /* Ensure pre-defined classes fit. */ && + classTable.sanitize (c, this)))) return_trace (false); + + const HBUSHORT *states = (this+stateArrayTable).arrayZ; + const Entry<Extra> *entries = (this+entryTable).arrayZ; + + unsigned int num_classes = nClasses; + if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) + return_trace (false); + unsigned int row_stride = num_classes * states[0].static_size; + + /* Apple 'kern' table has this peculiarity: + * + * "Because the stateTableOffset in the state table header is (strictly + * speaking) redundant, some 'kern' tables use it to record an initial + * state where that should not be StartOfText. To determine if this is + * done, calculate what the stateTableOffset should be. If it's different + * from the actual stateTableOffset, use it as the initial state." + * + * We implement this by calling the initial state zero, but allow *negative* + * states if the start state indeed was not the first state. Since the code + * is shared, this will also apply to 'mort' table. The 'kerx' / 'morx' + * tables are not affected since those address states by index, not offset. + */ + + int min_state = 0; + int max_state = 0; + unsigned int num_entries = 0; + + int state_pos = 0; + int state_neg = 0; + unsigned int entry = 0; + while (min_state < state_neg || state_pos <= max_state) + { + if (min_state < state_neg) + { + /* Negative states. */ + if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) + return_trace (false); + if (unlikely (!c->check_range (&states[min_state * num_classes], + -min_state, + row_stride))) + return_trace (false); + if ((c->max_ops -= state_neg - min_state) <= 0) + return_trace (false); + { /* Sweep new states. */ + const HBUSHORT *stop = &states[min_state * num_classes]; + if (unlikely (stop > states)) + return_trace (false); + for (const HBUSHORT *p = states; stop < p; p--) + num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1); + state_neg = min_state; + } + } + + if (state_pos <= max_state) + { + /* Positive states. */ + if (unlikely (!c->check_range (states, + max_state + 1, + row_stride))) + return_trace (false); + if ((c->max_ops -= max_state - state_pos + 1) <= 0) + return_trace (false); + { /* Sweep new states. */ + if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes))) + return_trace (false); + const HBUSHORT *stop = &states[(max_state + 1) * num_classes]; + if (unlikely (stop < states)) + return_trace (false); + for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) + num_entries = MAX<unsigned int> (num_entries, *p + 1); + state_pos = max_state + 1; + } + } + + if (unlikely (!c->check_array (entries, num_entries))) + return_trace (false); + if ((c->max_ops -= num_entries - entry) <= 0) + return_trace (false); + { /* Sweep new entries. */ + const Entry<Extra> *stop = &entries[num_entries]; + for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) + { + int newState = new_state (p->newState); + min_state = MIN (min_state, newState); + max_state = MAX (max_state, newState); + } + entry = num_entries; + } + } + + if (num_entries_out) + *num_entries_out = num_entries; + + return_trace (true); + } + + protected: + HBUINT nClasses; /* Number of classes, which is the number of indices + * in a single line in the state array. */ + NNOffsetTo<ClassType, HBUINT> + classTable; /* Offset to the class table. */ + NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT> + stateArrayTable;/* Offset to the state array. */ + NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT> + entryTable; /* Offset to the entry array. */ + + public: + DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); +}; + +template <typename HBUCHAR> +struct ClassTable +{ + unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const + { + unsigned int i = glyph_id - firstGlyph; + return i >= classArray.len ? outOfRange : classArray.arrayZ[i]; + } + unsigned int get_class (hb_codepoint_t glyph_id, + unsigned int num_glyphs HB_UNUSED, + unsigned int outOfRange) const + { + return get_class (glyph_id, outOfRange); + } + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && classArray.sanitize (c)); + } + protected: + GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus + * firstGlyph). */ + public: + DEFINE_SIZE_ARRAY (4, classArray); +}; + +struct ObsoleteTypes +{ + static constexpr bool extended = false; + typedef HBUINT16 HBUINT; + typedef HBUINT8 HBUSHORT; + typedef ClassTable<HBUINT8> ClassTypeNarrow; + typedef ClassTable<HBUINT16> ClassTypeWide; + + template <typename T> + static unsigned int offsetToIndex (unsigned int offset, + const void *base, + const T *array) + { + return (offset - ((const char *) array - (const char *) base)) / sizeof (T); + } + template <typename T> + static unsigned int byteOffsetToIndex (unsigned int offset, + const void *base, + const T *array) + { + return offsetToIndex (offset, base, array); + } + template <typename T> + static unsigned int wordOffsetToIndex (unsigned int offset, + const void *base, + const T *array) + { + return offsetToIndex (2 * offset, base, array); + } +}; +struct ExtendedTypes +{ + static constexpr bool extended = true; + typedef HBUINT32 HBUINT; + typedef HBUINT16 HBUSHORT; + typedef Lookup<HBUINT16> ClassTypeNarrow; + typedef Lookup<HBUINT16> ClassTypeWide; + + template <typename T> + static unsigned int offsetToIndex (unsigned int offset, + const void *base HB_UNUSED, + const T *array HB_UNUSED) + { + return offset; + } + template <typename T> + static unsigned int byteOffsetToIndex (unsigned int offset, + const void *base HB_UNUSED, + const T *array HB_UNUSED) + { + return offset / 2; + } + template <typename T> + static unsigned int wordOffsetToIndex (unsigned int offset, + const void *base HB_UNUSED, + const T *array HB_UNUSED) + { + return offset; + } +}; + +template <typename Types, typename EntryData> +struct StateTableDriver +{ + StateTableDriver (const StateTable<Types, EntryData> &machine_, + hb_buffer_t *buffer_, + hb_face_t *face_) : + machine (machine_), + buffer (buffer_), + num_glyphs (face_->get_num_glyphs ()) {} + + template <typename context_t> + void drive (context_t *c) + { + if (!c->in_place) + buffer->clear_output (); + + int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT; + for (buffer->idx = 0; buffer->successful;) + { + unsigned int klass = buffer->idx < buffer->len ? + machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : + (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT; + DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); + const Entry<EntryData> &entry = machine.get_entry (state, klass); + + /* Unsafe-to-break before this if not in state 0, as things might + * go differently if we start from state 0 here. + * + * Ugh. The indexing here is ugly... */ + if (state && buffer->backtrack_len () && buffer->idx < buffer->len) + { + /* If there's no action and we're just epsilon-transitioning to state 0, + * safe to break. */ + if (c->is_actionable (this, entry) || + !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT && + entry.flags == context_t::DontAdvance)) + buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); + } + + /* Unsafe-to-break if end-of-text would kick in here. */ + if (buffer->idx + 2 <= buffer->len) + { + const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT); + if (c->is_actionable (this, end_entry)) + buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); + } + + c->transition (this, entry); + + state = machine.new_state (entry.newState); + DEBUG_MSG (APPLY, nullptr, "s%d", state); + + if (buffer->idx == buffer->len) + break; + + if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) + buffer->next_glyph (); + } + + if (!c->in_place) + { + for (; buffer->successful && buffer->idx < buffer->len;) + buffer->next_glyph (); + buffer->swap_buffers (); + } + } + + public: + const StateTable<Types, EntryData> &machine; + hb_buffer_t *buffer; + unsigned int num_glyphs; +}; + + +struct ankr; + +struct hb_aat_apply_context_t : + hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> +{ + const char *get_name () { return "APPLY"; } + template <typename T> + return_t dispatch (const T &obj) { return obj.apply (this); } + static return_t default_return_value () { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_ot_shape_plan_t *plan; + hb_font_t *font; + hb_face_t *face; + hb_buffer_t *buffer; + hb_sanitize_context_t sanitizer; + const ankr *ankr_table; + + /* Unused. For debug tracing only. */ + unsigned int lookup_index; + unsigned int debug_depth; + + HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, + hb_font_t *font_, + hb_buffer_t *buffer_, + hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t))); + + HB_INTERNAL ~hb_aat_apply_context_t (); + + HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); + + void set_lookup_index (unsigned int i) { lookup_index = i; } +}; + + +} /* namespace AAT */ + + +#endif /* HB_AAT_LAYOUT_COMMON_HH */ diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh index 3e070d7..ab23ee0 100644 --- a/src/hb-aat-layout-feat-table.hh +++ b/src/hb-aat-layout-feat-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH #define HB_AAT_LAYOUT_FEAT_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * feat -- Feature Name @@ -39,7 +39,28 @@ namespace AAT { struct SettingName { - inline bool sanitize (hb_sanitize_context_t *c) const + friend struct FeatureName; + + int cmp (hb_aat_layout_feature_selector_t key) const + { return (int) key - (int) setting; } + + hb_aat_layout_feature_selector_t get_selector () const + { return (hb_aat_layout_feature_selector_t) (unsigned) setting; } + + void get_info (hb_aat_layout_feature_selector_info_t *s, + hb_aat_layout_feature_selector_t default_selector) const + { + s->name_id = nameIndex; + + s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting; + s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ? + (hb_aat_layout_feature_selector_t) (s->enable + 1) : + default_selector; + + s->reserved = 0; + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this))); @@ -51,35 +72,75 @@ struct SettingName public: DEFINE_SIZE_STATIC (4); }; +DECLARE_NULL_NAMESPACE_BYTES (AAT, SettingName); + +struct feat; struct FeatureName { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (base+settingTable).sanitize (c, nSettings))); - } + int cmp (hb_aat_layout_feature_type_t key) const + { return (int) key - (int) feature; } enum { - Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */ - NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in + Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */ + NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in * the setting name array for this feature should * be taken as the default for the feature * (if one is required). If set, then bits 0-15 of this * featureFlags field contain the index of the setting * which is to be taken as the default. */ - IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits + IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits * indicate the index of the setting in the setting name * array for this feature which should be taken * as the default. */ }; + unsigned int get_selector_infos (unsigned int start_offset, + unsigned int *selectors_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */ + unsigned int *pdefault_index, /* OUT. May be NULL. */ + const void *base) const + { + hb_array_t< const SettingName> settings_table = (base+settingTableZ).as_array (nSettings); + + static_assert (Index::NOT_FOUND_INDEX == HB_AAT_LAYOUT_NO_SELECTOR_INDEX, ""); + + hb_aat_layout_feature_selector_t default_selector = HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID; + unsigned int default_index = Index::NOT_FOUND_INDEX; + if (featureFlags & Exclusive) + { + default_index = (featureFlags & NotDefault) ? featureFlags & IndexMask : 0; + default_selector = settings_table[default_index].get_selector (); + } + if (pdefault_index) + *pdefault_index = default_index; + + if (selectors_count) + { + hb_array_t<const SettingName> arr = settings_table.sub_array (start_offset, selectors_count); + for (unsigned int i = 0; i < arr.length; i++) + settings_table[start_offset + i].get_info (&selectors[i], default_selector); + } + return settings_table.length; + } + + hb_aat_layout_feature_type_t get_feature_type () const + { return (hb_aat_layout_feature_type_t) (unsigned int) feature; } + + hb_ot_name_id_t get_feature_name_id () const { return nameIndex; } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (base+settingTableZ).sanitize (c, nSettings))); + } + protected: HBUINT16 feature; /* Feature type. */ HBUINT16 nSettings; /* The number of records in the setting name array. */ - LOffsetTo<UnsizedArrayOf<SettingName> > - settingTable; /* Offset in bytes from the beginning of this table to + LOffsetTo<UnsizedArrayOf<SettingName>, false> + settingTableZ; /* Offset in bytes from the beginning of this table to * this feature's setting name array. The actual type of * record this offset refers to will depend on the * exclusivity value, as described below. */ @@ -93,13 +154,49 @@ struct FeatureName struct feat { - static const hb_tag_t tableTag = HB_AAT_TAG_feat; + static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat; + + bool has_data () const { return version.to_int (); } + + unsigned int get_feature_types (unsigned int start_offset, + unsigned int *count, + hb_aat_layout_feature_type_t *features) const + { + unsigned int feature_count = featureNameCount; + if (count && *count) + { + unsigned int len = MIN (feature_count - start_offset, *count); + for (unsigned int i = 0; i < len; i++) + features[i] = namesZ[i + start_offset].get_feature_type (); + *count = len; + } + return featureNameCount; + } + + const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const + { + return namesZ.bsearch (featureNameCount, feature_type); + } + + hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const + { return get_feature (feature).get_feature_name_id (); } + + unsigned int get_selector_infos (hb_aat_layout_feature_type_t feature_type, + unsigned int start_offset, + unsigned int *selectors_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */ + unsigned int *default_index /* OUT. May be NULL. */) const + { + return get_feature (feature_type).get_selector_infos (start_offset, selectors_count, selectors, + default_index, this); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - names.sanitize (c, featureNameCount, this))); + version.major == 1 && + namesZ.sanitize (c, featureNameCount, this))); } protected: @@ -109,8 +206,8 @@ struct feat /* The number of entries in the feature name array. */ HBUINT16 reserved1; /* Reserved (set to zero). */ HBUINT32 reserved2; /* Reserved (set to zero). */ - UnsizedArrayOf<FeatureName> - names; /* The feature name array. */ + SortedUnsizedArrayOf<FeatureName> + namesZ; /* The feature name array. */ public: DEFINE_SIZE_STATIC (24); }; diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh new file mode 100644 index 0000000..d53f8f1 --- /dev/null +++ b/src/hb-aat-layout-just-table.hh @@ -0,0 +1,417 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#ifndef HB_AAT_LAYOUT_JUST_TABLE_HH +#define HB_AAT_LAYOUT_JUST_TABLE_HH + +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout.hh" +#include "hb-open-type.hh" + +#include "hb-aat-layout-morx-table.hh" + +/* + * just -- Justification + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html + */ +#define HB_AAT_TAG_just HB_TAG('j','u','s','t') + + +namespace AAT { + +using namespace OT; + + +struct ActionSubrecordHeader +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + HBUINT16 actionClass; /* The JustClass value associated with this + * ActionSubrecord. */ + HBUINT16 actionType; /* The type of postcompensation action. */ + HBUINT16 actionLength; /* Length of this ActionSubrecord record, which + * must be a multiple of 4. */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct DecompositionAction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + ActionSubrecordHeader + header; + Fixed lowerLimit; /* If the distance factor is less than this value, + * then the ligature is decomposed. */ + Fixed upperLimit; /* If the distance factor is greater than this value, + * then the ligature is decomposed. */ + HBUINT16 order; /* Numerical order in which this ligature will + * be decomposed; you may want infrequent ligatures + * to decompose before more frequent ones. The ligatures + * on the line of text will decompose in increasing + * value of this field. */ + ArrayOf<HBUINT16> + decomposedglyphs; + /* Number of 16-bit glyph indexes that follow; + * the ligature will be decomposed into these glyphs. + * + * Array of decomposed glyphs. */ + public: + DEFINE_SIZE_ARRAY (18, decomposedglyphs); +}; + +struct UnconditionalAddGlyphAction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + ActionSubrecordHeader + header; + GlyphID addGlyph; /* Glyph that should be added if the distance factor + * is growing. */ + + public: + DEFINE_SIZE_STATIC (8); +}; + +struct ConditionalAddGlyphAction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + ActionSubrecordHeader + header; + Fixed substThreshold; /* Distance growth factor (in ems) at which + * this glyph is replaced and the growth factor + * recalculated. */ + GlyphID addGlyph; /* Glyph to be added as kashida. If this value is + * 0xFFFF, no extra glyph will be added. Note that + * generally when a glyph is added, justification + * will need to be redone. */ + GlyphID substGlyph; /* Glyph to be substituted for this glyph if the + * growth factor equals or exceeds the value of + * substThreshold. */ + public: + DEFINE_SIZE_STATIC (14); +}; + +struct DuctileGlyphAction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + ActionSubrecordHeader + header; + HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. + * This would normally be 0x64756374 ('duct'), + * but you may use any axis the font contains. */ + Fixed minimumLimit; /* The lowest value for the ductility axis tha + * still yields an acceptable appearance. Normally + * this will be 1.0. */ + Fixed noStretchValue; /* This is the default value that corresponds to + * no change in appearance. Normally, this will + * be 1.0. */ + Fixed maximumLimit; /* The highest value for the ductility axis that + * still yields an acceptable appearance. */ + public: + DEFINE_SIZE_STATIC (22); +}; + +struct RepeatedAddGlyphAction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + ActionSubrecordHeader + header; + HBUINT16 flags; /* Currently unused; set to 0. */ + GlyphID glyph; /* Glyph that should be added if the distance factor + * is growing. */ + public: + DEFINE_SIZE_STATIC (10); +}; + +struct ActionSubrecord +{ + unsigned int get_length () const { return u.header.actionLength; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + switch (u.header.actionType) + { + case 0: return_trace (u.decompositionAction.sanitize (c)); + case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c)); + case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c)); + // case 3: return_trace (u.stretchGlyphAction.sanitize (c)); + case 4: return_trace (u.decompositionAction.sanitize (c)); + case 5: return_trace (u.decompositionAction.sanitize (c)); + default: return_trace (true); + } + } + + protected: + union { + ActionSubrecordHeader header; + DecompositionAction decompositionAction; + UnconditionalAddGlyphAction unconditionalAddGlyphAction; + ConditionalAddGlyphAction conditionalAddGlyphAction; + /* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */ + DuctileGlyphAction ductileGlyphAction; + RepeatedAddGlyphAction repeatedAddGlyphAction; + } u; /* Data. The format of this data depends on + * the value of the actionType field. */ + public: + DEFINE_SIZE_UNION (6, header); +}; + +struct PostcompensationActionChain +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + unsigned int offset = min_size; + for (unsigned int i = 0; i < count; i++) + { + const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset); + if (unlikely (!subrecord.sanitize (c))) return_trace (false); + offset += subrecord.get_length (); + } + + return_trace (true); + } + + protected: + HBUINT32 count; + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct JustWidthDeltaEntry +{ + enum Flags + { + Reserved1 =0xE000,/* Reserved. You should set these bits to zero. */ + UnlimiteGap =0x1000,/* The glyph can take unlimited gap. When this + * glyph participates in the justification process, + * it and any other glyphs on the line having this + * bit set absorb all the remaining gap. */ + Reserved2 =0x0FF0,/* Reserved. You should set these bits to zero. */ + Priority =0x000F /* The justification priority of the glyph. */ + }; + + enum Priority + { + Kashida = 0, /* Kashida priority. This is the highest priority + * during justification. */ + Whitespace = 1, /* Whitespace priority. Any whitespace glyphs (as + * identified in the glyph properties table) will + * get this priority. */ + InterCharacter = 2, /* Inter-character priority. Give this to any + * remaining glyphs. */ + NullPriority = 3 /* Null priority. You should set this priority for + * glyphs that only participate in justification + * after the above priorities. Normally all glyphs + * have one of the previous three values. If you + * don't want a glyph to participate in justification, + * and you don't want to set its factors to zero, + * you may instead assign it to the null priority. */ + }; + + protected: + Fixed beforeGrowLimit;/* The ratio by which the advance width of the + * glyph is permitted to grow on the left or top side. */ + Fixed beforeShrinkLimit; + /* The ratio by which the advance width of the + * glyph is permitted to shrink on the left or top side. */ + Fixed afterGrowLimit; /* The ratio by which the advance width of the glyph + * is permitted to shrink on the left or top side. */ + Fixed afterShrinkLimit; + /* The ratio by which the advance width of the glyph + * is at most permitted to shrink on the right or + * bottom side. */ + HBUINT16 growFlags; /* Flags controlling the grow case. */ + HBUINT16 shrinkFlags; /* Flags controlling the shrink case. */ + + public: + DEFINE_SIZE_STATIC (20); +}; + +struct WidthDeltaPair +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT32 justClass; /* The justification category associated + * with the wdRecord field. Only 7 bits of + * this field are used. (The other bits are + * used as padding to guarantee longword + * alignment of the following record). */ + JustWidthDeltaEntry + wdRecord; /* The actual width delta record. */ + + public: + DEFINE_SIZE_STATIC (24); +}; + +typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster; + +struct JustificationCategory +{ + typedef void EntryData; + + enum Flags + { + SetMark =0x8000,/* If set, make the current glyph the marked + * glyph. */ + DontAdvance =0x4000,/* If set, don't advance to the next glyph before + * going to the new state. */ + MarkCategory =0x3F80,/* The justification category for the marked + * glyph if nonzero. */ + CurrentCategory =0x007F /* The justification category for the current + * glyph if nonzero. */ + }; + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + morphHeader.sanitize (c) && + stHeader.sanitize (c))); + } + + protected: + ChainSubtable<ObsoleteTypes> + morphHeader; /* Metamorphosis-style subtable header. */ + StateTable<ObsoleteTypes, EntryData> + stHeader; /* The justification insertion state table header */ + public: + DEFINE_SIZE_STATIC (30); +}; + +struct JustificationHeader +{ + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + justClassTable.sanitize (c, base, base) && + wdcTable.sanitize (c, base) && + pcTable.sanitize (c, base) && + lookupTable.sanitize (c, base))); + } + + protected: + OffsetTo<JustificationCategory> + justClassTable; /* Offset to the justification category state table. */ + OffsetTo<WidthDeltaCluster> + wdcTable; /* Offset from start of justification table to start + * of the subtable containing the width delta factors + * for the glyphs in your font. + * + * The width delta clusters table. */ + OffsetTo<PostcompensationActionChain> + pcTable; /* Offset from start of justification table to start + * of postcompensation subtable (set to zero if none). + * + * The postcompensation subtable, if present in the font. */ + Lookup<OffsetTo<WidthDeltaCluster> > + lookupTable; /* Lookup table associating glyphs with width delta + * clusters. See the description of Width Delta Clusters + * table for details on how to interpret the lookup values. */ + + public: + DEFINE_SIZE_MIN (8); +}; + +struct just +{ + static constexpr hb_tag_t tableTag = HB_AAT_TAG_just; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + return_trace (likely (c->check_struct (this) && + version.major == 1 && + horizData.sanitize (c, this, this) && + vertData.sanitize (c, this, this))); + } + + protected: + FixedVersion<>version; /* Version of the justification table + * (0x00010000u for version 1.0). */ + HBUINT16 format; /* Format of the justification table (set to 0). */ + OffsetTo<JustificationHeader> + horizData; /* Byte offset from the start of the justification table + * to the header for tables that contain justification + * information for horizontal text. + * If you are not including this information, + * store 0. */ + OffsetTo<JustificationHeader> + vertData; /* ditto, vertical */ + + public: + DEFINE_SIZE_STATIC (10); +}; + +} /* namespace AAT */ + + +#endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */ diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index cc03d62..a64c807 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -28,8 +28,7 @@ #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH #define HB_AAT_LAYOUT_KERX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-aat-layout-common-private.hh" +#include "hb-kern.hh" #include "hb-aat-layout-ankr-table.hh" /* @@ -44,12 +43,42 @@ namespace AAT { using namespace OT; -struct KerxFormat0Records +static inline int +kerxTupleKern (int value, + unsigned int tupleCount, + const void *base, + hb_aat_apply_context_t *c) { - inline bool sanitize (hb_sanitize_context_t *c) const + if (likely (!tupleCount || !c)) return value; + + unsigned int offset = value; + const FWORD *pv = &StructAtOffset<FWORD> (base, offset); + if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; + return *pv; +} + + +struct hb_glyph_pair_t +{ + hb_codepoint_t left; + hb_codepoint_t right; +}; + +struct KernPair +{ + int get_kerning () const { return value; } + + int cmp (const hb_glyph_pair_t &o) const + { + int ret = left.cmp (o.left); + if (ret) return ret; + return right.cmp (o.right); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: @@ -60,286 +89,912 @@ struct KerxFormat0Records DEFINE_SIZE_STATIC (6); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat0 { - // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf - // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const - // { - // hb_glyph_pair_t pair = {left, right}; - // int i = pairs.bsearch (pair); - // if (i == -1) - // return 0; - // return pairs[i].get_kerning (); - // } - - inline bool sanitize (hb_sanitize_context_t *c) const + int get_kerning (hb_codepoint_t left, hb_codepoint_t right, + hb_aat_apply_context_t *c = nullptr) const + { + hb_glyph_pair_t pair = {left, right}; + int v = pairs.bsearch (pair).get_kerning (); + return kerxTupleKern (v, header.tuple_count (), this, c); + } + + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + if (header.coverage & header.Backwards) + return false; + + accelerator_t accel (*this, c); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); + } + + struct accelerator_t + { + const KerxSubTableFormat0 &table; + hb_aat_apply_context_t *c; + + accelerator_t (const KerxSubTableFormat0 &table_, + hb_aat_apply_context_t *c_) : + table (table_), c (c_) {} + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { return table.get_kerning (left, right, c); } + }; + + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - recordsZ.sanitize (c, nPairs))); + return_trace (likely (pairs.sanitize (c))); } protected: - // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is - // needed here to use HBUINT32 instead - HBUINT32 nPairs; /* The number of kerning pairs in this subtable */ - HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs, - * multiplied by the size in bytes of an entry in the subtable. */ - HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less - * than or equal to the value of nPairs. */ - HBUINT32 rangeShift; /* The value of nPairs minus the largest power of two less than or equal to nPairs. */ - UnsizedArrayOf<KerxFormat0Records> - recordsZ; /* VAR=nPairs */ + KernSubTableHeader header; + BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT> + pairs; /* Sorted kern records. */ public: - DEFINE_SIZE_ARRAY (16, recordsZ); + DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs); }; -struct KerxSubTableFormat1 + +template <bool extended> +struct Format1Entry; + +template <> +struct Format1Entry<true> { - inline bool sanitize (hb_sanitize_context_t *c) const + enum Flags { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - stateHeader.sanitize (c))); - } + Push = 0x8000, /* If set, push this glyph on the kerning stack. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph + * before going to the new state. */ + Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */ + Reserved = 0x1FFF, /* Not used; set to 0. */ + }; + + struct EntryData + { + HBUINT16 kernActionIndex;/* Index into the kerning value array. If + * this index is 0xFFFF, then no kerning + * is to be performed. */ + public: + DEFINE_SIZE_STATIC (2); + }; + + static bool performAction (const Entry<EntryData> &entry) + { return entry.data.kernActionIndex != 0xFFFF; } + + static unsigned int kernActionIndex (const Entry<EntryData> &entry) + { return entry.data.kernActionIndex; } +}; +template <> +struct Format1Entry<false> +{ + enum Flags + { + Push = 0x8000, /* If set, push this glyph on the kerning stack. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph + * before going to the new state. */ + Offset = 0x3FFF, /* Byte offset from beginning of subtable to the + * value table for the glyphs on the kerning stack. */ - protected: - StateTable<HBUINT16> stateHeader; - LOffsetTo<ArrayOf<HBUINT16> > valueTable; - public: - DEFINE_SIZE_STATIC (20); + Reset = 0x0000, /* Not supported? */ + }; + + typedef void EntryData; + + static bool performAction (const Entry<EntryData> &entry) + { return entry.flags & Offset; } + + static unsigned int kernActionIndex (const Entry<EntryData> &entry) + { return entry.flags & Offset; } }; -// TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>? -struct KerxClassTable +template <typename KernSubTableHeader> +struct KerxSubTableFormat1 { - inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; } + typedef typename KernSubTableHeader::Types Types; + typedef typename Types::HBUINT HBUINT; + + typedef Format1Entry<Types::extended> Format1EntryT; + typedef typename Format1EntryT::EntryData EntryData; - inline bool sanitize (hb_sanitize_context_t *c) const + struct driver_context_t + { + static constexpr bool in_place = true; + enum + { + DontAdvance = Format1EntryT::DontAdvance, + }; + + driver_context_t (const KerxSubTableFormat1 *table_, + hb_aat_apply_context_t *c_) : + c (c_), + table (table_), + /* Apparently the offset kernAction is from the beginning of the state-machine, + * similar to offsets in morx table, NOT from beginning of this table, like + * other subtables in kerx. Discovered via testing. */ + kernAction (&table->machine + table->kernAction), + depth (0), + crossStream (table->header.coverage & table->header.CrossStream) {} + + bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, + const Entry<EntryData> &entry) + { + return Format1EntryT::performAction (entry); + } + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) + { + hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry.flags; + + if (flags & Format1EntryT::Reset) + depth = 0; + + if (flags & Format1EntryT::Push) + { + if (likely (depth < ARRAY_LENGTH (stack))) + stack[depth++] = buffer->idx; + else + depth = 0; /* Probably not what CoreText does, but better? */ + } + + if (Format1EntryT::performAction (entry) && depth) + { + unsigned int tuple_count = MAX (1u, table->header.tuple_count ()); + + unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); + kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); + const FWORD *actions = &kernAction[kern_idx]; + if (!c->sanitizer.check_array (actions, depth, tuple_count)) + { + depth = 0; + return; + } + + hb_mask_t kern_mask = c->plan->kern_mask; + + /* From Apple 'kern' spec: + * "Each pops one glyph from the kerning stack and applies the kerning value to it. + * The end of the list is marked by an odd value... */ + bool last = false; + while (!last && depth) + { + unsigned int idx = stack[--depth]; + int v = *actions; + actions += tuple_count; + if (idx >= buffer->len) continue; + + /* "The end of the list is marked by an odd value..." */ + last = v & 1; + v &= ~1; + + hb_glyph_position_t &o = buffer->pos[idx]; + + /* Testing shows that CoreText only applies kern (cross-stream or not) + * if none has been applied by previous subtables. That is, it does + * NOT seem to accumulate as otherwise implied by specs. */ + + /* The following flag is undocumented in the spec, but described + * in the 'kern' table example. */ + if (v == -0x8000) + { + o.attach_type() = ATTACH_TYPE_NONE; + o.attach_chain() = 0; + o.x_offset = o.y_offset = 0; + } + else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + { + if (crossStream) + { + if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset) + { + o.y_offset = c->font->em_scale_y (v); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + } + else if (buffer->info[idx].mask & kern_mask) + { + if (!buffer->pos[idx].x_offset) + { + buffer->pos[idx].x_advance += c->font->em_scale_x (v); + buffer->pos[idx].x_offset += c->font->em_scale_x (v); + } + } + } + else + { + if (crossStream) + { + /* CoreText doesn't do crossStream kerning in vertical. We do. */ + if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset) + { + o.x_offset = c->font->em_scale_x (v); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + } + else if (buffer->info[idx].mask & kern_mask) + { + if (!buffer->pos[idx].y_offset) + { + buffer->pos[idx].y_advance += c->font->em_scale_y (v); + buffer->pos[idx].y_offset += c->font->em_scale_y (v); + } + } + } + } + } + } + + private: + hb_aat_apply_context_t *c; + const KerxSubTableFormat1 *table; + const UnsizedArrayOf<FWORD> &kernAction; + unsigned int stack[8]; + unsigned int depth; + bool crossStream; + }; + + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning && + !(header.coverage & header.CrossStream)) + return false; + + driver_context_t dc (this, c); + + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); + driver.drive (&dc); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (firstGlyph.sanitize (c) && - classes.sanitize (c))); + /* The rest of array sanitizations are done at run-time. */ + return_trace (likely (c->check_struct (this) && + machine.sanitize (c))); } protected: - HBUINT16 firstGlyph; /* First glyph in class range. */ - ArrayOf<HBUINT16> classes; /* Glyph classes. */ + KernSubTableHeader header; + StateTable<Types, EntryData> machine; + NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction; public: - DEFINE_SIZE_ARRAY (4, classes); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT)); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat2 { - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const - { - unsigned int l = (this+leftClassTable).get_class (left); - unsigned int r = (this+leftClassTable).get_class (left); - unsigned int offset = l * rowWidth + r * sizeof (FWORD); - const FWORD *arr = &(this+array); - if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) - return 0; - const FWORD *v = &StructAtOffset<FWORD> (arr, offset); - if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) - return 0; - return *v; + typedef typename KernSubTableHeader::Types Types; + typedef typename Types::HBUINT HBUINT; + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right, + hb_aat_apply_context_t *c) const + { + unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); + unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0); + unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0); + + const UnsizedArrayOf<FWORD> &arrayZ = this+array; + unsigned int kern_idx = l + r; + kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ); + const FWORD *v = &arrayZ[kern_idx]; + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + + return kerxTupleKern (*v, header.tuple_count (), this, c); + } + + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + if (header.coverage & header.Backwards) + return false; + + accelerator_t accel (*this, c); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + struct accelerator_t + { + const KerxSubTableFormat2 &table; + hb_aat_apply_context_t *c; + + accelerator_t (const KerxSubTableFormat2 &table_, + hb_aat_apply_context_t *c_) : + table (table_), c (c_) {} + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { return table.get_kerning (left, right, c); } + }; + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - rowWidth.sanitize (c) && leftClassTable.sanitize (c, this) && rightClassTable.sanitize (c, this) && - array.sanitize (c, this))); + c->check_range (this, array))); } protected: - HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ - LOffsetTo<KerxClassTable> - leftClassTable; /* Offset from beginning of this subtable to - * left-hand class table. */ - LOffsetTo<KerxClassTable> - rightClassTable;/* Offset from beginning of this subtable to - * right-hand class table. */ - LOffsetTo<FWORD> - array; /* Offset from beginning of this subtable to - * the start of the kerning array. */ + KernSubTableHeader header; + HBUINT rowWidth; /* The width, in bytes, of a row in the table. */ + NNOffsetTo<typename Types::ClassTypeWide, HBUINT> + leftClassTable; /* Offset from beginning of this subtable to + * left-hand class table. */ + NNOffsetTo<typename Types::ClassTypeWide, HBUINT> + rightClassTable;/* Offset from beginning of this subtable to + * right-hand class table. */ + NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> + array; /* Offset from beginning of this subtable to + * the start of the kerning array. */ public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT)); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat4 { - inline bool sanitize (hb_sanitize_context_t *c) const + typedef ExtendedTypes Types; + + struct EntryData + { + HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of + * the action to perform. */ + public: + DEFINE_SIZE_STATIC (2); + }; + + struct driver_context_t + { + static constexpr bool in_place = true; + enum Flags + { + Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. */ + Reserved = 0x3FFF, /* Not used; set to 0. */ + }; + + enum SubTableFlags + { + ActionType = 0xC0000000, /* A two-bit field containing the action type. */ + Unused = 0x3F000000, /* Unused - must be zero. */ + Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning + * of the subtable to the beginning of the control + * point table. */ + }; + + driver_context_t (const KerxSubTableFormat4 *table, + hb_aat_apply_context_t *c_) : + c (c_), + action_type ((table->flags & ActionType) >> 30), + ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))), + mark_set (false), + mark (0) {} + + bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, + const Entry<EntryData> &entry) + { + return entry.data.ankrActionIndex != 0xFFFF; + } + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) + { + hb_buffer_t *buffer = driver->buffer; + + if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) + { + hb_glyph_position_t &o = buffer->cur_pos(); + switch (action_type) + { + case 0: /* Control Point Actions.*/ + { + /* indexed into glyph outline. */ + const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 2)) return; + HB_UNUSED unsigned int markControlPoint = *data++; + HB_UNUSED unsigned int currControlPoint = *data++; + hb_position_t markX = 0; + hb_position_t markY = 0; + hb_position_t currX = 0; + hb_position_t currY = 0; + if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint, + markControlPoint, + HB_DIRECTION_LTR /*XXX*/, + &markX, &markY) || + !c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint, + currControlPoint, + HB_DIRECTION_LTR /*XXX*/, + &currX, &currY)) + return; + + o.x_offset = markX - currX; + o.y_offset = markY - currY; + } + break; + + case 1: /* Anchor Point Actions. */ + { + /* Indexed into 'ankr' table. */ + const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 2)) return; + unsigned int markAnchorPoint = *data++; + unsigned int currAnchorPoint = *data++; + const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint, + markAnchorPoint, + c->sanitizer.get_num_glyphs ()); + const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint, + currAnchorPoint, + c->sanitizer.get_num_glyphs ()); + + o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate); + o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate); + } + break; + + case 2: /* Control Point Coordinate Actions. */ + { + const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 4)) return; + int markX = *data++; + int markY = *data++; + int currX = *data++; + int currY = *data++; + + o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX); + o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY); + } + break; + } + o.attach_type() = ATTACH_TYPE_MARK; + o.attach_chain() = (int) mark - (int) buffer->idx; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + + if (entry.flags & Mark) + { + mark_set = true; + mark = buffer->idx; + } + } + + private: + hb_aat_apply_context_t *c; + unsigned int action_type; + const HBUINT16 *ankrData; + bool mark_set; + unsigned int mark; + }; + + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + driver_context_t dc (this, c); + + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); + driver.drive (&dc); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + /* The rest of array sanitizations are done at run-time. */ return_trace (likely (c->check_struct (this) && - rowWidth.sanitize (c) && - leftClassTable.sanitize (c, this) && - rightClassTable.sanitize (c, this) && - array.sanitize (c, this))); + machine.sanitize (c))); } protected: - HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ - LOffsetTo<KerxClassTable> - leftClassTable; /* Offset from beginning of this subtable to - * left-hand class table. */ - LOffsetTo<KerxClassTable> - rightClassTable;/* Offset from beginning of this subtable to - * right-hand class table. */ - LOffsetTo<FWORD> - array; /* Offset from beginning of this subtable to - * the start of the kerning array. */ + KernSubTableHeader header; + StateTable<Types, EntryData> machine; + HBUINT32 flags; public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat6 { - inline bool sanitize (hb_sanitize_context_t *c) const + enum Flags + { + ValuesAreLong = 0x00000001, + }; + + bool is_long () const { return flags & ValuesAreLong; } + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right, + hb_aat_apply_context_t *c) const + { + unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); + if (is_long ()) + { + const typename U::Long &t = u.l; + unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); + unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); + unsigned int offset = l + r; + if (unlikely (offset < l)) return 0; /* Addition overflow. */ + if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; + const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32)); + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); + } + else + { + const typename U::Short &t = u.s; + unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); + unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); + unsigned int offset = l + r; + const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD)); + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); + } + } + + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + if (header.coverage & header.Backwards) + return false; + + accelerator_t accel (*this, c); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - rowIndexTable.sanitize (c, this) && - columnIndexTable.sanitize (c, this) && - kerningArray.sanitize (c, this) && - kerningVector.sanitize (c, this))); + (is_long () ? + ( + u.l.rowIndexTable.sanitize (c, this) && + u.l.columnIndexTable.sanitize (c, this) && + c->check_range (this, u.l.array) + ) : ( + u.s.rowIndexTable.sanitize (c, this) && + u.s.columnIndexTable.sanitize (c, this) && + c->check_range (this, u.s.array) + )) && + (header.tuple_count () == 0 || + c->check_range (this, vector)))); } + struct accelerator_t + { + const KerxSubTableFormat6 &table; + hb_aat_apply_context_t *c; + + accelerator_t (const KerxSubTableFormat6 &table_, + hb_aat_apply_context_t *c_) : + table (table_), c (c_) {} + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { return table.get_kerning (left, right, c); } + }; + protected: - HBUINT32 flags; - HBUINT16 rowCount; - HBUINT16 columnCount; - LOffsetTo<Lookup<HBUINT16> > rowIndexTable; - LOffsetTo<Lookup<HBUINT16> > columnIndexTable; - LOffsetTo<Lookup<HBUINT16> > kerningArray; - LOffsetTo<Lookup<HBUINT16> > kerningVector; + KernSubTableHeader header; + HBUINT32 flags; + HBUINT16 rowCount; + HBUINT16 columnCount; + union U + { + struct Long + { + LNNOffsetTo<Lookup<HBUINT32> > rowIndexTable; + LNNOffsetTo<Lookup<HBUINT32> > columnIndexTable; + LNNOffsetTo<UnsizedArrayOf<FWORD32> > array; + } l; + struct Short + { + LNNOffsetTo<Lookup<HBUINT16> > rowIndexTable; + LNNOffsetTo<Lookup<HBUINT16> > columnIndexTable; + LNNOffsetTo<UnsizedArrayOf<FWORD> > array; + } s; + } u; + LNNOffsetTo<UnsizedArrayOf<FWORD> > vector; public: - DEFINE_SIZE_STATIC (24); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24); }; -enum coverage_flags_t + +struct KerxSubTableHeader { - COVERAGE_VERTICAL_FLAG = 0x80u, - COVERAGE_CROSSSTREAM_FLAG = 0x40u, - COVERAGE_VARIATION_FLAG = 0x20u, - COVERAGE_PROCESS_DIRECTION = 0x10u, + typedef ExtendedTypes Types; + + unsigned int tuple_count () const { return tupleCount; } + bool is_horizontal () const { return !(coverage & Vertical); } + + enum Coverage + { + Vertical = 0x80000000u, /* Set if table has vertical kerning values. */ + CrossStream = 0x40000000u, /* Set if table has cross-stream kerning values. */ + Variation = 0x20000000u, /* Set if table has variation kerning values. */ + Backwards = 0x10000000u, /* If clear, process the glyphs forwards, that + * is, from first to last in the glyph stream. + * If we, process them from last to first. + * This flag only applies to state-table based + * 'kerx' subtables (types 1 and 4). */ + Reserved = 0x0FFFFF00u, /* Reserved, set to zero. */ + SubtableType= 0x000000FFu, /* Subtable type. */ + }; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + public: + HBUINT32 length; + HBUINT32 coverage; + HBUINT32 tupleCount; + public: + DEFINE_SIZE_STATIC (12); }; -struct KerxTable +struct KerxSubTable { - inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const + friend struct kerx; + + unsigned int get_size () const { return u.header.length; } + unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; } + + template <typename context_t> + typename context_t::return_t dispatch (context_t *c) const { - TRACE_APPLY (this); - /* TODO */ - return_trace (false); + unsigned int subtable_type = get_type (); + TRACE_DISPATCH (this, subtable_type); + switch (subtable_type) { + case 0: return_trace (c->dispatch (u.format0)); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + case 4: return_trace (c->dispatch (u.format4)); + case 6: return_trace (c->dispatch (u.format6)); + default: return_trace (c->default_return_value ()); + } } - inline unsigned int get_size (void) const { return length; } - - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) + if (!u.header.sanitize (c) || + u.header.length <= u.header.static_size || + !c->check_range (this, u.header.length)) return_trace (false); - switch (format) { - case 0: return u.format0.sanitize (c); - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 4: return u.format4.sanitize (c); - case 6: return u.format6.sanitize (c); - default:return_trace (false); - } + return_trace (dispatch (c)); } -protected: - HBUINT32 length; - HBUINT8 coverage; - HBUINT16 unused; - HBUINT8 format; - HBUINT32 tupleIndex; + public: union { - KerxSubTableFormat0 format0; - KerxSubTableFormat1 format1; - KerxSubTableFormat2 format2; - KerxSubTableFormat4 format4; - KerxSubTableFormat6 format6; + KerxSubTableHeader header; + KerxSubTableFormat0<KerxSubTableHeader> format0; + KerxSubTableFormat1<KerxSubTableHeader> format1; + KerxSubTableFormat2<KerxSubTableHeader> format2; + KerxSubTableFormat4<KerxSubTableHeader> format4; + KerxSubTableFormat6<KerxSubTableHeader> format6; } u; -public: + public: DEFINE_SIZE_MIN (12); }; -struct SubtableGlyphCoverageArray + +/* + * The 'kerx' Table + */ + +template <typename T> +struct KerxTable { - inline bool sanitize (hb_sanitize_context_t *c) const + /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + const T* thiz () const { return static_cast<const T *> (this); } + + bool has_state_machine () const { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + typedef typename T::SubTable SubTable; + + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + if (st->get_type () == 1) + return true; + st = &StructAfter<SubTable> (*st); + } + return false; } - protected: - HBUINT32 length; - HBUINT32 coverage; - HBUINT32 tupleCount; - public: - DEFINE_SIZE_STATIC (12); -}; + bool has_cross_stream () const + { + typedef typename T::SubTable SubTable; -struct kerx -{ - static const hb_tag_t tableTag = HB_AAT_TAG_kerx; + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + if (st->u.header.coverage & st->u.header.CrossStream) + return true; + st = &StructAfter<SubTable> (*st); + } + return false; + } - inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const + int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - TRACE_APPLY (this); - const KerxTable &table = StructAfter<KerxTable> (*this); - return_trace (table.apply (c, ankr)); + typedef typename T::SubTable SubTable; + + int v = 0; + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) || + !st->u.header.is_horizontal ()) + continue; + v += st->get_kerning (left, right); + st = &StructAfter<SubTable> (*st); + } + return v; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool apply (AAT::hb_aat_apply_context_t *c) const { - TRACE_SANITIZE (this); - if (unlikely (!(c->check_struct (this)))) - return_trace (false); + typedef typename T::SubTable SubTable; + + bool ret = false; + bool seenCrossStream = false; + c->set_lookup_index (0); + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + bool reverse; + + if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) + goto skip; + + if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) + goto skip; + + reverse = bool (st->u.header.coverage & st->u.header.Backwards) != + HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); + + if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index)) + goto skip; + + if (!seenCrossStream && + (st->u.header.coverage & st->u.header.CrossStream)) + { + /* Attach all glyphs into a chain. */ + seenCrossStream = true; + hb_glyph_position_t *pos = c->buffer->pos; + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) + { + pos[i].attach_type() = ATTACH_TYPE_CURSIVE; + pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1; + /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT, + * since there needs to be a non-zero attachment for post-positioning to + * be needed. */ + } + } + + if (reverse) + c->buffer->reverse (); + + { + /* See comment in sanitize() for conditional here. */ + hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); + ret |= st->dispatch (c); + } + + if (reverse) + c->buffer->reverse (); + + (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index); + + skip: + st = &StructAfter<SubTable> (*st); + c->set_lookup_index (c->lookup_index + 1); + } - /* TODO: Something like `morx`s ChainSubtable should be done here instead */ - const KerxTable *table = &StructAfter<KerxTable> (*this); - if (unlikely (!(table->sanitize (c)))) + return ret; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!thiz()->version.sanitize (c) || + (unsigned) thiz()->version < (unsigned) T::minVersion || + !thiz()->tableCount.sanitize (c))) return_trace (false); - for (unsigned int i = 0; i < nTables - 1; ++i) + typedef typename T::SubTable SubTable; + + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) { - table = &StructAfter<KerxTable> (*table); - if (unlikely (!(table->sanitize (c)))) - return_trace (false); + if (unlikely (!st->u.header.sanitize (c))) + return_trace (false); + /* OpenType kern table has 2-byte subtable lengths. That's limiting. + * MS implementation also only supports one subtable, of format 0, + * anyway. Certain versions of some fonts, like Calibry, contain + * kern subtable that exceeds 64kb. Looks like, the subtable length + * is simply ignored. Which makes sense. It's only needed if you + * have multiple subtables. To handle such fonts, we just ignore + * the length for the last subtable. */ + hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr); + + if (unlikely (!st->sanitize (c))) + return_trace (false); + + st = &StructAfter<SubTable> (*st); } - // If version is less than 3, we are done here; otherwise better to check footer also - if (version < 3) - return_trace (true); - - // TODO: Investigate why this just work on some fonts no matter of version - // const SubtableGlyphCoverageArray &footer = - // StructAfter<SubtableGlyphCoverageArray> (*table); - // return_trace (footer.sanitize (c)); - return_trace (true); } +}; + +struct kerx : KerxTable<kerx> +{ + friend struct KerxTable<kerx>; + + static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx; + static constexpr unsigned minVersion = 2u; + + typedef KerxSubTableHeader SubTableHeader; + typedef SubTableHeader::Types Types; + typedef KerxSubTable SubTable; + + bool has_data () const { return version; } protected: - HBUINT16 version; - HBUINT16 padding; - HBUINT32 nTables; -/*KerxTable tablesZ[VAR]; XXX ArrayOf??? */ -/*SubtableGlyphCoverageArray coverage_array;*/ + HBUINT16 version; /* The version number of the extended kerning table + * (currently 2, 3, or 4). */ + HBUINT16 unused; /* Set to 0. */ + HBUINT32 tableCount; /* The number of subtables included in the extended kerning + * table. */ + SubTable firstSubTable; /* Subtables. */ +/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ + public: - DEFINE_SIZE_STATIC (8); + DEFINE_SIZE_MIN (8); }; + } /* namespace AAT */ diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh new file mode 100644 index 0000000..4be799f --- /dev/null +++ b/src/hb-aat-layout-lcar-table.hh @@ -0,0 +1,93 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ +#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH +#define HB_AAT_LAYOUT_LCAR_TABLE_HH + +#include "hb-open-type.hh" +#include "hb-aat-layout-common.hh" + +/* + * lcar -- Ligature caret + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html + */ +#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r') + + +namespace AAT { + +typedef ArrayOf<HBINT16> LigCaretClassEntry; + +struct lcar +{ + static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar; + + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph, + font->face->get_num_glyphs ()); + const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry); + if (caret_count) + { + hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count); + unsigned int count = arr.length; + for (unsigned int i = 0; i < count; ++i) + switch (format) + { + case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break; + case 1: + hb_position_t x, y; + font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y); + caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; + break; + } + } + return array.len; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + version.major == 1 && + lookup.sanitize (c, this))); + } + + protected: + FixedVersion<>version; /* Version number of the ligature caret table */ + HBUINT16 format; /* Format of the ligature caret table. */ + Lookup<OffsetTo<LigCaretClassEntry> > + lookup; /* data Lookup table associating glyphs */ + + public: + DEFINE_SIZE_MIN (8); +}; + +} /* namespace AAT */ + +#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */ diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index f258424..4a1d959 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -27,30 +27,36 @@ #ifndef HB_AAT_LAYOUT_MORX_TABLE_HH #define HB_AAT_LAYOUT_MORX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-aat-layout-common-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout-common.hh" +#include "hb-aat-map.hh" /* * morx -- Extended Glyph Metamorphosis * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html */ #define HB_AAT_TAG_morx HB_TAG('m','o','r','x') +#define HB_AAT_TAG_mort HB_TAG('m','o','r','t') namespace AAT { using namespace OT; - +template <typename Types> struct RearrangementSubtable { + typedef typename Types::HBUINT HBUINT; + typedef void EntryData; struct driver_context_t { - static const bool in_place = true; - enum Flags { + static constexpr bool in_place = true; + enum Flags + { MarkFirst = 0x8000, /* If set, make the current glyph the first * glyph to be rearranged. */ DontAdvance = 0x4000, /* If set, don't advance to the next glyph @@ -63,20 +69,20 @@ struct RearrangementSubtable Verb = 0x000F, /* The type of rearrangement specified. */ }; - inline driver_context_t (const RearrangementSubtable *table) : + driver_context_t (const RearrangementSubtable *table HB_UNUSED) : ret (false), start (0), end (0) {} - inline bool is_actionable (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, + const Entry<EntryData> &entry) { - return (entry->flags & Verb) && start < end; + return (entry.flags & Verb) && start < end; } - inline bool transition (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) { hb_buffer_t *buffer = driver->buffer; - unsigned int flags = entry->flags; + unsigned int flags = entry.flags; if (flags & MarkFirst) start = buffer->idx; @@ -146,8 +152,6 @@ struct RearrangementSubtable } } } - - return true; } public: @@ -157,32 +161,35 @@ struct RearrangementSubtable unsigned int end; }; - inline bool apply (hb_aat_apply_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); driver_context_t dc (this); - StateTableDriver<void> driver (machine, c->buffer, c->face); + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (machine.sanitize (c)); } protected: - StateTable<EntryData> machine; + StateTable<Types, EntryData> machine; public: DEFINE_SIZE_STATIC (16); }; +template <typename Types> struct ContextualSubtable { + typedef typename Types::HBUINT HBUINT; + struct EntryData { HBUINT16 markIndex; /* Index of the substitution table for the @@ -195,101 +202,133 @@ struct ContextualSubtable struct driver_context_t { - static const bool in_place = true; - enum Flags { + static constexpr bool in_place = true; + enum Flags + { SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ DontAdvance = 0x4000, /* If set, don't advance to the next glyph before * going to the new state. */ Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ }; - inline driver_context_t (const ContextualSubtable *table) : + driver_context_t (const ContextualSubtable *table_, + hb_aat_apply_context_t *c_) : ret (false), + c (c_), mark_set (false), mark (0), + table (table_), subs (table+table->substitutionTables) {} - inline bool is_actionable (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + bool is_actionable (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) { hb_buffer_t *buffer = driver->buffer; if (buffer->idx == buffer->len && !mark_set) return false; - return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF; + return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; } - inline bool transition (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) { hb_buffer_t *buffer = driver->buffer; /* Looks like CoreText applies neither mark nor current substitution for * end-of-text if mark was not explicitly set. */ if (buffer->idx == buffer->len && !mark_set) - return true; + return; + + const GlyphID *replacement; - if (entry->data.markIndex != 0xFFFF) + replacement = nullptr; + if (Types::extended) { - const Lookup<GlyphID> &lookup = subs[entry->data.markIndex]; - hb_glyph_info_t *info = buffer->info; - const GlyphID *replacement = lookup.get_value (info[mark].codepoint, driver->num_glyphs); - if (replacement) + if (entry.data.markIndex != 0xFFFF) { - buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len)); - info[mark].codepoint = *replacement; - ret = true; + const Lookup<GlyphID> &lookup = subs[entry.data.markIndex]; + replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs); } } - if (entry->data.currentIndex != 0xFFFF) + else + { + unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; + const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs; + replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; + if (!replacement->sanitize (&c->sanitizer) || !*replacement) + replacement = nullptr; + } + if (replacement) { - unsigned int idx = MIN (buffer->idx, buffer->len - 1); - const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex]; - hb_glyph_info_t *info = buffer->info; - const GlyphID *replacement = lookup.get_value (info[idx].codepoint, driver->num_glyphs); - if (replacement) + buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len)); + buffer->info[mark].codepoint = *replacement; + ret = true; + } + + replacement = nullptr; + unsigned int idx = MIN (buffer->idx, buffer->len - 1); + if (Types::extended) + { + if (entry.data.currentIndex != 0xFFFF) { - info[idx].codepoint = *replacement; - ret = true; + const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex]; + replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs); } } + else + { + unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; + const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs; + replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; + if (!replacement->sanitize (&c->sanitizer) || !*replacement) + replacement = nullptr; + } + if (replacement) + { + buffer->info[idx].codepoint = *replacement; + ret = true; + } - if (entry->flags & SetMark) + if (entry.flags & SetMark) { mark_set = true; mark = buffer->idx; } - - return true; } public: bool ret; private: + hb_aat_apply_context_t *c; bool mark_set; unsigned int mark; - const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs; + const ContextualSubtable *table; + const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs; }; - inline bool apply (hb_aat_apply_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - driver_context_t dc (this); + driver_context_t dc (this, c); - StateTableDriver<EntryData> driver (machine, c->buffer, c->face); + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); unsigned int num_entries = 0; if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); + if (!Types::extended) + return_trace (substitutionTables.sanitize (c, this, 0)); + unsigned int num_lookups = 0; const Entry<EntryData> *entries = machine.get_entries (); @@ -307,16 +346,32 @@ struct ContextualSubtable } protected: - StateTable<EntryData> + StateTable<Types, EntryData> machine; - LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> > + NNOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT> substitutionTables; public: DEFINE_SIZE_STATIC (20); }; -struct LigatureSubtable + +template <bool extended> +struct LigatureEntry; + +template <> +struct LigatureEntry<true> { + enum Flags + { + SetComponent = 0x8000, /* Push this glyph onto the component stack for + * eventual processing. */ + DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the + next iteration. */ + PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature + * group. */ + Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ + }; + struct EntryData { HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry @@ -326,19 +381,53 @@ struct LigatureSubtable DEFINE_SIZE_STATIC (2); }; - struct driver_context_t + static bool performAction (const Entry<EntryData> &entry) + { return entry.flags & PerformAction; } + + static unsigned int ligActionIndex (const Entry<EntryData> &entry) + { return entry.data.ligActionIndex; } +}; +template <> +struct LigatureEntry<false> +{ + enum Flags { - static const bool in_place = false; - enum Flags { - SetComponent = 0x8000, /* Push this glyph onto the component stack for + SetComponent = 0x8000, /* Push this glyph onto the component stack for * eventual processing. */ - DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the + DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the next iteration. */ - PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature - * group. */ - Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ + Offset = 0x3FFF, /* Byte offset from beginning of subtable to the + * ligature action list. This value must be a + * multiple of 4. */ + }; + + typedef void EntryData; + + static bool performAction (const Entry<EntryData> &entry) + { return entry.flags & Offset; } + + static unsigned int ligActionIndex (const Entry<EntryData> &entry) + { return entry.flags & Offset; } +}; + + +template <typename Types> +struct LigatureSubtable +{ + typedef typename Types::HBUINT HBUINT; + + typedef LigatureEntry<Types::extended> LigatureEntryT; + typedef typename LigatureEntryT::EntryData EntryData; + + struct driver_context_t + { + static constexpr bool in_place = false; + enum + { + DontAdvance = LigatureEntryT::DontAdvance, }; - enum LigActionFlags { + enum LigActionFlags + { LigActionLast = 0x80000000, /* This is the last action in the list. This also * implies storage. */ LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index @@ -349,96 +438,120 @@ struct LigatureSubtable * into the component table. */ }; - inline driver_context_t (const LigatureSubtable *table, - hb_aat_apply_context_t *c_) : + driver_context_t (const LigatureSubtable *table_, + hb_aat_apply_context_t *c_) : ret (false), c (c_), + table (table_), ligAction (table+table->ligAction), component (table+table->component), ligature (table+table->ligature), match_length (0) {} - inline bool is_actionable (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, + const Entry<EntryData> &entry) { - return !!(entry->flags & PerformAction); + return LigatureEntryT::performAction (entry); } - inline bool transition (StateTableDriver<EntryData> *driver, - const Entry<EntryData> *entry) + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) { hb_buffer_t *buffer = driver->buffer; - unsigned int flags = entry->flags; - if (flags & SetComponent) + DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); + if (entry.flags & LigatureEntryT::SetComponent) { - if (unlikely (match_length >= ARRAY_LENGTH (match_positions))) - return false; - /* Never mark same index twice, in case DontAdvance was used... */ - if (match_length && match_positions[match_length - 1] == buffer->out_len) + if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len) match_length--; - match_positions[match_length++] = buffer->out_len; + match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len; + DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len); } - if (flags & PerformAction) + if (LigatureEntryT::performAction (entry)) { + DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length); unsigned int end = buffer->out_len; - unsigned int action_idx = entry->data.ligActionIndex; - unsigned int action; + + if (unlikely (!match_length)) + return; + + if (buffer->idx >= buffer->len) + return; /* TODO Work on previous instead? */ + + unsigned int cursor = match_length; + + unsigned int action_idx = LigatureEntryT::ligActionIndex (entry); + action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ); + const HBUINT32 *actionData = &ligAction[action_idx]; + unsigned int ligature_idx = 0; + unsigned int action; do { - if (unlikely (!match_length)) - return false; + if (unlikely (!cursor)) + { + /* Stack underflow. Clear the stack. */ + DEBUG_MSG (APPLY, nullptr, "Stack underflow"); + match_length = 0; + break; + } - buffer->move_to (match_positions[--match_length]); + DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1); + buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]); - const HBUINT32 &actionData = ligAction[action_idx]; - if (unlikely (!actionData.sanitize (&c->sanitizer))) return false; - action = actionData; + if (unlikely (!actionData->sanitize (&c->sanitizer))) break; + action = *actionData; uint32_t uoffset = action & LigActionOffset; if (uoffset & 0x20000000) - uoffset += 0xC0000000; + uoffset |= 0xC0000000; /* Sign-extend. */ int32_t offset = (int32_t) uoffset; unsigned int component_idx = buffer->cur().codepoint + offset; - + component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); const HBUINT16 &componentData = component[component_idx]; - if (unlikely (!componentData.sanitize (&c->sanitizer))) return false; + if (unlikely (!componentData.sanitize (&c->sanitizer))) break; ligature_idx += componentData; + DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", + bool (action & LigActionStore), + bool (action & LigActionLast)); if (action & (LigActionStore | LigActionLast)) { + ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); const GlyphID &ligatureData = ligature[ligature_idx]; - if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false; + if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; hb_codepoint_t lig = ligatureData; - match_positions[match_length++] = buffer->out_len; + DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); buffer->replace_glyph (lig); - //ligature_idx = 0; // XXX Yes or no? - } - else - { - buffer->skip_glyph (); - end--; + unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; + /* Now go and delete all subsequent components. */ + while (match_length - 1u > cursor) + { + DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); + buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]); + buffer->replace_glyph (DELETED_GLYPH); + } + + buffer->move_to (lig_end); + buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len); } - /* TODO merge_clusters / unsafe_to_break */ - action_idx++; + actionData++; } while (!(action & LigActionLast)); buffer->move_to (end); } - - return true; } public: bool ret; private: hb_aat_apply_context_t *c; + const LigatureSubtable *table; const UnsizedArrayOf<HBUINT32> &ligAction; const UnsizedArrayOf<HBUINT16> &component; const UnsizedArrayOf<GlyphID> &ligature; @@ -446,19 +559,19 @@ struct LigatureSubtable unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; }; - inline bool apply (hb_aat_apply_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); driver_context_t dc (this, c); - StateTableDriver<EntryData> driver (machine, c->buffer, c->face); + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* The rest of array sanitizations are done at run-time. */ @@ -467,21 +580,22 @@ struct LigatureSubtable } protected: - StateTable<EntryData> + StateTable<Types, EntryData> machine; - LOffsetTo<UnsizedArrayOf<HBUINT32> > + NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT> ligAction; /* Offset to the ligature action table. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > + NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT> component; /* Offset to the component table. */ - LOffsetTo<UnsizedArrayOf<GlyphID> > + NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT> ligature; /* Offset to the actual ligature lists. */ public: DEFINE_SIZE_STATIC (28); }; +template <typename Types> struct NoncontextualSubtable { - inline bool apply (hb_aat_apply_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); @@ -503,7 +617,7 @@ struct NoncontextualSubtable return_trace (ret); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (substitute.sanitize (c)); @@ -515,27 +629,207 @@ struct NoncontextualSubtable DEFINE_SIZE_MIN (2); }; +template <typename Types> struct InsertionSubtable { - inline bool apply (hb_aat_apply_context_t *c) const + typedef typename Types::HBUINT HBUINT; + + struct EntryData + { + HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table. + * The number of glyphs to be inserted is contained + * in the currentInsertCount field in the flags. + * A value of 0xFFFF indicates no insertion is to + * be done. */ + HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table. + * The number of glyphs to be inserted is contained + * in the markedInsertCount field in the flags. + * A value of 0xFFFF indicates no insertion is to + * be done. */ + public: + DEFINE_SIZE_STATIC (4); + }; + + struct driver_context_t + { + static constexpr bool in_place = false; + enum Flags + { + SetMark = 0x8000, /* If set, mark the current glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. This does not mean + * that the glyph pointed to is the same one as + * before. If you've made insertions immediately + * downstream of the current glyph, the next glyph + * processed would in fact be the first one + * inserted. */ + CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). If clear, and + * the currentInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). */ + MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). If clear, and + * the markedInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). */ + CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made + * to the left of the current glyph. If clear, + * they're made to the right of the current glyph. */ + MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be + * made to the left of the marked glyph. If clear, + * they're made to the right of the marked glyph. */ + CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the current + * position. Since zero means no insertions, the + * largest number of insertions at any given + * current location is 31 glyphs. */ + MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the marked + * position. Since zero means no insertions, the + * largest number of insertions at any given + * marked location is 31 glyphs. */ + }; + + driver_context_t (const InsertionSubtable *table, + hb_aat_apply_context_t *c_) : + ret (false), + c (c_), + mark (0), + insertionAction (table+table->insertionAction) {} + + bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, + const Entry<EntryData> &entry) + { + return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && + (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); + } + void transition (StateTableDriver<Types, EntryData> *driver, + const Entry<EntryData> &entry) + { + hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry.flags; + + unsigned mark_loc = buffer->out_len; + + if (entry.data.markedInsertIndex != 0xFFFF) + { + unsigned int count = (flags & MarkedInsertCount); + unsigned int start = entry.data.markedInsertIndex; + const GlyphID *glyphs = &insertionAction[start]; + if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; + + bool before = flags & MarkedInsertBefore; + + unsigned int end = buffer->out_len; + buffer->move_to (mark); + + if (buffer->idx < buffer->len && !before) + buffer->copy_glyph (); + /* TODO We ignore KashidaLike setting. */ + for (unsigned int i = 0; i < count; i++) + buffer->output_glyph (glyphs[i]); + if (buffer->idx < buffer->len && !before) + buffer->skip_glyph (); + + buffer->move_to (end + count); + + buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len)); + } + + if (flags & SetMark) + mark = mark_loc; + + if (entry.data.currentInsertIndex != 0xFFFF) + { + unsigned int count = (flags & CurrentInsertCount) >> 5; + unsigned int start = entry.data.currentInsertIndex; + const GlyphID *glyphs = &insertionAction[start]; + if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; + + bool before = flags & CurrentInsertBefore; + + unsigned int end = buffer->out_len; + + if (buffer->idx < buffer->len && !before) + buffer->copy_glyph (); + /* TODO We ignore KashidaLike setting. */ + for (unsigned int i = 0; i < count; i++) + buffer->output_glyph (glyphs[i]); + if (buffer->idx < buffer->len && !before) + buffer->skip_glyph (); + + /* Humm. Not sure where to move to. There's this wording under + * DontAdvance flag: + * + * "If set, don't update the glyph index before going to the new state. + * This does not mean that the glyph pointed to is the same one as + * before. If you've made insertions immediately downstream of the + * current glyph, the next glyph processed would in fact be the first + * one inserted." + * + * This suggests that if DontAdvance is NOT set, we should move to + * end+count. If it *was*, then move to end, such that newly inserted + * glyphs are now visible. + * + * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 + */ + buffer->move_to ((flags & DontAdvance) ? end : end + count); + } + } + + public: + bool ret; + private: + hb_aat_apply_context_t *c; + unsigned int mark; + const UnsizedArrayOf<GlyphID> &insertionAction; + }; + + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - /* TODO */ - return_trace (false); + + driver_context_t dc (this, c); + + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); + driver.drive (&dc); + + return_trace (dc.ret); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* TODO */ - return_trace (true); + /* The rest of array sanitizations are done at run-time. */ + return_trace (c->check_struct (this) && machine.sanitize (c) && + insertionAction); } + + protected: + StateTable<Types, EntryData> + machine; + NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT> + insertionAction; /* Byte offset from stateHeader to the start of + * the insertion glyph table. */ + public: + DEFINE_SIZE_STATIC (20); }; struct Feature { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -553,15 +847,35 @@ struct Feature DEFINE_SIZE_STATIC (12); }; - +template <typename Types> struct ChainSubtable { + typedef typename Types::HBUINT HBUINT; + + template <typename T> friend struct Chain; - inline unsigned int get_size (void) const { return length; } - inline unsigned int get_type (void) const { return coverage & 0xFF; } + unsigned int get_size () const { return length; } + unsigned int get_type () const { return coverage & 0xFF; } + unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } - enum Type { + enum Coverage + { + Vertical = 0x80, /* If set, this subtable will only be applied + * to vertical text. If clear, this subtable + * will only be applied to horizontal text. */ + Backwards = 0x40, /* If set, this subtable will process glyphs + * in descending order. If clear, it will + * process the glyphs in ascending order. */ + AllDirections = 0x20, /* If set, this subtable will be applied to + * both horizontal and vertical text (i.e. + * the state of bit 0x80000000 is ignored). */ + Logical = 0x10, /* If set, this subtable will process glyphs + * in logical order (or reverse logical order, + * depending on the value of bit 0x80000000). */ + }; + enum Type + { Rearrangement = 0, Contextual = 1, Ligature = 2, @@ -569,13 +883,8 @@ struct ChainSubtable Insertion = 5 }; - inline void apply (hb_aat_apply_context_t *c) const - { - dispatch (c); - } - template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); @@ -589,58 +898,147 @@ struct ChainSubtable } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_sanitize_with_object_t with (&c->sanitizer, this); + return_trace (dispatch (c)); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!length.sanitize (c) || - length < min_size || + length <= min_size || !c->check_range (this, length)) return_trace (false); + hb_sanitize_with_object_t with (c, this); return_trace (dispatch (c)); } protected: - HBUINT32 length; /* Total subtable length, including this header. */ - HBUINT32 coverage; /* Coverage flags and subtable type. */ + HBUINT length; /* Total subtable length, including this header. */ + HBUINT coverage; /* Coverage flags and subtable type. */ HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */ union { - RearrangementSubtable rearrangement; - ContextualSubtable contextual; - LigatureSubtable ligature; - NoncontextualSubtable noncontextual; - InsertionSubtable insertion; + RearrangementSubtable<Types> rearrangement; + ContextualSubtable<Types> contextual; + LigatureSubtable<Types> ligature; + NoncontextualSubtable<Types> noncontextual; + InsertionSubtable<Types> insertion; } u; public: - DEFINE_SIZE_MIN (12); + DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4); }; +template <typename Types> struct Chain { - inline void apply (hb_aat_apply_context_t *c) const + typedef typename Types::HBUINT HBUINT; + + hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const { - const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount); + hb_mask_t flags = defaultFlags; + { + unsigned int count = featureCount; + for (unsigned i = 0; i < count; i++) + { + const Feature &feature = featureZ[i]; + hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; + hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; + retry: + const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type); + if (info && info->setting == setting) + { + flags &= feature.disableFlags; + flags |= feature.enableFlags; + } + else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS) + { + /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */ + type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE; + setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS; + goto retry; + } + } + } + return flags; + } + + void apply (hb_aat_apply_context_t *c, + hb_mask_t flags) const + { + const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount)); unsigned int count = subtableCount; for (unsigned int i = 0; i < count; i++) { + bool reverse; + + if (!(subtable->subFeatureFlags & flags)) + goto skip; + + if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && + HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != + bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical)) + goto skip; + + /* Buffer contents is always in logical direction. Determine if + * we need to reverse before applying this subtable. We reverse + * back after if we did reverse indeed. + * + * Quoting the spac: + * """ + * Bits 28 and 30 of the coverage field control the order in which + * glyphs are processed when the subtable is run by the layout engine. + * Bit 28 is used to indicate if the glyph processing direction is + * the same as logical order or layout order. Bit 30 is used to + * indicate whether glyphs are processed forwards or backwards within + * that order. + + Bit 30 Bit 28 Interpretation for Horizontal Text + 0 0 The subtable is processed in layout order + (the same order as the glyphs, which is + always left-to-right). + 1 0 The subtable is processed in reverse layout order + (the order opposite that of the glyphs, which is + always right-to-left). + 0 1 The subtable is processed in logical order + (the same order as the characters, which may be + left-to-right or right-to-left). + 1 1 The subtable is processed in reverse logical order + (the order opposite that of the characters, which + may be right-to-left or left-to-right). + */ + reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ? + bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) : + bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) != + HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); + if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index)) - { - c->set_lookup_index (c->lookup_index + 1); - continue; - } + goto skip; + + if (reverse) + c->buffer->reverse (); subtable->apply (c); - subtable = &StructAfter<ChainSubtable> (*subtable); + + if (reverse) + c->buffer->reverse (); (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index); + if (unlikely (!c->buffer->successful)) return; + + skip: + subtable = &StructAfter<ChainSubtable<Types> > (*subtable); c->set_lookup_index (c->lookup_index + 1); } } - inline unsigned int get_size (void) const { return length; } + unsigned int get_size () const { return length; } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const + bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const { TRACE_SANITIZE (this); if (!length.sanitize (c) || @@ -648,16 +1046,16 @@ struct Chain !c->check_range (this, length)) return_trace (false); - if (!c->check_array (featureZ, featureZ[0].static_size, featureCount)) + if (!c->check_array (featureZ.arrayZ, featureCount)) return_trace (false); - const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount); + const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount)); unsigned int count = subtableCount; for (unsigned int i = 0; i < count; i++) { if (!subtable->sanitize (c)) return_trace (false); - subtable = &StructAfter<ChainSubtable> (*subtable); + subtable = &StructAfter<ChainSubtable<Types> > (*subtable); } return_trace (true); @@ -666,69 +1064,95 @@ struct Chain protected: HBUINT32 defaultFlags; /* The default specification for subtables. */ HBUINT32 length; /* Total byte count, including this header. */ - HBUINT32 featureCount; /* Number of feature subtable entries. */ - HBUINT32 subtableCount; /* The number of subtables in the chain. */ + HBUINT featureCount; /* Number of feature subtable entries. */ + HBUINT subtableCount; /* The number of subtables in the chain. */ - Feature featureZ[VAR]; /* Features. */ -/*ChainSubtable subtableX[VAR];*//* Subtables. */ -/*subtableGlyphCoverageArray*/ /* Only if major == 3. */ + UnsizedArrayOf<Feature> featureZ; /* Features. */ +/*ChainSubtable firstSubtable;*//* Subtables. */ +/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ public: - DEFINE_SIZE_MIN (16); + DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); }; /* - * The 'mort'/'morx' Tables + * The 'mort'/'morx' Table */ -struct morx +template <typename Types> +struct mortmorx { - static const hb_tag_t tableTag = HB_AAT_TAG_morx; + static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx; + + bool has_data () const { return version != 0; } + + void compile_flags (const hb_aat_map_builder_t *mapper, + hb_aat_map_t *map) const + { + const Chain<Types> *chain = &firstChain; + unsigned int count = chainCount; + for (unsigned int i = 0; i < count; i++) + { + map->chain_flags.push (chain->compile_flags (mapper)); + chain = &StructAfter<Chain<Types> > (*chain); + } + } - inline void apply (hb_aat_apply_context_t *c) const + void apply (hb_aat_apply_context_t *c) const { + if (unlikely (!c->buffer->successful)) return; c->set_lookup_index (0); - const Chain *chain = chainsZ; + const Chain<Types> *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - chain->apply (c); - chain = &StructAfter<Chain> (*chain); + chain->apply (c, c->plan->aat_map.chain_flags[i]); + if (unlikely (!c->buffer->successful)) return; + chain = &StructAfter<Chain<Types> > (*chain); } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!version.sanitize (c) || - (version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 || - !chainCount.sanitize (c)) + if (!version.sanitize (c) || !version || !chainCount.sanitize (c)) return_trace (false); - const Chain *chain = chainsZ; + const Chain<Types> *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - if (!chain->sanitize (c, version.major)) + if (!chain->sanitize (c, version)) return_trace (false); - chain = &StructAfter<Chain> (*chain); + chain = &StructAfter<Chain<Types> > (*chain); } return_trace (true); } protected: - FixedVersion<>version; /* Version number of the glyph metamorphosis table. - * 1 for mort, 2 or 3 for morx. */ + HBUINT16 version; /* Version number of the glyph metamorphosis table. + * 1, 2, or 3. */ + HBUINT16 unused; /* Set to 0. */ HBUINT32 chainCount; /* Number of metamorphosis chains contained in this * table. */ - Chain chainsZ[VAR]; /* Chains. */ + Chain<Types> firstChain; /* Chains. */ public: DEFINE_SIZE_MIN (8); }; +struct morx : mortmorx<ExtendedTypes> +{ + static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx; +}; +struct mort : mortmorx<ObsoleteTypes> +{ + static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort; +}; + + } /* namespace AAT */ diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh index 0617e23..0c8e455 100644 --- a/src/hb-aat-layout-trak-table.hh +++ b/src/hb-aat-layout-trak-table.hh @@ -28,9 +28,9 @@ #ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH #define HB_AAT_LAYOUT_TRAK_TABLE_HH -#include "hb-aat-layout-common-private.hh" -#include "hb-ot-layout-private.hh" -#include "hb-open-type-private.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout.hh" +#include "hb-open-type.hh" /* * trak -- Tracking @@ -46,29 +46,27 @@ struct TrackTableEntry { friend struct TrackData; - inline bool sanitize (hb_sanitize_context_t *c, const void *base, - unsigned int size) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (valuesZ.sanitize (c, base, size)))); - } + float get_track_value () const { return track.to_float (); } - private: - inline float get_track_value () const - { - return track.to_float (); - } + int get_value (const void *base, unsigned int index, + unsigned int table_size) const + { return (base+valuesZ).as_array (table_size)[index]; } - inline int get_value (const void *base, unsigned int index) const + public: + bool sanitize (hb_sanitize_context_t *c, const void *base, + unsigned int table_size) const { - return (base+valuesZ)[index]; + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (valuesZ.sanitize (c, base, table_size)))); } protected: Fixed track; /* Track value for this record. */ - NameID trackNameID; /* The 'name' table index for this track */ - OffsetTo<UnsizedArrayOf<FWORD> > + NameID trackNameID; /* The 'name' table index for this track. + * (a short word or phrase like "loose" + * or "very tight") */ + NNOffsetTo<UnsizedArrayOf<FWORD> > valuesZ; /* Offset from start of tracking table to * per-size tracking values for this track. */ @@ -78,15 +76,22 @@ struct TrackTableEntry struct TrackData { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + float interpolate_at (unsigned int idx, + float target_size, + const TrackTableEntry &trackTableEntry, + const void *base) const { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - sizeTable.sanitize (c, base, nSizes) && - trackTable.sanitize (c, nTracks, base, nSizes)); + unsigned int sizes = nSizes; + hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes); + + float s0 = size_table[idx].to_float (); + float s1 = size_table[idx + 1].to_float (); + float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0); + return t * trackTableEntry.get_value (base, idx + 1, sizes) + + (1.f - t) * trackTableEntry.get_value (base, idx, sizes); } - inline float get_tracking (const void *base, float ptem) const + int get_tracking (const void *base, float ptem) const { /* CoreText points are CSS pixels (96 per inch), * NOT typographic points (72 per inch). @@ -94,48 +99,58 @@ struct TrackData * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html */ float csspx = ptem * 96.f / 72.f; - Fixed fixed_size; - fixed_size.set_float (csspx); - /* XXX Clean this up. Make it work with nSizes==1 and 0. */ + /* + * Choose track. + */ + const TrackTableEntry *trackTableEntry = nullptr; + unsigned int count = nTracks; + for (unsigned int i = 0; i < count; i++) + { + /* Note: Seems like the track entries are sorted by values. But the + * spec doesn't explicitly say that. It just mentions it in the example. */ - unsigned int sizes = nSizes; + /* For now we only seek for track entries with zero tracking value */ - const TrackTableEntry *trackTableEntry = nullptr; - for (unsigned int i = 0; i < sizes; ++i) - // For now we only seek for track entries with zero tracking value if (trackTable[i].get_track_value () == 0.f) - trackTableEntry = &trackTable[0]; - - // We couldn't match any, exit + { + trackTableEntry = &trackTable[i]; + break; + } + } if (!trackTableEntry) return 0.; - /* TODO bfind() */ + /* + * Choose size. + */ + unsigned int sizes = nSizes; + if (!sizes) return 0.; + if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); + + hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes); unsigned int size_index; - UnsizedArrayOf<Fixed> size_table = base+sizeTable; - for (size_index = 0; size_index < sizes; ++size_index) - if (size_table[size_index] >= fixed_size) + for (size_index = 0; size_index < sizes - 1; size_index++) + if (size_table[size_index].to_float () >= csspx) break; - // TODO(ebraminio): We don't attempt to extrapolate to larger or - // smaller values for now but we should do, per spec - if (size_index == sizes) - return trackTableEntry->get_value (base, sizes - 1); - if (size_index == 0 || size_table[size_index] == fixed_size) - return trackTableEntry->get_value (base, size_index); - - float s0 = size_table[size_index - 1].to_float (); - float s1 = size_table[size_index].to_float (); - float t = (csspx - s0) / (s1 - s0); - return (float) t * trackTableEntry->get_value (base, size_index) + - ((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1); + return round (interpolate_at (size_index ? size_index - 1 : 0, csspx, + *trackTableEntry, base)); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + sizeTable.sanitize (c, base, nSizes) && + trackTable.sanitize (c, nTracks, base, nSizes))); } protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ - LOffsetTo<UnsizedArrayOf<Fixed> > - sizeTable; /* Offset to array[nSizes] of size values. */ + LOffsetTo<UnsizedArrayOf<Fixed>, false> + sizeTable; /* Offset from start of the tracking table to + * Array[nSizes] of size values.. */ UnsizedArrayOf<TrackTableEntry> trackTable; /* Array[nTracks] of TrackTableEntry records. */ @@ -145,21 +160,16 @@ struct TrackData struct trak { - static const hb_tag_t tableTag = HB_AAT_TAG_trak; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); + static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak; - return_trace (unlikely (c->check_struct (this) && - horizData.sanitize (c, this, this) && - vertData.sanitize (c, this, this))); - } + bool has_data () const { return version.to_int (); } - inline bool apply (hb_aat_apply_context_t *c) const + bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); + hb_mask_t trak_mask = c->plan->trak_mask; + const float ptem = c->font->ptem; if (unlikely (ptem <= 0.f)) return_trace (false); @@ -168,41 +178,57 @@ struct trak if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) { const TrackData &trackData = this+horizData; - float tracking = trackData.get_tracking (this, ptem); - hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2); + int tracking = trackData.get_tracking (this, ptem); + hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2); + hb_position_t advance_to_add = c->font->em_scalef_x (tracking); foreach_grapheme (buffer, start, end) { - /* TODO This is wrong. */ + if (!(buffer->info[start].mask & trak_mask)) continue; buffer->pos[start].x_advance += advance_to_add; - buffer->pos[end].x_advance += advance_to_add; + buffer->pos[start].x_offset += offset_to_add; } } else { const TrackData &trackData = this+vertData; - float tracking = trackData.get_tracking (this, ptem); - hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2); + int tracking = trackData.get_tracking (this, ptem); + hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2); + hb_position_t advance_to_add = c->font->em_scalef_y (tracking); foreach_grapheme (buffer, start, end) { - /* TODO This is wrong. */ + if (!(buffer->info[start].mask & trak_mask)) continue; buffer->pos[start].y_advance += advance_to_add; - buffer->pos[end].y_advance += advance_to_add; + buffer->pos[start].y_offset += offset_to_add; } } return_trace (true); } + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + return_trace (likely (c->check_struct (this) && + version.major == 1 && + horizData.sanitize (c, this, this) && + vertData.sanitize (c, this, this))); + } + protected: - FixedVersion<> version; /* Version of the tracking table--currently - * 0x00010000u for version 1.0. */ - HBUINT16 format; /* Format of the tracking table */ - OffsetTo<TrackData> horizData; /* TrackData for horizontal text */ - OffsetTo<TrackData> vertData; /* TrackData for vertical text */ - HBUINT16 reserved; /* Reserved. Set to 0. */ + FixedVersion<>version; /* Version of the tracking table + * (0x00010000u for version 1.0). */ + HBUINT16 format; /* Format of the tracking table (set to 0). */ + OffsetTo<TrackData> + horizData; /* Offset from start of tracking table to TrackData + * for horizontal text (or 0 if none). */ + OffsetTo<TrackData> + vertData; /* Offset from start of tracking table to TrackData + * for vertical text (or 0 if none). */ + HBUINT16 reserved; /* Reserved. Set to 0. */ public: - DEFINE_SIZE_MIN (12); + DEFINE_SIZE_STATIC (12); }; } /* namespace AAT */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 7784fae..5168a9c 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -1,5 +1,6 @@ /* * Copyright © 2017 Google, Inc. + * Copyright © 2018 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -24,131 +25,360 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" -#include "hb-ot-layout-gsubgpos-private.hh" - -#include "hb-aat-layout-private.hh" +#include "hb-ot-face.hh" +#include "hb-aat-layout.hh" +#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-ankr-table.hh" #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise. -#include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise. +#include "hb-aat-layout-feat-table.hh" +#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-kerx-table.hh" #include "hb-aat-layout-morx-table.hh" #include "hb-aat-layout-trak-table.hh" -#include "hb-aat-fmtx-table.hh" // Just so we compile it; unused otherwise. -#include "hb-aat-gcid-table.hh" // Just so we compile it; unused otherwise. -#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise. +#include "hb-aat-ltag-table.hh" + + +/** + * SECTION:hb-aat-layout + * @title: hb-aat-layout + * @short_description: Apple Advanced Typography Layout + * @include: hb-aat.h + * + * Functions for querying OpenType Layout features in the font face. + **/ + + +/* Table data courtesy of Apple. Converted from mnemonics to integers + * when moving to this file. */ +static const hb_aat_feature_mapping_t feature_mappings[] = +{ + {HB_TAG ('a','f','r','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS}, + {HB_TAG ('c','2','p','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE}, + {HB_TAG ('c','2','s','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE}, + {HB_TAG ('c','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF}, + {HB_TAG ('c','a','s','e'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF}, + {HB_TAG ('c','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF}, + {HB_TAG ('c','p','s','p'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF}, + {HB_TAG ('c','s','w','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF}, + {HB_TAG ('d','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF}, + {HB_TAG ('e','x','p','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS}, + {HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF}, + {HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF}, + {HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF}, + {HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION}, + {HB_TAG ('h','o','j','o'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('h','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('i','t','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF}, + {HB_TAG ('j','p','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('j','p','7','8'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('j','p','8','3'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('j','p','9','0'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('l','i','g','a'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF}, + {HB_TAG ('l','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2}, + {HB_TAG ('m','g','r','k'), HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF}, + {HB_TAG ('n','l','c','k'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('o','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2}, + {HB_TAG ('o','r','d','n'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, + {HB_TAG ('p','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('p','c','a','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE}, + {HB_TAG ('p','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4}, + {HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF}, + {HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, + {HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE}, + {HB_TAG ('s','m','p','l'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('s','s','0','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF}, + {HB_TAG ('s','s','0','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF}, + {HB_TAG ('s','s','0','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF}, + {HB_TAG ('s','s','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF}, + {HB_TAG ('s','s','0','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF}, + {HB_TAG ('s','s','0','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF}, + {HB_TAG ('s','s','0','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF}, + {HB_TAG ('s','s','0','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF}, + {HB_TAG ('s','s','0','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF}, + {HB_TAG ('s','s','1','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF}, + {HB_TAG ('s','s','1','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF}, + {HB_TAG ('s','s','1','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF}, + {HB_TAG ('s','s','1','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF}, + {HB_TAG ('s','s','1','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF}, + {HB_TAG ('s','s','1','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF}, + {HB_TAG ('s','s','1','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF}, + {HB_TAG ('s','s','1','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF}, + {HB_TAG ('s','s','1','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF}, + {HB_TAG ('s','s','1','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF}, + {HB_TAG ('s','s','2','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF}, + {HB_TAG ('s','u','b','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, + {HB_TAG ('s','u','p','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, + {HB_TAG ('s','w','s','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF}, + {HB_TAG ('t','i','t','l'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS}, + {HB_TAG ('t','n','a','m'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('t','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS, (hb_aat_layout_feature_selector_t) 4}, + {HB_TAG ('t','r','a','d'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS, (hb_aat_layout_feature_selector_t) 16}, + {HB_TAG ('t','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('u','n','i','c'), HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE, (hb_aat_layout_feature_selector_t) 14, (hb_aat_layout_feature_selector_t) 15}, + {HB_TAG ('v','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('v','e','r','t'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF}, + {HB_TAG ('v','h','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF}, + {HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF}, + {HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF}, +}; + +const hb_aat_feature_mapping_t * +hb_aat_layout_find_feature_mapping (hb_tag_t tag) +{ + return (const hb_aat_feature_mapping_t *) bsearch (&tag, + feature_mappings, + ARRAY_LENGTH (feature_mappings), + sizeof (feature_mappings[0]), + hb_aat_feature_mapping_t::cmp); +} + /* - * morx/kerx/trak + * hb_aat_apply_context_t */ -#if 0 -static inline const AAT::ankr& -_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr) +AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, + hb_font_t *font_, + hb_buffer_t *buffer_, + hb_blob_t *blob) : + plan (plan_), + font (font_), + face (font->face), + buffer (buffer_), + sanitizer (), + ankr_table (&Null(AAT::ankr)), + lookup_index (0), + debug_depth (0) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) - { - if (blob) - *blob = hb_blob_get_empty (); - return Null(AAT::ankr); - } - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - const AAT::ankr& ankr = *(layout->ankr.get ()); - if (blob) - *blob = layout->ankr.blob; - return ankr; + sanitizer.init (blob); + sanitizer.set_num_glyphs (face->get_num_glyphs ()); + sanitizer.start_processing (); + sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX); } -static inline const AAT::kerx& -_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr) +AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t () +{ sanitizer.end_processing (); } + +void +AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_) +{ ankr_table = ankr_table_; } + + +/* + * mort/morx/kerx/trak + */ + + +void +hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, + hb_aat_map_t *map) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + const AAT::morx& morx = *mapper->face->table.morx; + if (morx.has_data ()) { - if (blob) - *blob = hb_blob_get_empty (); - return Null(AAT::kerx); + morx.compile_flags (mapper, map); + return; } - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - /* XXX this doesn't call set_num_glyphs on sanitizer. */ - const AAT::kerx& kerx = *(layout->kerx.get ()); - if (blob) - *blob = layout->kerx.blob; - return kerx; -} -static inline const AAT::morx& -_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + const AAT::mort& mort = *mapper->face->table.mort; + if (mort.has_data ()) { - if (blob) - *blob = hb_blob_get_empty (); - return Null(AAT::morx); + mort.compile_flags (mapper, map); + return; } - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - /* XXX this doesn't call set_num_glyphs on sanitizer. */ - const AAT::morx& morx = *(layout->morx.get ()); - if (blob) - *blob = layout->morx.blob; - return morx; } -static inline const AAT::trak& -_get_trak (hb_face_t *face, hb_blob_t **blob = nullptr) + +/* + * hb_aat_layout_has_substitution: + * @face: + * + * Returns: + * Since: 2.3.0 + */ +hb_bool_t +hb_aat_layout_has_substitution (hb_face_t *face) +{ + return face->table.morx->has_data () || + face->table.mort->has_data (); +} + +void +hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + hb_blob_t *morx_blob = font->face->table.morx.get_blob (); + const AAT::morx& morx = *morx_blob->as<AAT::morx> (); + if (morx.has_data ()) { - if (blob) - *blob = hb_blob_get_empty (); - return Null(AAT::trak); + AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); + morx.apply (&c); + return; } - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - const AAT::trak& trak = *(layout->trak.get ()); - if (blob) - *blob = layout->trak.blob; - return trak; -} -#endif - -// static inline void -// _hb_aat_layout_create (hb_face_t *face) -// { -// OT::Sanitizer<AAT::morx> sanitizer; -// sanitizer.set_num_glyphs (face->get_num_glyphs ()); -// hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_morx)); -// morx_blob->as<AAT::morx> (); - -// if (0) -// { -// morx_blob->as<AAT::Lookup<OT::GlyphID> > ()->get_value (1, face->get_num_glyphs ()); -// } -// } + + hb_blob_t *mort_blob = font->face->table.mort.get_blob (); + const AAT::mort& mort = *mort_blob->as<AAT::mort> (); + if (mort.has_data ()) + { + AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); + mort.apply (&c); + return; + } +} void -hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer) +hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer) { -#if 0 - hb_blob_t *blob; - const AAT::morx& morx = _get_morx (font->face, &blob); + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + for (unsigned int i = 0; i < count; i++) + if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH)) + pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; +} - AAT::hb_aat_apply_context_t c (font, buffer, blob); - morx.apply (&c); -#endif +static bool +is_deleted_glyph (const hb_glyph_info_t *info) +{ + return info->codepoint == AAT::DELETED_GLYPH; } void -hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer) +hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) { -#if 0 - hb_blob_t *blob; - const AAT::ankr& ankr = _get_ankr (font->face, &blob); - const AAT::kerx& kerx = _get_kerx (font->face, &blob); - const AAT::trak& trak = _get_trak (font->face, &blob); + hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph); +} - AAT::hb_aat_apply_context_t c (font, buffer, blob); - kerx.apply (&c, &ankr); +/* + * hb_aat_layout_has_positioning: + * @face: + * + * Returns: + * Since: 2.3.0 + */ +hb_bool_t +hb_aat_layout_has_positioning (hb_face_t *face) +{ + return face->table.kerx->has_data (); +} + +void +hb_aat_layout_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + hb_blob_t *kerx_blob = font->face->table.kerx.get_blob (); + const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> (); + + AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob); + c.set_ankr_table (font->face->table.ankr.get ()); + kerx.apply (&c); +} + + +/* + * hb_aat_layout_has_tracking: + * @face: + * + * Returns: + * Since: 2.3.0 + */ +hb_bool_t +hb_aat_layout_has_tracking (hb_face_t *face) +{ + return face->table.trak->has_data (); +} + +void +hb_aat_layout_track (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + const AAT::trak& trak = *font->face->table.trak; + + AAT::hb_aat_apply_context_t c (plan, font, buffer); trak.apply (&c); -#endif +} + + +hb_language_t +_hb_aat_language_get (hb_face_t *face, + unsigned int i) +{ + return face->table.ltag->get_language (i); +} + +/** + * hb_aat_layout_get_feature_types: + * @face: a face object + * @start_offset: iteration's start offset + * @feature_count:(inout) (allow-none): buffer size as input, filled size as output + * @features: (out caller-allocates) (array length=feature_count): features buffer + * + * Return value: Number of all available feature types. + * + * Since: 2.2.0 + */ +unsigned int +hb_aat_layout_get_feature_types (hb_face_t *face, + unsigned int start_offset, + unsigned int *feature_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */) +{ + return face->table.feat->get_feature_types (start_offset, feature_count, features); +} + +/** + * hb_aat_layout_feature_type_get_name_id: + * @face: a face object + * @feature_type: feature id + * + * Return value: Name ID index + * + * Since: 2.2.0 + */ +hb_ot_name_id_t +hb_aat_layout_feature_type_get_name_id (hb_face_t *face, + hb_aat_layout_feature_type_t feature_type) +{ + return face->table.feat->get_feature_name_id (feature_type); +} + +/** + * hb_aat_layout_feature_type_get_selectors: + * @face: a face object + * @feature_type: feature id + * @start_offset: iteration's start offset + * @selector_count: (inout) (allow-none): buffer size as input, filled size as output + * @selectors: (out caller-allocates) (array length=selector_count): settings buffer + * @default_index: (out) (allow-none): index of default selector if any + * + * If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then + * the feature type is non-exclusive. Otherwise, @default_index is the index of + * the selector that is selected by default. + * + * Return value: Number of all available feature selectors. + * + * Since: 2.2.0 + */ +unsigned int +hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face, + hb_aat_layout_feature_type_t feature_type, + unsigned int start_offset, + unsigned int *selector_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */ + unsigned int *default_index /* OUT. May be NULL. */) +{ + return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index); } diff --git a/src/hb-aat-layout.h b/src/hb-aat-layout.h new file mode 100644 index 0000000..760aaae --- /dev/null +++ b/src/hb-aat-layout.h @@ -0,0 +1,486 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#ifndef HB_AAT_H_IN +#error "Include <hb-aat.h> instead." +#endif + +#ifndef HB_AAT_LAYOUT_H +#define HB_AAT_LAYOUT_H + +#include "hb.h" + +#include "hb-ot.h" + +HB_BEGIN_DECLS + +/** + * hb_aat_layout_feature_type_t: + * + * + * Since: 2.2.0 + */ +typedef enum +{ + HB_AAT_LAYOUT_FEATURE_TYPE_INVALID = 0xFFFF, + + HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0, + HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1, + HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2, + HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3, + HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4, + HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5, + HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING = 6, + HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE = 8, + HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE = 9, + HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION = 10, + HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS = 11, + HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE = 13, + HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS = 14, + HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS = 15, + HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE = 16, + HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES = 17, + HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE = 18, + HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS = 19, + HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE = 20, + HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE = 21, + HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING = 22, + HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION = 23, + HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE = 24, + HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE = 25, + HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE = 26, + HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE = 27, + HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA = 28, + HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE = 29, + HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE = 30, + HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE = 31, + HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN = 32, + HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT = 33, + HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA = 34, + HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES = 35, + HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES = 36, + HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE = 37, + HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE = 38, + HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39, + HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103, + + _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/ +} hb_aat_layout_feature_type_t; + +/** + * hb_aat_layout_feature_selector_t: + * + * + * Since: 2.2.0 + */ +typedef enum +{ + HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID = 0xFFFF, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON = 10, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF = 11, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON = 12, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF = 13, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON = 14, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF = 15, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON = 16, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF = 17, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON = 18, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF = 19, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON = 20, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF = 21, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE = 0, /* deprecated */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS = 1, /* deprecated */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE = 2, /* deprecated */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS = 3, /* deprecated */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS = 4, /* deprecated */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS = 5, /* deprecated */ + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS = 3, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF = 9, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS = 4, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON = 10, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF = 11, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON = 10, + HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF = 11, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS = 6, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES = 0, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1 = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2 = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3 = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4 = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5 = 4, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS = 5, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS = 10, + HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS = 11, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS = 12, + HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS = 13, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS = 14, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT = 6, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE = 9, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION= 10, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF = 5, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF = 3, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE = 5, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE = 5, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE = 1, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF = 3, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF = 3, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF = 3, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF = 5, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON = 6, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF = 7, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON = 8, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF = 9, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON = 10, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF = 11, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON = 12, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF = 13, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON = 14, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF = 15, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON = 16, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF = 17, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON = 18, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF = 19, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON = 20, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF = 21, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON = 22, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF = 23, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON = 24, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF = 25, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON = 26, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF = 27, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON = 28, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF = 29, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON = 30, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF = 31, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON = 32, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF = 33, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON = 34, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF = 35, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON = 36, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF = 37, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON = 38, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF = 39, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON = 40, + HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF = 41, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF = 3, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON = 4, + HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF= 5, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS = 2, + + /* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */ + HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN = 0, + HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN = 1, + HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2, + HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3, + + _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/ +} hb_aat_layout_feature_selector_t; + +HB_EXTERN unsigned int +hb_aat_layout_get_feature_types (hb_face_t *face, + unsigned int start_offset, + unsigned int *feature_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */); + +HB_EXTERN hb_ot_name_id_t +hb_aat_layout_feature_type_get_name_id (hb_face_t *face, + hb_aat_layout_feature_type_t feature_type); + +typedef struct hb_aat_layout_feature_selector_info_t +{ + hb_ot_name_id_t name_id; + hb_aat_layout_feature_selector_t enable; + hb_aat_layout_feature_selector_t disable; + /*< private >*/ + unsigned int reserved; +} hb_aat_layout_feature_selector_info_t; + +#define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu + +HB_EXTERN unsigned int +hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face, + hb_aat_layout_feature_type_t feature_type, + unsigned int start_offset, + unsigned int *selector_count, /* IN/OUT. May be NULL. */ + hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */ + unsigned int *default_index /* OUT. May be NULL. */); + + +/* + * morx/mort + */ + +HB_EXTERN hb_bool_t +hb_aat_layout_has_substitution (hb_face_t *face); + + +/* + * kerx + */ + +HB_EXTERN hb_bool_t +hb_aat_layout_has_positioning (hb_face_t *face); + + +/* + * trak + */ + +HB_EXTERN hb_bool_t +hb_aat_layout_has_tracking (hb_face_t *face); + + +HB_END_DECLS + +#endif /* HB_AAT_LAYOUT_H */ diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh new file mode 100644 index 0000000..8346d9f --- /dev/null +++ b/src/hb-aat-layout.hh @@ -0,0 +1,85 @@ +/* + * Copyright © 2017 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): Behdad Esfahbod + */ + +#ifndef HB_AAT_LAYOUT_HH +#define HB_AAT_LAYOUT_HH + +#include "hb.hh" + +#include "hb-ot-shape.hh" + + +struct hb_aat_feature_mapping_t +{ + hb_tag_t otFeatureTag; + hb_aat_layout_feature_type_t aatFeatureType; + hb_aat_layout_feature_selector_t selectorToEnable; + hb_aat_layout_feature_selector_t selectorToDisable; + + static int cmp (const void *key_, const void *entry_) + { + hb_tag_t key = * (unsigned int *) key_; + const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_; + return key < entry->otFeatureTag ? -1 : + key > entry->otFeatureTag ? 1 : + 0; + } +}; + +HB_INTERNAL const hb_aat_feature_mapping_t * +hb_aat_layout_find_feature_mapping (hb_tag_t tag); + +HB_INTERNAL void +hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, + hb_aat_map_t *map); + +HB_INTERNAL void +hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +HB_INTERNAL void +hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); + +HB_INTERNAL void +hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer); + +HB_INTERNAL void +hb_aat_layout_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +HB_INTERNAL void +hb_aat_layout_track (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +HB_INTERNAL hb_language_t +_hb_aat_language_get (hb_face_t *face, + unsigned int i); + + +#endif /* HB_AAT_LAYOUT_HH */ diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh index 15c4e89..6f34a00 100644 --- a/src/hb-aat-ltag-table.hh +++ b/src/hb-aat-ltag-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LTAG_TABLE_HH #define HB_AAT_LTAG_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-open-type.hh" /* * ltag -- Language Tag @@ -36,17 +36,21 @@ namespace AAT { +using namespace OT; + struct FTStringRange { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + friend struct ltag; + + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && (base+tag).sanitize (c, length)); } protected: - OffsetTo<UnsizedArrayOf<HBUINT8> > + NNOffsetTo<UnsizedArrayOf<HBUINT8> > tag; /* Offset from the start of the table to * the beginning of the string */ HBUINT16 length; /* String length (in bytes) */ @@ -56,12 +60,21 @@ struct FTStringRange struct ltag { - static const hb_tag_t tableTag = HB_AAT_TAG_ltag; + static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag; + + hb_language_t get_language (unsigned int i) const + { + const FTStringRange &range = tagRanges[i]; + return hb_language_from_string ((const char *) (this+range.tag).arrayZ, + range.length); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && tagRanges.sanitize (c, this))); + return_trace (likely (c->check_struct (this) && + version >= 1 && + tagRanges.sanitize (c, this))); } protected: diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc new file mode 100644 index 0000000..98c5d7f --- /dev/null +++ b/src/hb-aat-map.cc @@ -0,0 +1,68 @@ +/* + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2010,2011,2013 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-aat-map.hh" + +#include "hb-aat-layout.hh" + + +void hb_aat_map_builder_t::add_feature (hb_tag_t tag, + unsigned int value) +{ + if (tag == HB_TAG ('a','a','l','t')) + { + feature_info_t *info = features.push(); + info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; + info->setting = (hb_aat_layout_feature_selector_t) value; + return; + } + + const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); + if (!mapping) return; + + feature_info_t *info = features.push(); + info->type = mapping->aatFeatureType; + info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; +} + +void +hb_aat_map_builder_t::compile (hb_aat_map_t &m) +{ + /* Sort features and merge duplicates */ + if (features.length) + { + features.qsort (); + unsigned int j = 0; + for (unsigned int i = 1; i < features.length; i++) + if (features[i].type != features[j].type) + features[++j] = features[i]; + features.shrink (j + 1); + } + + hb_aat_layout_compile_map (this, &m); +} diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh new file mode 100644 index 0000000..3d5ad0e --- /dev/null +++ b/src/hb-aat-map.hh @@ -0,0 +1,91 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_AAT_MAP_HH +#define HB_AAT_MAP_HH + +#include "hb.hh" + + +struct hb_aat_map_t +{ + friend struct hb_aat_map_builder_t; + + public: + + void init () + { + memset (this, 0, sizeof (*this)); + chain_flags.init (); + } + void fini () { chain_flags.fini (); } + + public: + hb_vector_t<hb_mask_t> chain_flags; +}; + +struct hb_aat_map_builder_t +{ + public: + + HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_, + const hb_segment_properties_t *props_ HB_UNUSED) : + face (face_) {} + + HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); + + HB_INTERNAL void compile (hb_aat_map_t &m); + + public: + struct feature_info_t + { + hb_aat_layout_feature_type_t type; + hb_aat_layout_feature_selector_t setting; + unsigned seq; /* For stable sorting only. */ + + static int cmp (const void *pa, const void *pb) + { + const feature_info_t *a = (const feature_info_t *) pa; + const feature_info_t *b = (const feature_info_t *) pb; + return (a->type != b->type) ? (a->type < b->type ? -1 : 1) : + (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); + } + + int cmp (hb_aat_layout_feature_type_t ty) const + { + return (type != ty) ? (type < ty ? -1 : 1) : 0; + } + }; + + public: + hb_face_t *face; + + public: + hb_vector_t<feature_info_t> features; +}; + + +#endif /* HB_AAT_MAP_HH */ diff --git a/src/hb-ot-tag.h b/src/hb-aat.h index 54fb747..c14313d 100644 --- a/src/hb-ot-tag.h +++ b/src/hb-aat.h @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Red Hat, Inc. + * Copyright © 2018 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,40 +20,19 @@ * 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. - * - * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_OT_H_IN -#error "Include <hb-ot.h> instead." -#endif - -#ifndef HB_OT_TAG_H -#define HB_OT_TAG_H +#ifndef HB_AAT_H +#define HB_AAT_H +#define HB_AAT_H_IN #include "hb.h" -HB_BEGIN_DECLS - - -#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T') -#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't') - -HB_EXTERN void -hb_ot_tags_from_script (hb_script_t script, - hb_tag_t *script_tag_1, - hb_tag_t *script_tag_2); - -HB_EXTERN hb_script_t -hb_ot_tag_to_script (hb_tag_t tag); - -HB_EXTERN hb_tag_t -hb_ot_tag_from_language (hb_language_t language); - -HB_EXTERN hb_language_t -hb_ot_tag_to_language (hb_tag_t tag); +#include "hb-aat-layout.h" +HB_BEGIN_DECLS HB_END_DECLS -#endif /* HB_OT_TAG_H */ +#undef HB_AAT_H_IN +#endif /* HB_AAT_H */ diff --git a/src/hb-array.hh b/src/hb-array.hh new file mode 100644 index 0000000..52b775e --- /dev/null +++ b/src/hb-array.hh @@ -0,0 +1,277 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_ARRAY_HH +#define HB_ARRAY_HH + +#include "hb.hh" +#include "hb-dsalgs.hh" +#include "hb-iter.hh" +#include "hb-null.hh" + + +template <typename Type> +struct hb_sorted_array_t; + +template <typename Type> +struct hb_array_t : + hb_iter_t<hb_array_t<Type>, Type>, + hb_iter_mixin_t<hb_array_t<Type>, Type> +{ + /* + * Constructors. + */ + hb_array_t () : arrayZ (nullptr), length (0) {} + hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {} + template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {} + + + /* + * Iterator implementation. + */ + typedef Type __item_type__; + Type& __item_at__ (unsigned i) const + { + if (unlikely (i >= length)) return CrapOrNull (Type); + return arrayZ[i]; + } + void __forward__ (unsigned n) + { + if (unlikely (n > length)) + n = length; + length -= n; + arrayZ += n; + } + void __rewind__ (unsigned n) + { + if (unlikely (n > length)) + n = length; + length -= n; + } + unsigned __len__ () const { return length; } + bool __random_access__ () const { return true; } + + /* Extra operators. + */ + Type * operator & () const { return arrayZ; } + operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); } + template <typename T> operator T * () const { return arrayZ; } + + /* + * Compare, Sort, and Search. + */ + + /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */ + int cmp (const hb_array_t<Type> &a) const + { + if (length != a.length) + return (int) a.length - (int) length; + return hb_memcmp (a.arrayZ, arrayZ, get_size ()); + } + static int cmp (const void *pa, const void *pb) + { + hb_array_t<Type> *a = (hb_array_t<Type> *) pa; + hb_array_t<Type> *b = (hb_array_t<Type> *) pb; + return b->cmp (*a); + } + + template <typename T> + Type *lsearch (const T &x, Type *not_found = nullptr) + { + unsigned int count = length; + for (unsigned int i = 0; i < count; i++) + if (!this->arrayZ[i].cmp (x)) + return &this->arrayZ[i]; + return not_found; + } + template <typename T> + const Type *lsearch (const T &x, const Type *not_found = nullptr) const + { + unsigned int count = length; + for (unsigned int i = 0; i < count; i++) + if (!this->arrayZ[i].cmp (x)) + return &this->arrayZ[i]; + return not_found; + } + + hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*)) + { + if (likely (length)) + ::qsort (arrayZ, length, this->item_size, cmp_); + return hb_sorted_array_t<Type> (*this); + } + hb_sorted_array_t<Type> qsort () + { + if (likely (length)) + ::qsort (arrayZ, length, this->item_size, Type::cmp); + return hb_sorted_array_t<Type> (*this); + } + void qsort (unsigned int start, unsigned int end) + { + end = MIN (end, length); + assert (start <= end); + if (likely (start < end)) + ::qsort (arrayZ + start, end - start, this->item_size, Type::cmp); + } + + /* + * Other methods. + */ + + unsigned int get_size () const { return length * this->item_size; } + + hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const + { + if (!start_offset && !seg_count) + return *this; + + unsigned int count = length; + if (unlikely (start_offset > count)) + count = 0; + else + count -= start_offset; + if (seg_count) + count = *seg_count = MIN (count, *seg_count); + return hb_array_t<Type> (arrayZ + start_offset, count); + } + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const + { return sub_array (start_offset, &seg_count); } + + /* Only call if you allocated the underlying array using malloc() or similar. */ + void free () + { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; } + + template <typename hb_sanitize_context_t> + bool sanitize (hb_sanitize_context_t *c) const + { return c->check_array (arrayZ, length); } + + /* + * Members + */ + + public: + Type *arrayZ; + unsigned int length; +}; +template <typename T> inline hb_array_t<T> +hb_array (T *array, unsigned int length) +{ return hb_array_t<T> (array, length); } +template <typename T, unsigned int length_> inline hb_array_t<T> +hb_array (T (&array_)[length_]) +{ return hb_array_t<T> (array_); } + + +enum hb_bfind_not_found_t +{ + HB_BFIND_NOT_FOUND_DONT_STORE, + HB_BFIND_NOT_FOUND_STORE, + HB_BFIND_NOT_FOUND_STORE_CLOSEST, +}; + +template <typename Type> +struct hb_sorted_array_t : + hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>, + hb_array_t<Type>, + hb_iter_mixin_t<hb_sorted_array_t<Type>, Type> +{ + hb_sorted_array_t () : hb_array_t<Type> () {} + hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {} + hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {} + template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {} + + hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const + { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); } + hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const + { return sub_array (start_offset, &seg_count); } + + template <typename T> + Type *bsearch (const T &x, Type *not_found = nullptr) + { + unsigned int i; + return bfind (x, &i) ? &this->arrayZ[i] : not_found; + } + template <typename T> + const Type *bsearch (const T &x, const Type *not_found = nullptr) const + { + unsigned int i; + return bfind (x, &i) ? &this->arrayZ[i] : not_found; + } + template <typename T> + bool bfind (const T &x, unsigned int *i = nullptr, + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { + int min = 0, max = (int) this->length - 1; + const Type *array = this->arrayZ; + while (min <= max) + { + int mid = ((unsigned int) min + (unsigned int) max) / 2; + int c = array[mid].cmp (x); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + { + if (i) + *i = mid; + return true; + } + } + if (i) + { + switch (not_found) + { + case HB_BFIND_NOT_FOUND_DONT_STORE: + break; + + case HB_BFIND_NOT_FOUND_STORE: + *i = to_store; + break; + + case HB_BFIND_NOT_FOUND_STORE_CLOSEST: + if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0)) + max++; + *i = max; + break; + } + } + return false; + } +}; +template <typename T> inline hb_sorted_array_t<T> +hb_sorted_array (T *array, unsigned int length) +{ return hb_sorted_array_t<T> (array, length); } +template <typename T, unsigned int length_> inline hb_sorted_array_t<T> +hb_sorted_array (T (&array_)[length_]) +{ return hb_sorted_array_t<T> (array_); } + + +typedef hb_array_t<const char> hb_bytes_t; +typedef hb_array_t<const unsigned char> hb_ubytes_t; + + +#endif /* HB_ARRAY_HH */ diff --git a/src/hb-atomic-private.hh b/src/hb-atomic-private.hh deleted file mode 100644 index 12caaca..0000000 --- a/src/hb-atomic-private.hh +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright © 2007 Chris Wilson - * Copyright © 2009,2010 Red Hat, Inc. - * 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. - * - * Contributor(s): - * Chris Wilson <chris@chris-wilson.co.uk> - * Red Hat Author(s): Behdad Esfahbod - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_ATOMIC_PRIVATE_HH -#define HB_ATOMIC_PRIVATE_HH - -#include "hb-private.hh" - - -/* atomic_int */ - -/* We need external help for these */ - -#if defined(hb_atomic_int_impl_add) \ - && defined(hb_atomic_ptr_impl_get) \ - && defined(hb_atomic_ptr_impl_cmpexch) - -/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */ - - -#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) - -#include <windows.h> - -/* MinGW has a convoluted history of supporting MemoryBarrier - * properly. As such, define a function to wrap the whole - * thing. */ -static inline void _HBMemoryBarrier (void) { -#if !defined(MemoryBarrier) - long dummy = 0; - InterlockedExchange (&dummy, 1); -#else - MemoryBarrier (); -#endif -} - -typedef LONG hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) - -#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) - - -#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) - -typedef int hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V)) - -#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) - - -#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) - -#include <atomic.h> -#include <mbarrier.h> - -typedef unsigned int hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V)) - -#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false) - - -#elif !defined(HB_NO_MT) && defined(__APPLE__) - -#include <libkern/OSAtomic.h> -#ifdef __MAC_OS_X_MIN_REQUIRED -#include <AvailabilityMacros.h> -#elif defined(__IPHONE_OS_MIN_REQUIRED) -#include <Availability.h> -#endif - - -typedef int32_t hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) - -#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P)) -#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) -#else -#if __ppc64__ || __x86_64__ || __aarch64__ -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P)) -#else -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P)) -#endif -#endif - - -#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__) - -#include <builtins.h> - - -static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) { - __lwsync(); - int result = __fetch_and_add(AI, V); - __isync(); - return result; -} -static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) { - __sync(); - int result = __compare_and_swaplp (P, &O, N); - __sync(); - return result; -} - -typedef int hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add (&(AI), (V)) - -#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N)) - -#elif !defined(HB_NO_MT) - -#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ - -typedef volatile int hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) - -#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false) - - -#else /* HB_NO_MT */ - -typedef int hb_atomic_int_impl_t; -#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) - -#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) - - -#endif - - -#define HB_ATOMIC_INT_INIT(V) {V} - -struct hb_atomic_int_t -{ - hb_atomic_int_impl_t v; - - inline void set_unsafe (int v_) { v = v_; } - inline int get_unsafe (void) const { return v; } - inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), 1); } - inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); } -}; - - -#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P) -#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N)) - - -#endif /* HB_ATOMIC_PRIVATE_HH */ diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh new file mode 100644 index 0000000..9321932 --- /dev/null +++ b/src/hb-atomic.hh @@ -0,0 +1,300 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * 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. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_ATOMIC_HH +#define HB_ATOMIC_HH + +#include "hb.hh" + + +/* + * Atomic integers and pointers. + */ + + +/* We need external help for these */ + +#if defined(hb_atomic_int_impl_add) \ + && defined(hb_atomic_ptr_impl_get) \ + && defined(hb_atomic_ptr_impl_cmpexch) + +/* Defined externally, i.e. in config.h. */ + + +#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE) + +/* C++11-style GCC primitives. */ + +#define _hb_memory_barrier() __sync_synchronize () + +#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL) +#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED) +#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE) +#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED) +#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE) + +#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED) +#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED) +#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE) +static inline bool +_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) +{ + const void *O = O_; // Need lvalue + return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED); +} +#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) + +#elif !defined(HB_NO_MT) && __cplusplus >= 201103L + +/* C++11 atomics. */ + +#include <atomic> + +#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel) +#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) +#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) + +#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) +#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release)) +#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire)) + +#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed)) +#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire)) +static inline bool +_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) +{ + const void *O = O_; // Need lvalue + return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed); +} +#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) + + +#elif !defined(HB_NO_MT) && defined(_WIN32) + +#include <windows.h> + +static inline void _hb_memory_barrier () +{ +#if !defined(MemoryBarrier) + /* MinGW has a convoluted history of supporting MemoryBarrier. */ + LONG dummy = 0; + InterlockedExchange (&dummy, 1); +#else + MemoryBarrier (); +#endif +} +#define _hb_memory_barrier() _hb_memory_barrier () + +#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V)) +static_assert ((sizeof (LONG) == sizeof (int)), ""); + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O)) + + +#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +#define _hb_memory_barrier() __sync_synchronize () + +#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V)) + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) + + +#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) + +#include <atomic.h> +#include <mbarrier.h> + +#define _hb_memory_r_barrier() __machine_r_barrier () +#define _hb_memory_w_barrier() __machine_w_barrier () +#define _hb_memory_barrier() __machine_rw_barrier () + +static inline int _hb_fetch_and_add (int *AI, int V) +{ + _hb_memory_w_barrier (); + int result = atomic_add_int_nv ((uint_t *) AI, V) - V; + _hb_memory_r_barrier (); + return result; +} +static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N) +{ + _hb_memory_w_barrier (); + bool result = atomic_cas_ptr (P, O, N) == O; + _hb_memory_r_barrier (); + return result; +} + +#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V)) + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N)) + + +#elif !defined(HB_NO_MT) && defined(__APPLE__) + +#include <libkern/OSAtomic.h> +#ifdef __MAC_OS_X_MIN_REQUIRED +#include <AvailabilityMacros.h> +#elif defined(__IPHONE_OS_MIN_REQUIRED) +#include <Availability.h> +#endif + +#define _hb_memory_barrier() OSMemoryBarrier () + +#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V)) + +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P)) +#else +#if __ppc64__ || __x86_64__ || __aarch64__ +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) +#else +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) +#endif +#endif + + +#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__) + +#include <builtins.h> + +#define _hb_memory_barrier() __lwsync () + +static inline int _hb_fetch_and_add (int *AI, int V) +{ + _hb_memory_barrier (); + int result = __fetch_and_add (AI, V); + _hb_memory_barrier (); + return result; +} +static inline bool _hb_compare_and_swaplp (long *P, long O, long N) +{ + _hb_memory_barrier (); + bool result = __compare_and_swaplp (P, &O, N); + _hb_memory_barrier (); + return result; +} + +#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V)) + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N)) +static_assert ((sizeof (long) == sizeof (void *)), ""); + + +#elif !defined(HB_NO_MT) + +#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ + +#define _hb_memory_barrier() + +#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) + + +#else /* HB_NO_MT */ + +#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) + +#define _hb_memory_barrier() + +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) + + +#endif + + +#ifndef _hb_memory_r_barrier +#define _hb_memory_r_barrier() _hb_memory_barrier () +#endif +#ifndef _hb_memory_w_barrier +#define _hb_memory_w_barrier() _hb_memory_barrier () +#endif +#ifndef hb_atomic_int_impl_set_relaxed +#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V)) +#endif +#ifndef hb_atomic_int_impl_get_relaxed +#define hb_atomic_int_impl_get_relaxed(AI) (*(AI)) +#endif + +#ifndef hb_atomic_ptr_impl_set_relaxed +#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V)) +#endif +#ifndef hb_atomic_ptr_impl_get_relaxed +#define hb_atomic_ptr_impl_get_relaxed(P) (*(P)) +#endif +#ifndef hb_atomic_int_impl_set +inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } +#endif +#ifndef hb_atomic_int_impl_get +inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } +#endif +#ifndef hb_atomic_ptr_impl_get +inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } +#endif + + +#define HB_ATOMIC_INT_INIT(V) {V} +struct hb_atomic_int_t +{ + void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + void set (int v_) { hb_atomic_int_impl_set (&v, v_); } + int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } + int get () const { return hb_atomic_int_impl_get (&v); } + int inc () { return hb_atomic_int_impl_add (&v, 1); } + int dec () { return hb_atomic_int_impl_add (&v, -1); } + + int v; +}; + + +#define HB_ATOMIC_PTR_INIT(V) {V} +template <typename P> +struct hb_atomic_ptr_t +{ + typedef typename hb_remove_pointer (P) T; + + void init (T* v_ = nullptr) { set_relaxed (v_); } + void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } + T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } + T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } + bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } + + T * operator -> () const { return get (); } + template <typename C> operator C * () const { return get (); } + + T *v; +}; + + +#endif /* HB_ATOMIC_HH */ diff --git a/src/hb-blob.cc b/src/hb-blob.cc index c138648..bcf381e 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -25,14 +25,20 @@ * Red Hat Author(s): Behdad Esfahbod */ -/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ + +/* https://github.com/harfbuzz/harfbuzz/issues/1308 + * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html + * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html + */ #ifndef _POSIX_C_SOURCE +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" #define _POSIX_C_SOURCE 200809L +#pragma GCC diagnostic pop #endif -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-blob-private.hh" +#include "hb.hh" +#include "hb-blob.hh" #ifdef HAVE_SYS_MMAN_H #ifdef HAVE_UNISTD_H @@ -47,6 +53,19 @@ /** + * SECTION: hb-blob + * @title: hb-blob + * @short_description: Binary data containers + * @include: hb.h + * + * Blobs wrap a chunk of binary data to handle lifecycle management of data + * while it is passed between client and HarfBuzz. Blobs are primarily used + * to create font faces, but also to access font face tables, as well as + * pass around other binary data. + **/ + + +/** * hb_blob_create: (skip) * @data: Pointer to blob data. * @length: Length of @data in bytes. @@ -130,7 +149,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent, { hb_blob_t *blob; - if (!length || offset >= parent->length) + if (!length || !parent || offset >= parent->length) return hb_blob_get_empty (); hb_blob_make_immutable (parent); @@ -181,22 +200,9 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob) * Since: 0.9.2 **/ hb_blob_t * -hb_blob_get_empty (void) +hb_blob_get_empty () { - static const hb_blob_t _hb_blob_nil = { - HB_OBJECT_HEADER_STATIC, - - true, /* immutable */ - - nullptr, /* data */ - 0, /* length */ - HB_MEMORY_MODE_READONLY, /* mode */ - - nullptr, /* user_data */ - nullptr /* destroy */ - }; - - return const_cast<hb_blob_t *> (&_hb_blob_nil); + return const_cast<hb_blob_t *> (&Null(hb_blob_t)); } /** @@ -291,10 +297,10 @@ hb_blob_get_user_data (hb_blob_t *blob, void hb_blob_make_immutable (hb_blob_t *blob) { - if (hb_object_is_inert (blob)) + if (hb_object_is_immutable (blob)) return; - blob->immutable = true; + hb_object_make_immutable (blob); } /** @@ -310,7 +316,7 @@ hb_blob_make_immutable (hb_blob_t *blob) hb_bool_t hb_blob_is_immutable (hb_blob_t *blob) { - return blob->immutable; + return hb_object_is_immutable (blob); } @@ -384,7 +390,7 @@ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) bool -hb_blob_t::try_make_writable_inplace_unix (void) +hb_blob_t::try_make_writable_inplace_unix () { #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) uintptr_t pagesize = -1, mask, length; @@ -427,7 +433,7 @@ hb_blob_t::try_make_writable_inplace_unix (void) } bool -hb_blob_t::try_make_writable_inplace (void) +hb_blob_t::try_make_writable_inplace () { DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n"); @@ -442,9 +448,9 @@ hb_blob_t::try_make_writable_inplace (void) } bool -hb_blob_t::try_make_writable (void) +hb_blob_t::try_make_writable () { - if (this->immutable) + if (hb_object_is_immutable (this)) return false; if (this->mode == HB_MEMORY_MODE_WRITABLE) @@ -487,12 +493,12 @@ hb_blob_t::try_make_writable (void) # include <fcntl.h> #endif -#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _WIN32 # include <windows.h> -#endif - -#ifndef _O_BINARY -# define _O_BINARY 0 +#else +# ifndef O_BINARY +# define O_BINARY 0 +# endif #endif #ifndef MAP_NORESERVE @@ -503,25 +509,28 @@ struct hb_mapped_file_t { char *contents; unsigned long length; -#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _WIN32 HANDLE mapping; #endif }; +#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP) static void -_hb_mapped_file_destroy (hb_mapped_file_t *file) +_hb_mapped_file_destroy (void *file_) { + hb_mapped_file_t *file = (hb_mapped_file_t *) file_; #ifdef HAVE_MMAP munmap (file->contents, file->length); -#elif defined(_WIN32) || defined(__CYGWIN__) +#elif defined(_WIN32) UnmapViewOfFile (file->contents); CloseHandle (file->mapping); #else - free (file->contents); + assert (0); // If we don't have mmap we shouldn't reach here #endif free (file); } +#endif /** * hb_blob_create_from_file: @@ -534,77 +543,136 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file) hb_blob_t * hb_blob_create_from_file (const char *file_name) { - // Adopted from glib's gmappedfile.c with Matthias Clasen and - // Allison Lortie permission but changed a lot to suit our need. - bool writable = false; - hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE; + /* Adopted from glib's gmappedfile.c with Matthias Clasen and + Allison Lortie permission but changed a lot to suit our need. */ +#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); if (unlikely (!file)) return hb_blob_get_empty (); -#ifdef HAVE_MMAP - int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0); -# define CLOSE close + int fd = open (file_name, O_RDONLY | O_BINARY, 0); if (unlikely (fd == -1)) goto fail_without_close; struct stat st; if (unlikely (fstat (fd, &st) == -1)) goto fail; - // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142 - if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail; - file->length = (unsigned long) st.st_size; - file->contents = (char *) mmap (nullptr, file->length, - writable ? PROT_READ|PROT_WRITE : PROT_READ, + file->contents = (char *) mmap (nullptr, file->length, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); if (unlikely (file->contents == MAP_FAILED)) goto fail; -#elif defined(_WIN32) || defined(__CYGWIN__) - HANDLE fd = CreateFile (file_name, - writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); -# define CLOSE CloseHandle + close (fd); - if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; + return hb_blob_create (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); - file->length = (unsigned long) GetFileSize (fd, nullptr); - file->mapping = CreateFileMapping (fd, nullptr, - writable ? PAGE_WRITECOPY : PAGE_READONLY, - 0, 0, nullptr); - if (unlikely (file->mapping == nullptr)) goto fail; +fail: + close (fd); +fail_without_close: + free (file); - file->contents = (char *) MapViewOfFile (file->mapping, - writable ? FILE_MAP_COPY : FILE_MAP_READ, - 0, 0, 0); - if (unlikely (file->contents == nullptr)) goto fail; +#elif defined(_WIN32) && !defined(HB_NO_MMAP) + hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return hb_blob_get_empty (); + HANDLE fd; + unsigned int size = strlen (file_name) + 1; + wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size); + if (unlikely (wchar_file_name == nullptr)) goto fail_without_close; + mbstowcs (wchar_file_name, file_name, size); +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + { + CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; + ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; + ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; + ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; + ceparams.lpSecurityAttributes = nullptr; + ceparams.hTemplateFile = nullptr; + fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, &ceparams); + } #else - mm = HB_MEMORY_MODE_WRITABLE; - - FILE *fd = fopen (file_name, "rb"); -# define CLOSE fclose - if (unlikely (!fd)) goto fail_without_close; + fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + nullptr); +#endif + free (wchar_file_name); - fseek (fd, 0, SEEK_END); - file->length = ftell (fd); - rewind (fd); - file->contents = (char *) malloc (file->length); - if (unlikely (!file->contents)) goto fail; + if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; - if (unlikely (fread (file->contents, 1, file->length, fd) != file->length)) - goto fail; +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + { + LARGE_INTEGER length; + GetFileSizeEx (fd, &length); + file->length = length.LowPart; + file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); + } +#else + file->length = (unsigned long) GetFileSize (fd, nullptr); + file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); +#endif + if (unlikely (file->mapping == nullptr)) goto fail; +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); +#else + file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); #endif + if (unlikely (file->contents == nullptr)) goto fail; - CLOSE (fd); - return hb_blob_create (file->contents, file->length, mm, (void *) file, + CloseHandle (fd); + return hb_blob_create (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, (hb_destroy_func_t) _hb_mapped_file_destroy); fail: - CLOSE (fd); -#undef CLOSE + CloseHandle (fd); fail_without_close: free (file); + +#endif + + /* The following tries to read a file without knowing its size beforehand + It's used as a fallback for systems without mmap or to read from pipes */ + unsigned long len = 0, allocated = BUFSIZ * 16; + char *data = (char *) malloc (allocated); + if (unlikely (data == nullptr)) return hb_blob_get_empty (); + + FILE *fp = fopen (file_name, "rb"); + if (unlikely (fp == nullptr)) goto fread_fail_without_close; + + while (!feof (fp)) + { + if (allocated - len < BUFSIZ) + { + allocated *= 2; + /* Don't allocate and go more than ~536MB, our mmap reader still + can cover files like that but lets limit our fallback reader */ + if (unlikely (allocated > (2 << 28))) goto fread_fail; + char *new_data = (char *) realloc (data, allocated); + if (unlikely (new_data == nullptr)) goto fread_fail; + data = new_data; + } + + unsigned long addition = fread (data + len, 1, allocated - len, fp); + + int err = ferror (fp); +#ifdef EINTR // armcc doesn't have it + if (unlikely (err == EINTR)) continue; +#endif + if (unlikely (err)) goto fread_fail; + + len += addition; + } + + return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, + (hb_destroy_func_t) free); + +fread_fail: + fclose (fp); +fread_fail_without_close: + free (data); return hb_blob_get_empty (); } diff --git a/src/hb-blob-private.hh b/src/hb-blob.hh index b72fa72..4ea13f8 100644 --- a/src/hb-blob-private.hh +++ b/src/hb-blob.hh @@ -26,12 +26,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BLOB_PRIVATE_HH -#define HB_BLOB_PRIVATE_HH +#ifndef HB_BLOB_HH +#define HB_BLOB_HH -#include "hb-private.hh" - -#include "hb-object-private.hh" +#include "hb.hh" /* @@ -40,12 +38,9 @@ struct hb_blob_t { - inline void fini_shallow (void) - { - destroy_user_data (); - } + void fini_shallow () { destroy_user_data (); } - inline void destroy_user_data (void) + void destroy_user_data () { if (destroy) { @@ -55,26 +50,20 @@ struct hb_blob_t } } - HB_INTERNAL bool try_make_writable (void); - HB_INTERNAL bool try_make_writable_inplace (void); - HB_INTERNAL bool try_make_writable_inplace_unix (void); - - inline void lock (void) - { - hb_blob_make_immutable (this); - } + HB_INTERNAL bool try_make_writable (); + HB_INTERNAL bool try_make_writable_inplace (); + HB_INTERNAL bool try_make_writable_inplace_unix (); template <typename Type> - inline const Type* as (void) const + const Type* as () const { - return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data); + return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast<const Type *> (data); } + hb_bytes_t as_bytes () const + { return hb_bytes_t (data, length); } public: hb_object_header_t header; - ASSERT_POD (); - - bool immutable; const char *data; unsigned int length; @@ -85,4 +74,28 @@ struct hb_blob_t }; -#endif /* HB_BLOB_PRIVATE_HH */ +/* + * hb_blob_ptr_t + */ + +template <typename P> +struct hb_blob_ptr_t +{ + typedef typename hb_remove_pointer (P) T; + + hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {} + hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; } + const T * operator -> () const { return get (); } + const T & operator * () const { return *get (); } + template <typename C> operator const C * () const { return get (); } + operator const char * () const { return (const char *) get (); } + const T * get () const { return b->as<T> (); } + hb_blob_t * get_blob () const { return b.get_raw (); } + unsigned int get_length () const { return b.get ()->length; } + void destroy () { hb_blob_destroy (b.get ()); b = nullptr; } + + hb_nonnull_ptr_t<hb_blob_t> b; +}; + + +#endif /* HB_BLOB_HH */ diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh index 380f3c5..1f9e2e9 100644 --- a/src/hb-buffer-deserialize-json.hh +++ b/src/hb-buffer-deserialize-json.hh @@ -29,7 +29,7 @@ #ifndef HB_BUFFER_DESERIALIZE_JSON_HH #define HB_BUFFER_DESERIALIZE_JSON_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-buffer-deserialize-json.hh" diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl index ec9bc7c..f3abb02 100644 --- a/src/hb-buffer-deserialize-json.rl +++ b/src/hb-buffer-deserialize-json.rl @@ -27,7 +27,7 @@ #ifndef HB_BUFFER_DESERIALIZE_JSON_HH #define HB_BUFFER_DESERIALIZE_JSON_HH -#include "hb-private.hh" +#include "hb.hh" %%{ diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh index 5bca369..67f0a12 100644 --- a/src/hb-buffer-deserialize-text.hh +++ b/src/hb-buffer-deserialize-text.hh @@ -29,7 +29,7 @@ #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH #define HB_BUFFER_DESERIALIZE_TEXT_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-buffer-deserialize-text.hh" diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl index 1d90979..6268a6c 100644 --- a/src/hb-buffer-deserialize-text.rl +++ b/src/hb-buffer-deserialize-text.rl @@ -27,7 +27,7 @@ #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH #define HB_BUFFER_DESERIALIZE_TEXT_HH -#include "hb-private.hh" +#include "hb.hh" %%{ diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc index 1147194..6e265e8 100644 --- a/src/hb-buffer-serialize.cc +++ b/src/hb-buffer-serialize.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-buffer-private.hh" +#include "hb-buffer.hh" static const char *serialize_formats[] = { @@ -44,7 +44,7 @@ static const char *serialize_formats[] = { * Since: 0.9.7 **/ const char ** -hb_buffer_serialize_list_formats (void) +hb_buffer_serialize_list_formats () { return serialize_formats; } @@ -58,7 +58,7 @@ hb_buffer_serialize_list_formats (void) * @str is a valid buffer serialization format, use * hb_buffer_serialize_list_formats() to get the list of supported formats. * - * Return value: + * Return value: * The parsed #hb_buffer_serialize_format_t. * * Since: 0.9.7 @@ -246,7 +246,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) { - if (info[i].mask &HB_GLYPH_FLAG_DEFINED) + if (info[i].mask & HB_GLYPH_FLAG_DEFINED) p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED)); } @@ -319,7 +319,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, * ## json * TODO. * - * Return value: + * Return value: * The number of serialized items. * * Since: 0.9.7 @@ -425,14 +425,14 @@ parse_int (const char *pp, const char *end, int32_t *pv) * hb_buffer_deserialize_glyphs: * @buffer: an #hb_buffer_t buffer. * @buf: (array length=buf_len): - * @buf_len: + * @buf_len: * @end_ptr: (out): - * @font: - * @format: + * @font: + * @format: + * * - * * - * Return value: + * Return value: * * Since: 0.9.7 **/ @@ -440,8 +440,8 @@ hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, const char *buf, int buf_len, /* -1 means nul-terminated */ - const char **end_ptr, /* May be nullptr */ - hb_font_t *font, /* May be nullptr */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ hb_buffer_serialize_format_t format) { const char *end; diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index 7b95aea..2dc02e9 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -27,20 +27,21 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-buffer-private.hh" -#include "hb-utf-private.hh" +#include "hb-buffer.hh" +#include "hb-utf.hh" /** * SECTION: hb-buffer - * @title: Buffers + * @title: hb-buffer * @short_description: Input and output buffers * @include: hb.h * * Buffers serve dual role in HarfBuzz; they hold the input characters that are - * passed hb_shape(), and after shaping they hold the output glyphs. + * passed to hb_shape(), and after shaping they hold the output glyphs. **/ + /** * hb_segment_properties_equal: * @a: first #hb_segment_properties_t to compare. @@ -124,14 +125,14 @@ hb_buffer_t::enlarge (unsigned int size) hb_glyph_info_t *new_info = nullptr; bool separate_out = out_info != info; - if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) + if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0])))) goto done; while (size >= new_allocated) new_allocated += (new_allocated >> 1) + 32; static_assert ((sizeof (info[0]) == sizeof (pos[0])), ""); - if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0])))) + if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0])))) goto done; new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0])); @@ -182,7 +183,11 @@ hb_buffer_t::shift_forward (unsigned int count) if (idx + count > len) { /* Under memory failure we might expose this area. At least - * clean it up. Oh well... */ + * clean it up. Oh well... + * + * Ideally, we should at least set Default_Ignorable bits on + * these, as well as consistent cluster values. But the former + * is layering violation... */ memset (info + len, 0, (idx + count - len) * sizeof (info[0])); } len += count; @@ -210,23 +215,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size) /* HarfBuzz-Internal API */ void -hb_buffer_t::reset (void) +hb_buffer_t::reset () { - if (unlikely (hb_object_is_inert (this))) + if (unlikely (hb_object_is_immutable (this))) return; hb_unicode_funcs_destroy (unicode); - unicode = hb_unicode_funcs_get_default (); + unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); flags = HB_BUFFER_FLAG_DEFAULT; replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + invisible = 0; clear (); } void -hb_buffer_t::clear (void) +hb_buffer_t::clear () { - if (unlikely (hb_object_is_inert (this))) + if (unlikely (hb_object_is_immutable (this))) return; hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; @@ -281,9 +287,9 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) void -hb_buffer_t::remove_output (void) +hb_buffer_t::remove_output () { - if (unlikely (hb_object_is_inert (this))) + if (unlikely (hb_object_is_immutable (this))) return; have_output = false; @@ -294,9 +300,9 @@ hb_buffer_t::remove_output (void) } void -hb_buffer_t::clear_output (void) +hb_buffer_t::clear_output () { - if (unlikely (hb_object_is_inert (this))) + if (unlikely (hb_object_is_immutable (this))) return; have_output = true; @@ -307,9 +313,9 @@ hb_buffer_t::clear_output (void) } void -hb_buffer_t::clear_positions (void) +hb_buffer_t::clear_positions () { - if (unlikely (hb_object_is_inert (this))) + if (unlikely (hb_object_is_immutable (this))) return; have_output = false; @@ -322,7 +328,7 @@ hb_buffer_t::clear_positions (void) } void -hb_buffer_t::swap_buffers (void) +hb_buffer_t::swap_buffers () { if (unlikely (!successful)) return; @@ -354,6 +360,8 @@ hb_buffer_t::replace_glyphs (unsigned int num_in, { if (unlikely (!make_room_for (num_in, num_out))) return; + assert (idx + num_in <= len); + merge_clusters (idx, idx + num_in); hb_glyph_info_t orig_info = info[idx]; @@ -369,37 +377,6 @@ hb_buffer_t::replace_glyphs (unsigned int num_in, out_len += num_out; } -void -hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = info[idx]; - out_info[out_len].codepoint = glyph_index; - - out_len++; -} - -void -hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = glyph_info; - - out_len++; -} - -void -hb_buffer_t::copy_glyph (void) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = info[idx]; - - out_len++; -} - bool hb_buffer_t::move_to (unsigned int i) { @@ -429,8 +406,14 @@ hb_buffer_t::move_to (unsigned int i) unsigned int count = out_len - i; /* This will blow in our face if memory allocation fails later - * in this same lookup... */ - if (unlikely (idx < count && !shift_forward (count + 32))) return false; + * in this same lookup... + * + * We used to shift with extra 32 items, instead of the 0 below. + * But that would leave empty slots in the buffer in case of allocation + * failures. Setting to zero for now to avoid other problems (see + * comments in shift_forward(). This can cause O(N^2) behavior more + * severely than adding 32 empty slots can... */ + if (unlikely (idx < count && !shift_forward (count + 0))) return false; assert (idx >= count); @@ -442,19 +425,6 @@ hb_buffer_t::move_to (unsigned int i) return true; } -void -hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) -{ - if (unlikely (out_info != info || out_len != idx)) { - if (unlikely (!make_room_for (1, 1))) return; - out_info[out_len] = info[idx]; - } - out_info[out_len].codepoint = glyph_index; - - idx++; - out_len++; -} - void hb_buffer_t::set_masks (hb_mask_t value, @@ -510,7 +480,7 @@ hb_buffer_t::reverse_range (unsigned int start, } void -hb_buffer_t::reverse (void) +hb_buffer_t::reverse () { if (unlikely (!len)) return; @@ -519,7 +489,7 @@ hb_buffer_t::reverse (void) } void -hb_buffer_t::reverse_clusters (void) +hb_buffer_t::reverse_clusters () { unsigned int i, start, count, last_cluster; @@ -666,7 +636,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en } void -hb_buffer_t::guess_segment_properties (void) +hb_buffer_t::guess_segment_properties () { assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); @@ -701,6 +671,29 @@ hb_buffer_t::guess_segment_properties (void) /* Public API */ +DEFINE_NULL_INSTANCE (hb_buffer_t) = +{ + HB_OBJECT_HEADER_STATIC, + + const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t), + HB_BUFFER_FLAG_DEFAULT, + HB_BUFFER_CLUSTER_LEVEL_DEFAULT, + HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, + 0, /* invisible */ + HB_BUFFER_SCRATCH_FLAG_DEFAULT, + HB_BUFFER_MAX_LEN_DEFAULT, + HB_BUFFER_MAX_OPS_DEFAULT, + + HB_BUFFER_CONTENT_TYPE_INVALID, + HB_SEGMENT_PROPERTIES_DEFAULT, + false, /* successful */ + true, /* have_output */ + true /* have_positions */ + + /* Zero is good enough for everything else. */ +}; + + /** * hb_buffer_create: (Xconstructor) * @@ -716,7 +709,7 @@ hb_buffer_t::guess_segment_properties (void) * Since: 0.9.2 **/ hb_buffer_t * -hb_buffer_create (void) +hb_buffer_create () { hb_buffer_t *buffer; @@ -734,36 +727,16 @@ hb_buffer_create (void) /** * hb_buffer_get_empty: * - * + * * * Return value: (transfer full): * * Since: 0.9.2 **/ hb_buffer_t * -hb_buffer_get_empty (void) +hb_buffer_get_empty () { - static const hb_buffer_t _hb_buffer_nil = { - HB_OBJECT_HEADER_STATIC, - - const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), - HB_BUFFER_FLAG_DEFAULT, - HB_BUFFER_CLUSTER_LEVEL_DEFAULT, - HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, - HB_BUFFER_SCRATCH_FLAG_DEFAULT, - HB_BUFFER_MAX_LEN_DEFAULT, - HB_BUFFER_MAX_OPS_DEFAULT, - - HB_BUFFER_CONTENT_TYPE_INVALID, - HB_SEGMENT_PROPERTIES_DEFAULT, - false, /* successful */ - true, /* have_output */ - true /* have_positions */ - - /* Zero is good enough for everything else. */ - }; - - return const_cast<hb_buffer_t *> (&_hb_buffer_nil); + return const_cast<hb_buffer_t *> (&Null(hb_buffer_t)); } /** @@ -812,14 +785,14 @@ hb_buffer_destroy (hb_buffer_t *buffer) /** * hb_buffer_set_user_data: (skip) * @buffer: an #hb_buffer_t. - * @key: - * @data: - * @destroy: - * @replace: + * @key: + * @data: + * @destroy: + * @replace: * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -836,11 +809,11 @@ hb_buffer_set_user_data (hb_buffer_t *buffer, /** * hb_buffer_get_user_data: (skip) * @buffer: an #hb_buffer_t. - * @key: + * @key: * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -890,9 +863,9 @@ hb_buffer_get_content_type (hb_buffer_t *buffer) /** * hb_buffer_set_unicode_funcs: * @buffer: an #hb_buffer_t. - * @unicode_funcs: + * @unicode_funcs: + * * - * * * Since: 0.9.2 **/ @@ -900,13 +873,12 @@ void hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, hb_unicode_funcs_t *unicode_funcs) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; if (!unicode_funcs) unicode_funcs = hb_unicode_funcs_get_default (); - hb_unicode_funcs_reference (unicode_funcs); hb_unicode_funcs_destroy (buffer->unicode); buffer->unicode = unicode_funcs; @@ -916,9 +888,9 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, * hb_buffer_get_unicode_funcs: * @buffer: an #hb_buffer_t. * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -948,7 +920,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->props.direction = direction; @@ -992,7 +964,7 @@ void hb_buffer_set_script (hb_buffer_t *buffer, hb_script_t script) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->props.script = script; @@ -1027,7 +999,7 @@ hb_buffer_get_script (hb_buffer_t *buffer) * are orthogonal to the scripts, and though they are related, they are * different concepts and should not be confused with each other. * - * Use hb_language_from_string() to convert from ISO 639 language codes to + * Use hb_language_from_string() to convert from BCP 47 language tags to * #hb_language_t. * * Since: 0.9.2 @@ -1036,7 +1008,7 @@ void hb_buffer_set_language (hb_buffer_t *buffer, hb_language_t language) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->props.language = language; @@ -1074,7 +1046,7 @@ void hb_buffer_set_segment_properties (hb_buffer_t *buffer, const hb_segment_properties_t *props) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->props = *props; @@ -1110,7 +1082,7 @@ void hb_buffer_set_flags (hb_buffer_t *buffer, hb_buffer_flags_t flags) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->flags = flags; @@ -1122,7 +1094,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer, * * See hb_buffer_set_flags(). * - * Return value: + * Return value: * The @buffer flags. * * Since: 0.9.7 @@ -1136,9 +1108,9 @@ hb_buffer_get_flags (hb_buffer_t *buffer) /** * hb_buffer_set_cluster_level: * @buffer: an #hb_buffer_t. - * @cluster_level: + * @cluster_level: + * * - * * * Since: 0.9.42 **/ @@ -1146,7 +1118,7 @@ void hb_buffer_set_cluster_level (hb_buffer_t *buffer, hb_buffer_cluster_level_t cluster_level) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->cluster_level = cluster_level; @@ -1156,9 +1128,9 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer, * hb_buffer_get_cluster_level: * @buffer: an #hb_buffer_t. * - * * - * Return value: + * + * Return value: * * Since: 0.9.42 **/ @@ -1185,7 +1157,7 @@ void hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, hb_codepoint_t replacement) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; buffer->replacement = replacement; @@ -1197,7 +1169,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, * * See hb_buffer_set_replacement_codepoint(). * - * Return value: + * Return value: * The @buffer replacement #hb_codepoint_t. * * Since: 0.9.31 @@ -1210,6 +1182,46 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) /** + * hb_buffer_set_invisible_glyph: + * @buffer: an #hb_buffer_t. + * @invisible: the invisible #hb_codepoint_t + * + * Sets the #hb_codepoint_t that replaces invisible characters in + * the shaping result. If set to zero (default), the glyph for the + * U+0020 SPACE character is used. Otherwise, this value is used + * verbatim. + * + * Since: 2.0.0 + **/ +void +hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, + hb_codepoint_t invisible) +{ + if (unlikely (hb_object_is_immutable (buffer))) + return; + + buffer->invisible = invisible; +} + +/** + * hb_buffer_get_invisible_glyph: + * @buffer: an #hb_buffer_t. + * + * See hb_buffer_set_invisible_glyph(). + * + * Return value: + * The @buffer invisible #hb_codepoint_t. + * + * Since: 2.0.0 + **/ +hb_codepoint_t +hb_buffer_get_invisible_glyph (hb_buffer_t *buffer) +{ + return buffer->invisible; +} + + +/** * hb_buffer_reset: * @buffer: an #hb_buffer_t. * @@ -1308,7 +1320,7 @@ hb_buffer_add (hb_buffer_t *buffer, * Similar to hb_buffer_pre_allocate(), but clears any new items added at the * end. * - * Return value: + * Return value: * %true if @buffer memory allocation succeeded, %false otherwise. * * Since: 0.9.2 @@ -1317,7 +1329,7 @@ hb_bool_t hb_buffer_set_length (hb_buffer_t *buffer, unsigned int length) { - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return length == 0; if (!buffer->ensure (length)) @@ -1498,6 +1510,8 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer) * it will be set to the process's default language as returned by * hb_language_get_default(). This may change in the future by * taking buffer script into consideration when choosing a language. + * Note that hb_language_get_default() is NOT threadsafe the first time + * it is called. See documentation for that function for details. * * Since: 0.9.7 **/ @@ -1521,7 +1535,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer, assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); - if (unlikely (hb_object_is_inert (buffer))) + if (unlikely (hb_object_is_immutable (buffer))) return; if (text_length == -1) @@ -1652,7 +1666,7 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer, unsigned int item_offset, int item_length) { - hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length); + hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length); } /** @@ -1713,7 +1727,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, unsigned int item_offset, int item_length) { - hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length); + hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length); } @@ -1886,6 +1900,10 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g /** * hb_buffer_diff: + * @buffer: a buffer. + * @reference: other buffer to compare to. + * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1. + * @position_fuzz: allowed absolute difference in position values. * * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most @@ -1982,7 +2000,7 @@ hb_buffer_diff (hb_buffer_t *buffer, * @user_data: * @destroy: * - * + * * * Since: 1.1.3 **/ diff --git a/src/hb-buffer.h b/src/hb-buffer.h index 8a2d3e8..f989d25 100644 --- a/src/hb-buffer.h +++ b/src/hb-buffer.h @@ -44,7 +44,6 @@ HB_BEGIN_DECLS * hb_glyph_info_t: * @codepoint: either a Unicode code point (before shaping) or a glyph index * (after shaping). - * @mask: * @cluster: the index of the character in the original text that corresponds * to this #hb_glyph_info_t, or whatever the client passes to * hb_buffer_add(). More than one #hb_glyph_info_t can have the same @@ -59,11 +58,13 @@ HB_BEGIN_DECLS * * The #hb_glyph_info_t is the structure that holds information about the * glyphs and their relation to input text. - * */ -typedef struct hb_glyph_info_t { +typedef struct hb_glyph_info_t +{ hb_codepoint_t codepoint; - hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */ + /*< private >*/ + hb_mask_t mask; + /*< public >*/ uint32_t cluster; /*< private >*/ @@ -88,6 +89,9 @@ typedef struct hb_glyph_info_t { * of each line after line-breaking, or limiting * the reshaping to a small piece around the * breaking point only. + * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags. + * + * Since: 1.5.0 */ typedef enum { /*< flags >*/ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, @@ -298,7 +302,15 @@ hb_buffer_set_flags (hb_buffer_t *buffer, HB_EXTERN hb_buffer_flags_t hb_buffer_get_flags (hb_buffer_t *buffer); -/* +/** + * hb_buffer_cluster_level_t: + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into + * monotone order. + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order. + * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values. + * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level, + * equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES. + * * Since: 0.9.42 */ typedef enum { @@ -332,6 +344,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, HB_EXTERN hb_codepoint_t hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer); +HB_EXTERN void +hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, + hb_codepoint_t invisible); + +HB_EXTERN hb_codepoint_t +hb_buffer_get_invisible_glyph (hb_buffer_t *buffer); + HB_EXTERN void hb_buffer_reset (hb_buffer_t *buffer); diff --git a/src/hb-buffer-private.hh b/src/hb-buffer.hh index dd6f1dc..330f88b 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer.hh @@ -27,12 +27,11 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BUFFER_PRIVATE_HH -#define HB_BUFFER_PRIVATE_HH +#ifndef HB_BUFFER_HH +#define HB_BUFFER_HH -#include "hb-private.hh" -#include "hb-object-private.hh" -#include "hb-unicode-private.hh" +#include "hb.hh" +#include "hb-unicode.hh" #ifndef HB_BUFFER_MAX_LEN_FACTOR @@ -84,15 +83,16 @@ HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t); * hb_buffer_t */ -struct hb_buffer_t { +struct hb_buffer_t +{ hb_object_header_t header; - ASSERT_POD (); /* Information about how the text in the buffer should be treated */ hb_unicode_funcs_t *unicode; /* Unicode functions */ hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_cluster_level_t cluster_level; hb_codepoint_t replacement; /* U+FFFD or something else. */ + hb_codepoint_t invisible; /* 0 or something else. */ hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ unsigned int max_len; /* Maximum allowed len. */ int max_ops; /* Maximum allowed operations. */ @@ -119,7 +119,7 @@ struct hb_buffer_t { /* Text before / after the main buffer contents. * Always in Unicode, and ordered outward. * Index 0 is for "pre-context", 1 for "post-context". */ - static const unsigned int CONTEXT_LENGTH = 5; + static constexpr unsigned CONTEXT_LENGTH = 5u; hb_codepoint_t context[2][CONTEXT_LENGTH]; unsigned int context_len[2]; @@ -137,7 +137,9 @@ struct hb_buffer_t { /* Methods */ - inline void allocate_var (unsigned int start, unsigned int count) + bool in_error () const { return !successful; } + + void allocate_var (unsigned int start, unsigned int count) { #ifndef HB_NDEBUG unsigned int end = start + count; @@ -147,7 +149,7 @@ struct hb_buffer_t { allocated_var_bits |= bits; #endif } - inline void deallocate_var (unsigned int start, unsigned int count) + void deallocate_var (unsigned int start, unsigned int count) { #ifndef HB_NDEBUG unsigned int end = start + count; @@ -157,7 +159,7 @@ struct hb_buffer_t { allocated_var_bits &= ~bits; #endif } - inline void assert_var (unsigned int start, unsigned int count) + void assert_var (unsigned int start, unsigned int count) { #ifndef HB_NDEBUG unsigned int end = start + count; @@ -166,67 +168,102 @@ struct hb_buffer_t { assert (bits == (allocated_var_bits & bits)); #endif } - inline void deallocate_var_all (void) + void deallocate_var_all () { #ifndef HB_NDEBUG allocated_var_bits = 0; #endif } - inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } - inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; } + hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } + hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; } - inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } - inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } + hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } + hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } - inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; } - inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; } + hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } + hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } - inline bool has_separate_output (void) const { return info != out_info; } + bool has_separate_output () const { return info != out_info; } - HB_INTERNAL void reset (void); - HB_INTERNAL void clear (void); + HB_INTERNAL void reset (); + HB_INTERNAL void clear (); - inline unsigned int backtrack_len (void) const - { return have_output? out_len : idx; } - inline unsigned int lookahead_len (void) const - { return len - idx; } - inline unsigned int next_serial (void) { return serial++; } + unsigned int backtrack_len () const { return have_output? out_len : idx; } + unsigned int lookahead_len () const { return len - idx; } + unsigned int next_serial () { return serial++; } HB_INTERNAL void add (hb_codepoint_t codepoint, unsigned int cluster); HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info); HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); - HB_INTERNAL void reverse (void); - HB_INTERNAL void reverse_clusters (void); - HB_INTERNAL void guess_segment_properties (void); + HB_INTERNAL void reverse (); + HB_INTERNAL void reverse_clusters (); + HB_INTERNAL void guess_segment_properties (); - HB_INTERNAL void swap_buffers (void); - HB_INTERNAL void remove_output (void); - HB_INTERNAL void clear_output (void); - HB_INTERNAL void clear_positions (void); + HB_INTERNAL void swap_buffers (); + HB_INTERNAL void remove_output (); + HB_INTERNAL void clear_output (); + HB_INTERNAL void clear_positions (); HB_INTERNAL void replace_glyphs (unsigned int num_in, unsigned int num_out, const hb_codepoint_t *glyph_data); - HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index); + void replace_glyph (hb_codepoint_t glyph_index) + { + if (unlikely (out_info != info || out_len != idx)) { + if (unlikely (!make_room_for (1, 1))) return; + out_info[out_len] = info[idx]; + } + out_info[out_len].codepoint = glyph_index; + + idx++; + out_len++; + } /* Makes a copy of the glyph at idx to output and replace glyph_index */ - HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index); - HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info); + hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index) + { + if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t); + + if (unlikely (idx == len && !out_len)) + return Crap(hb_glyph_info_t); + + out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1]; + out_info[out_len].codepoint = glyph_index; + + out_len++; + + return out_info[out_len - 1]; + } + void output_info (const hb_glyph_info_t &glyph_info) + { + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = glyph_info; + + out_len++; + } /* Copies glyph at idx to output but doesn't advance idx */ - HB_INTERNAL void copy_glyph (void); - HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + void copy_glyph () + { + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = info[idx]; + + out_len++; + } /* Copies glyph at idx to output and advance idx. * If there's no output, just advance idx. */ - inline void - next_glyph (void) + void + next_glyph () { if (have_output) { - if (unlikely (out_info != info || out_len != idx)) { + if (out_info != info || out_len != idx) + { if (unlikely (!make_room_for (1, 1))) return; out_info[out_len] = info[idx]; } @@ -235,16 +272,31 @@ struct hb_buffer_t { idx++; } + /* Copies n glyphs at idx to output and advance idx. + * If there's no output, just advance idx. */ + void + next_glyphs (unsigned int n) + { + if (have_output) + { + if (out_info != info || out_len != idx) + { + if (unlikely (!make_room_for (n, n))) return; + memmove (out_info + out_len, info + idx, n * sizeof (out_info[0])); + } + out_len += n; + } + idx += n; + } /* Advance idx without copying to output. */ - inline void skip_glyph (void) { idx++; } - - inline void reset_masks (hb_mask_t mask) + void skip_glyph () { idx++; } + void reset_masks (hb_mask_t mask) { for (unsigned int j = 0; j < len; j++) info[j].mask = mask; } - inline void add_masks (hb_mask_t mask) + void add_masks (hb_mask_t mask) { for (unsigned int j = 0; j < len; j++) info[j].mask |= mask; @@ -252,7 +304,7 @@ struct hb_buffer_t { HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask, unsigned int cluster_start, unsigned int cluster_end); - inline void merge_clusters (unsigned int start, unsigned int end) + void merge_clusters (unsigned int start, unsigned int end) { if (end - start < 2) return; @@ -261,9 +313,9 @@ struct hb_buffer_t { HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end); HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end); /* Merge clusters for deleting current glyph, and skip it. */ - HB_INTERNAL void delete_glyph (void); + HB_INTERNAL void delete_glyph (); - inline void unsafe_to_break (unsigned int start, + void unsafe_to_break (unsigned int start, unsigned int end) { if (end - start < 2) @@ -275,12 +327,14 @@ struct hb_buffer_t { /* Internal methods */ + HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + HB_INTERNAL bool enlarge (unsigned int size); - inline bool ensure (unsigned int size) + bool ensure (unsigned int size) { return likely (!size || size < allocated) ? true : enlarge (size); } - inline bool ensure_inplace (unsigned int size) + bool ensure_inplace (unsigned int size) { return likely (!size || size < allocated); } HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); @@ -289,12 +343,12 @@ struct hb_buffer_t { typedef long scratch_buffer_t; HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size); - inline void clear_context (unsigned int side) { context_len[side] = 0; } + void clear_context (unsigned int side) { context_len[side] = 0; } HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)); - inline bool messaging (void) { return unlikely (message_func); } - inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) + bool messaging () { return unlikely (message_func); } + bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) { if (!messaging ()) return true; @@ -306,7 +360,7 @@ struct hb_buffer_t { } HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0); - static inline void + static void set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0) { if (inf.cluster != cluster) @@ -319,7 +373,7 @@ struct hb_buffer_t { inf.cluster = cluster; } - inline int + int _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos, unsigned int start, unsigned int end, unsigned int cluster) const @@ -328,7 +382,7 @@ struct hb_buffer_t { cluster = MIN<unsigned int> (cluster, infos[i].cluster); return cluster; } - inline void + void _unsafe_to_break_set_mask (hb_glyph_info_t *infos, unsigned int start, unsigned int end, unsigned int cluster) @@ -341,18 +395,15 @@ struct hb_buffer_t { } } - inline void - unsafe_to_break_all (void) - { - unsafe_to_break_impl (0, len); - } - inline void - safe_to_break_all (void) + void unsafe_to_break_all () + { unsafe_to_break_impl (0, len); } + void safe_to_break_all () { for (unsigned int i = 0; i < len; i++) info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK; } }; +DECLARE_NULL_INSTANCE (hb_buffer_t); /* Loop over clusters. Duplicated in foreach_syllable(). */ @@ -385,4 +436,4 @@ _next_cluster (hb_buffer_t *buffer, unsigned int start) #define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ()) -#endif /* HB_BUFFER_PRIVATE_HH */ +#endif /* HB_BUFFER_HH */ diff --git a/src/hb-cache.hh b/src/hb-cache.hh new file mode 100644 index 0000000..bf26d96 --- /dev/null +++ b/src/hb-cache.hh @@ -0,0 +1,80 @@ +/* + * Copyright © 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): Behdad Esfahbod + */ + +#ifndef HB_CACHE_HH +#define HB_CACHE_HH + +#include "hb.hh" + + +/* Implements a lock-free cache for int->int functions. */ + +template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits> +struct hb_cache_t +{ + static_assert ((key_bits >= cache_bits), ""); + static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), ""); + static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), ""); + + void init () { clear (); } + void fini () {} + + void clear () + { + for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) + values[i].set_relaxed (-1); + } + + bool get (unsigned int key, unsigned int *value) const + { + unsigned int k = key & ((1u<<cache_bits)-1); + unsigned int v = values[k].get_relaxed (); + if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) || + (v >> value_bits) != (key >> cache_bits)) + return false; + *value = v & ((1u<<value_bits)-1); + return true; + } + + bool set (unsigned int key, unsigned int value) + { + if (unlikely ((key >> key_bits) || (value >> value_bits))) + return false; /* Overflows */ + unsigned int k = key & ((1u<<cache_bits)-1); + unsigned int v = ((key>>cache_bits)<<value_bits) | value; + values[k].set_relaxed (v); + return true; + } + + private: + hb_atomic_int_t values[1u<<cache_bits]; +}; + +typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t; +typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; + + +#endif /* HB_CACHE_HH */ diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh new file mode 100644 index 0000000..72e9e06 --- /dev/null +++ b/src/hb-cff-interp-common.hh @@ -0,0 +1,725 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF_INTERP_COMMON_HH +#define HB_CFF_INTERP_COMMON_HH + +namespace CFF { + +using namespace OT; + +typedef unsigned int op_code_t; + + +/* === Dict operators === */ + +/* One byte operators (0-31) */ +#define OpCode_version 0 /* CFF Top */ +#define OpCode_Notice 1 /* CFF Top */ +#define OpCode_FullName 2 /* CFF Top */ +#define OpCode_FamilyName 3 /* CFF Top */ +#define OpCode_Weight 4 /* CFF Top */ +#define OpCode_FontBBox 5 /* CFF Top */ +#define OpCode_BlueValues 6 /* CFF Private, CFF2 Private */ +#define OpCode_OtherBlues 7 /* CFF Private, CFF2 Private */ +#define OpCode_FamilyBlues 8 /* CFF Private, CFF2 Private */ +#define OpCode_FamilyOtherBlues 9 /* CFF Private, CFF2 Private */ +#define OpCode_StdHW 10 /* CFF Private, CFF2 Private */ +#define OpCode_StdVW 11 /* CFF Private, CFF2 Private */ +#define OpCode_escape 12 /* All. Shared with CS */ +#define OpCode_UniqueID 13 /* CFF Top */ +#define OpCode_XUID 14 /* CFF Top */ +#define OpCode_charset 15 /* CFF Top (0) */ +#define OpCode_Encoding 16 /* CFF Top (0) */ +#define OpCode_CharStrings 17 /* CFF Top, CFF2 Top */ +#define OpCode_Private 18 /* CFF Top, CFF2 FD */ +#define OpCode_Subrs 19 /* CFF Private, CFF2 Private */ +#define OpCode_defaultWidthX 20 /* CFF Private (0) */ +#define OpCode_nominalWidthX 21 /* CFF Private (0) */ +#define OpCode_vsindexdict 22 /* CFF2 Private/CS */ +#define OpCode_blenddict 23 /* CFF2 Private/CS */ +#define OpCode_vstore 24 /* CFF2 Top */ +#define OpCode_reserved25 25 +#define OpCode_reserved26 26 +#define OpCode_reserved27 27 + +/* Numbers */ +#define OpCode_shortint 28 /* 16-bit integer, All */ +#define OpCode_longintdict 29 /* 32-bit integer, All */ +#define OpCode_BCD 30 /* Real number, CFF2 Top/FD */ +#define OpCode_reserved31 31 + +/* 1-byte integers */ +#define OpCode_OneByteIntFirst 32 /* All. beginning of the range of first byte ints */ +#define OpCode_OneByteIntLast 246 /* All. ending of the range of first byte int */ + +/* 2-byte integers */ +#define OpCode_TwoBytePosInt0 247 /* All. first byte of two byte positive int (+108 to +1131) */ +#define OpCode_TwoBytePosInt1 248 +#define OpCode_TwoBytePosInt2 249 +#define OpCode_TwoBytePosInt3 250 + +#define OpCode_TwoByteNegInt0 251 /* All. first byte of two byte negative int (-1131 to -108) */ +#define OpCode_TwoByteNegInt1 252 +#define OpCode_TwoByteNegInt2 253 +#define OpCode_TwoByteNegInt3 254 + +/* Two byte escape operators 12, (0-41) */ +#define OpCode_ESC_Base 256 +#define Make_OpCode_ESC(byte2) ((op_code_t)(OpCode_ESC_Base + (byte2))) + +inline op_code_t Unmake_OpCode_ESC (op_code_t op) { return (op_code_t)(op - OpCode_ESC_Base); } +inline bool Is_OpCode_ESC (op_code_t op) { return op >= OpCode_ESC_Base; } +inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: 1; } + +#define OpCode_Copyright Make_OpCode_ESC(0) /* CFF Top */ +#define OpCode_isFixedPitch Make_OpCode_ESC(1) /* CFF Top (false) */ +#define OpCode_ItalicAngle Make_OpCode_ESC(2) /* CFF Top (0) */ +#define OpCode_UnderlinePosition Make_OpCode_ESC(3) /* CFF Top (-100) */ +#define OpCode_UnderlineThickness Make_OpCode_ESC(4) /* CFF Top (50) */ +#define OpCode_PaintType Make_OpCode_ESC(5) /* CFF Top (0) */ +#define OpCode_CharstringType Make_OpCode_ESC(6) /* CFF Top (2) */ +#define OpCode_FontMatrix Make_OpCode_ESC(7) /* CFF Top, CFF2 Top (.001 0 0 .001 0 0)*/ +#define OpCode_StrokeWidth Make_OpCode_ESC(8) /* CFF Top (0) */ +#define OpCode_BlueScale Make_OpCode_ESC(9) /* CFF Private, CFF2 Private (0.039625) */ +#define OpCode_BlueShift Make_OpCode_ESC(10) /* CFF Private, CFF2 Private (7) */ +#define OpCode_BlueFuzz Make_OpCode_ESC(11) /* CFF Private, CFF2 Private (1) */ +#define OpCode_StemSnapH Make_OpCode_ESC(12) /* CFF Private, CFF2 Private */ +#define OpCode_StemSnapV Make_OpCode_ESC(13) /* CFF Private, CFF2 Private */ +#define OpCode_ForceBold Make_OpCode_ESC(14) /* CFF Private (false) */ +#define OpCode_reservedESC15 Make_OpCode_ESC(15) +#define OpCode_reservedESC16 Make_OpCode_ESC(16) +#define OpCode_LanguageGroup Make_OpCode_ESC(17) /* CFF Private, CFF2 Private (0) */ +#define OpCode_ExpansionFactor Make_OpCode_ESC(18) /* CFF Private, CFF2 Private (0.06) */ +#define OpCode_initialRandomSeed Make_OpCode_ESC(19) /* CFF Private (0) */ +#define OpCode_SyntheticBase Make_OpCode_ESC(20) /* CFF Top */ +#define OpCode_PostScript Make_OpCode_ESC(21) /* CFF Top */ +#define OpCode_BaseFontName Make_OpCode_ESC(22) /* CFF Top */ +#define OpCode_BaseFontBlend Make_OpCode_ESC(23) /* CFF Top */ +#define OpCode_reservedESC24 Make_OpCode_ESC(24) +#define OpCode_reservedESC25 Make_OpCode_ESC(25) +#define OpCode_reservedESC26 Make_OpCode_ESC(26) +#define OpCode_reservedESC27 Make_OpCode_ESC(27) +#define OpCode_reservedESC28 Make_OpCode_ESC(28) +#define OpCode_reservedESC29 Make_OpCode_ESC(29) +#define OpCode_ROS Make_OpCode_ESC(30) /* CFF Top_CID */ +#define OpCode_CIDFontVersion Make_OpCode_ESC(31) /* CFF Top_CID (0) */ +#define OpCode_CIDFontRevision Make_OpCode_ESC(32) /* CFF Top_CID (0) */ +#define OpCode_CIDFontType Make_OpCode_ESC(33) /* CFF Top_CID (0) */ +#define OpCode_CIDCount Make_OpCode_ESC(34) /* CFF Top_CID (8720) */ +#define OpCode_UIDBase Make_OpCode_ESC(35) /* CFF Top_CID */ +#define OpCode_FDArray Make_OpCode_ESC(36) /* CFF Top_CID, CFF2 Top */ +#define OpCode_FDSelect Make_OpCode_ESC(37) /* CFF Top_CID, CFF2 Top */ +#define OpCode_FontName Make_OpCode_ESC(38) /* CFF Top_CID */ + + +/* === CharString operators === */ + +#define OpCode_hstem 1 /* CFF, CFF2 */ +#define OpCode_Reserved2 2 +#define OpCode_vstem 3 /* CFF, CFF2 */ +#define OpCode_vmoveto 4 /* CFF, CFF2 */ +#define OpCode_rlineto 5 /* CFF, CFF2 */ +#define OpCode_hlineto 6 /* CFF, CFF2 */ +#define OpCode_vlineto 7 /* CFF, CFF2 */ +#define OpCode_rrcurveto 8 /* CFF, CFF2 */ +#define OpCode_Reserved9 9 +#define OpCode_callsubr 10 /* CFF, CFF2 */ +#define OpCode_return 11 /* CFF */ +//#define OpCode_escape 12 /* CFF, CFF2 */ +#define OpCode_Reserved13 13 +#define OpCode_endchar 14 /* CFF */ +#define OpCode_vsindexcs 15 /* CFF2 */ +#define OpCode_blendcs 16 /* CFF2 */ +#define OpCode_Reserved17 17 +#define OpCode_hstemhm 18 /* CFF, CFF2 */ +#define OpCode_hintmask 19 /* CFF, CFF2 */ +#define OpCode_cntrmask 20 /* CFF, CFF2 */ +#define OpCode_rmoveto 21 /* CFF, CFF2 */ +#define OpCode_hmoveto 22 /* CFF, CFF2 */ +#define OpCode_vstemhm 23 /* CFF, CFF2 */ +#define OpCode_rcurveline 24 /* CFF, CFF2 */ +#define OpCode_rlinecurve 25 /* CFF, CFF2 */ +#define OpCode_vvcurveto 26 /* CFF, CFF2 */ +#define OpCode_hhcurveto 27 /* CFF, CFF2 */ +//#define OpCode_shortint 28 /* CFF, CFF2 */ +#define OpCode_callgsubr 29 /* CFF, CFF2 */ +#define OpCode_vhcurveto 30 /* CFF, CFF2 */ +#define OpCode_hvcurveto 31 /* CFF, CFF2 */ + +#define OpCode_fixedcs 255 /* 32-bit fixed */ + +/* Two byte escape operators 12, (0-41) */ +#define OpCode_dotsection Make_OpCode_ESC(0) /* CFF (obsoleted) */ +#define OpCode_ReservedESC1 Make_OpCode_ESC(1) +#define OpCode_ReservedESC2 Make_OpCode_ESC(2) +#define OpCode_and Make_OpCode_ESC(3) /* CFF */ +#define OpCode_or Make_OpCode_ESC(4) /* CFF */ +#define OpCode_not Make_OpCode_ESC(5) /* CFF */ +#define OpCode_ReservedESC6 Make_OpCode_ESC(6) +#define OpCode_ReservedESC7 Make_OpCode_ESC(7) +#define OpCode_ReservedESC8 Make_OpCode_ESC(8) +#define OpCode_abs Make_OpCode_ESC(9) /* CFF */ +#define OpCode_add Make_OpCode_ESC(10) /* CFF */ +#define OpCode_sub Make_OpCode_ESC(11) /* CFF */ +#define OpCode_div Make_OpCode_ESC(12) /* CFF */ +#define OpCode_ReservedESC13 Make_OpCode_ESC(13) +#define OpCode_neg Make_OpCode_ESC(14) /* CFF */ +#define OpCode_eq Make_OpCode_ESC(15) /* CFF */ +#define OpCode_ReservedESC16 Make_OpCode_ESC(16) +#define OpCode_ReservedESC17 Make_OpCode_ESC(17) +#define OpCode_drop Make_OpCode_ESC(18) /* CFF */ +#define OpCode_ReservedESC19 Make_OpCode_ESC(19) +#define OpCode_put Make_OpCode_ESC(20) /* CFF */ +#define OpCode_get Make_OpCode_ESC(21) /* CFF */ +#define OpCode_ifelse Make_OpCode_ESC(22) /* CFF */ +#define OpCode_random Make_OpCode_ESC(23) /* CFF */ +#define OpCode_mul Make_OpCode_ESC(24) /* CFF */ +//#define OpCode_reservedESC25 Make_OpCode_ESC(25) +#define OpCode_sqrt Make_OpCode_ESC(26) /* CFF */ +#define OpCode_dup Make_OpCode_ESC(27) /* CFF */ +#define OpCode_exch Make_OpCode_ESC(28) /* CFF */ +#define OpCode_index Make_OpCode_ESC(29) /* CFF */ +#define OpCode_roll Make_OpCode_ESC(30) /* CFF */ +#define OpCode_reservedESC31 Make_OpCode_ESC(31) +#define OpCode_reservedESC32 Make_OpCode_ESC(32) +#define OpCode_reservedESC33 Make_OpCode_ESC(33) +#define OpCode_hflex Make_OpCode_ESC(34) /* CFF, CFF2 */ +#define OpCode_flex Make_OpCode_ESC(35) /* CFF, CFF2 */ +#define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */ +#define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */ + + +#define OpCode_Invalid 0xFFFFu + + +struct number_t +{ + void init () { set_real (0.0); } + void fini () {} + + void set_int (int v) { value = (double) v; } + int to_int () const { return (int) value; } + + void set_fixed (int32_t v) { value = v / 65536.0; } + int32_t to_fixed () const { return (int32_t) (value * 65536.0); } + + void set_real (double v) { value = v; } + double to_real () const { return value; } + + int ceil () const { return (int) ::ceil (value); } + int floor () const { return (int) ::floor (value); } + + bool in_int_range () const + { return ((double) (int16_t) to_int () == value); } + + bool operator > (const number_t &n) const + { return value > n.to_real (); } + + bool operator < (const number_t &n) const + { return n > *this; } + + bool operator >= (const number_t &n) const + { return !(*this < n); } + + bool operator <= (const number_t &n) const + { return !(*this > n); } + + const number_t &operator += (const number_t &n) + { + set_real (to_real () + n.to_real ()); + + return *this; + } + + protected: + double value; +}; + +/* byte string */ +struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> +{ + // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) + template <typename INTTYPE, int minVal, int maxVal> + static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value) + { + TRACE_SERIALIZE (this); + + if (unlikely ((value < minVal || value > maxVal))) + return_trace (false); + + HBUINT8 *p = c->allocate_size<HBUINT8> (1); + if (unlikely (p == nullptr)) return_trace (false); + p->set (intOp); + + INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size); + if (unlikely (ip == nullptr)) return_trace (false); + ip->set ((unsigned int)value); + + return_trace (true); + } + + static bool serialize_int4 (hb_serialize_context_t *c, int value) + { return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); } + + static bool serialize_int2 (hb_serialize_context_t *c, int value) + { return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); } + + /* Defining null_size allows a Null object may be created. Should be safe because: + * A descendent struct Dict uses a Null pointer to indicate a missing table, + * checked before access. + * byte_str_t, a wrapper struct pairing a byte pointer along with its length, always + * checks the length before access. A Null pointer is used as the initial pointer + * along with zero length by the default ctor. + */ + DEFINE_SIZE_MIN(0); +}; + +/* Holder of a section of byte string within a CFFIndex entry */ +struct byte_str_t : hb_ubytes_t +{ + byte_str_t () + : hb_ubytes_t () {} + byte_str_t (const UnsizedByteStr& s, unsigned int l) + : hb_ubytes_t ((const unsigned char*)&s, l) {} + byte_str_t (const unsigned char *s, unsigned int l) + : hb_ubytes_t (s, l) {} + byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */ + : hb_ubytes_t (ub) {} + + /* sub-string */ + byte_str_t sub_str (unsigned int offset, unsigned int len_) const + { return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); } + + bool check_limit (unsigned int offset, unsigned int count) const + { return (offset + count <= length); } +}; + +/* A byte string associated with the current offset and an error condition */ +struct byte_str_ref_t +{ + byte_str_ref_t () + { init (); } + + void init () + { + str = byte_str_t (); + offset = 0; + error = false; + } + + void fini () {} + + byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0) + : str (str_), offset (offset_), error (false) {} + + void reset (const byte_str_t &str_, unsigned int offset_ = 0) + { + str = str_; + offset = offset_; + error = false; + } + + const unsigned char& operator [] (int i) { + if (unlikely ((unsigned int)(offset + i) >= str.length)) + { + set_error (); + return Null(unsigned char); + } + else + return str[offset + i]; + } + + /* Conversion to byte_str_t */ + operator byte_str_t () const { return str.sub_str (offset, str.length - offset); } + + byte_str_t sub_str (unsigned int offset_, unsigned int len_) const + { return str.sub_str (offset_, len_); } + + bool avail (unsigned int count=1) const + { + return (!in_error () && str.check_limit (offset, count)); + } + void inc (unsigned int count=1) + { + if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) + { + offset += count; + } + else + { + offset = str.length; + set_error (); + } + } + + void set_error () { error = true; } + bool in_error () const { return error; } + + byte_str_t str; + unsigned int offset; /* beginning of the sub-string within str */ + + protected: + bool error; +}; + +typedef hb_vector_t<byte_str_t> byte_str_array_t; + +/* stack */ +template <typename ELEM, int LIMIT> +struct stack_t +{ + void init () + { + error = false; + count = 0; + elements.init (); + elements.resize (kSizeLimit); + for (unsigned int i = 0; i < elements.length; i++) + elements[i].init (); + } + + void fini () + { + elements.fini_deep (); + } + + ELEM& operator [] (unsigned int i) + { + if (unlikely (i >= count)) set_error (); + return elements[i]; + } + + void push (const ELEM &v) + { + if (likely (count < elements.length)) + elements[count++] = v; + else + set_error (); + } + + ELEM &push () + { + if (likely (count < elements.length)) + return elements[count++]; + else + { + set_error (); + return Crap(ELEM); + } + } + + ELEM& pop () + { + if (likely (count > 0)) + return elements[--count]; + else + { + set_error (); + return Crap(ELEM); + } + } + + void pop (unsigned int n) + { + if (likely (count >= n)) + count -= n; + else + set_error (); + } + + const ELEM& peek () + { + if (likely (count > 0)) + return elements[count-1]; + else + { + set_error (); + return Null(ELEM); + } + } + + void unpop () + { + if (likely (count < elements.length)) + count++; + else + set_error (); + } + + void clear () { count = 0; } + + bool in_error () const { return (error || elements.in_error ()); } + void set_error () { error = true; } + + unsigned int get_count () const { return count; } + bool is_empty () const { return count == 0; } + + static constexpr unsigned kSizeLimit = LIMIT; + + protected: + bool error; + unsigned int count; + hb_vector_t<ELEM> elements; +}; + +/* argument stack */ +template <typename ARG=number_t> +struct arg_stack_t : stack_t<ARG, 513> +{ + void push_int (int v) + { + ARG &n = S::push (); + n.set_int (v); + } + + void push_fixed (int32_t v) + { + ARG &n = S::push (); + n.set_fixed (v); + } + + void push_real (double v) + { + ARG &n = S::push (); + n.set_real (v); + } + + ARG& pop_num () { return this->pop (); } + + int pop_int () { return this->pop ().to_int (); } + + unsigned int pop_uint () + { + int i = pop_int (); + if (unlikely (i < 0)) + { + i = 0; + S::set_error (); + } + return (unsigned)i; + } + + void push_longint_from_substr (byte_str_ref_t& str_ref) + { + push_int ((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3])); + str_ref.inc (4); + } + + bool push_fixed_from_substr (byte_str_ref_t& str_ref) + { + if (unlikely (!str_ref.avail (4))) + return false; + push_fixed ((int32_t)*(const HBUINT32*)&str_ref[0]); + str_ref.inc (4); + return true; + } + + hb_array_t<const ARG> get_subarray (unsigned int start) const + { + return S::elements.sub_array (start); + } + + private: + typedef stack_t<ARG, 513> S; +}; + +/* an operator prefixed by its operands in a byte string */ +struct op_str_t +{ + void init () {} + void fini () {} + + op_code_t op; + byte_str_t str; +}; + +/* base of OP_SERIALIZER */ +struct op_serializer_t +{ + protected: + bool copy_opstr (hb_serialize_context_t *c, const op_str_t& opstr) const + { + TRACE_SERIALIZE (this); + + HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length); + if (unlikely (d == nullptr)) return_trace (false); + memcpy (d, &opstr.str[0], opstr.str.length); + return_trace (true); + } +}; + +template <typename VAL> +struct parsed_values_t +{ + void init () + { + opStart = 0; + values.init (); + } + void fini () { values.fini_deep (); } + + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) + { + VAL *val = values.push (); + val->op = op; + val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart); + opStart = str_ref.offset; + } + + void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v) + { + VAL *val = values.push (v); + val->op = op; + val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart); + opStart = str_ref.offset; + } + + bool has_op (op_code_t op) const + { + for (unsigned int i = 0; i < get_count (); i++) + if (get_value (i).op == op) return true; + return false; + } + + unsigned get_count () const { return values.length; } + const VAL &get_value (unsigned int i) const { return values[i]; } + const VAL &operator [] (unsigned int i) const { return get_value (i); } + + unsigned int opStart; + hb_vector_t<VAL> values; +}; + +template <typename ARG=number_t> +struct interp_env_t +{ + void init (const byte_str_t &str_) + { + str_ref.reset (str_); + argStack.init (); + error = false; + } + void fini () { argStack.fini (); } + + bool in_error () const + { return error || str_ref.in_error () || argStack.in_error (); } + + void set_error () { error = true; } + + op_code_t fetch_op () + { + op_code_t op = OpCode_Invalid; + if (unlikely (!str_ref.avail ())) + return OpCode_Invalid; + op = (op_code_t)(unsigned char)str_ref[0]; + if (op == OpCode_escape) { + if (unlikely (!str_ref.avail ())) + return OpCode_Invalid; + op = Make_OpCode_ESC(str_ref[1]); + str_ref.inc (); + } + str_ref.inc (); + return op; + } + + const ARG& eval_arg (unsigned int i) + { + return argStack[i]; + } + + ARG& pop_arg () + { + return argStack.pop (); + } + + void pop_n_args (unsigned int n) + { + argStack.pop (n); + } + + void clear_args () + { + pop_n_args (argStack.get_count ()); + } + + byte_str_ref_t str_ref; + arg_stack_t<ARG> argStack; + protected: + bool error; +}; + +typedef interp_env_t<> num_interp_env_t; + +template <typename ARG=number_t> +struct opset_t +{ + static void process_op (op_code_t op, interp_env_t<ARG>& env) + { + switch (op) { + case OpCode_shortint: + env.argStack.push_int ((int16_t)((env.str_ref[0] << 8) | env.str_ref[1])); + env.str_ref.inc (2); + break; + + case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: + case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: + env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.str_ref[0] + 108)); + env.str_ref.inc (); + break; + + case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: + case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: + env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108)); + env.str_ref.inc (); + break; + + default: + /* 1-byte integer */ + if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast))) + { + env.argStack.push_int ((int)op - 139); + } else { + /* invalid unknown operator */ + env.clear_args (); + env.set_error (); + } + break; + } + } +}; + +template <typename ENV> +struct interpreter_t { + + ~interpreter_t() { fini (); } + + void fini () { env.fini (); } + + ENV env; +}; + +} /* namespace CFF */ + +#endif /* HB_CFF_INTERP_COMMON_HH */ diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh new file mode 100644 index 0000000..283bdf1 --- /dev/null +++ b/src/hb-cff-interp-cs-common.hh @@ -0,0 +1,905 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF_INTERP_CS_COMMON_HH +#define HB_CFF_INTERP_CS_COMMON_HH + +#include "hb.hh" +#include "hb-cff-interp-common.hh" + +namespace CFF { + +using namespace OT; + +enum cs_type_t { + CSType_CharString, + CSType_GlobalSubr, + CSType_LocalSubr +}; + +struct call_context_t +{ + void init (const byte_str_ref_t substr_=byte_str_ref_t (), cs_type_t type_=CSType_CharString, unsigned int subr_num_=0) + { + str_ref = substr_; + type = type_; + subr_num = subr_num_; + } + + void fini () {} + + byte_str_ref_t str_ref; + cs_type_t type; + unsigned int subr_num; +}; + +/* call stack */ +const unsigned int kMaxCallLimit = 10; +struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {}; + +template <typename SUBRS> +struct biased_subrs_t +{ + void init (const SUBRS &subrs_) + { + subrs = &subrs_; + unsigned int nSubrs = get_count (); + if (nSubrs < 1240) + bias = 107; + else if (nSubrs < 33900) + bias = 1131; + else + bias = 32768; + } + + void fini () {} + + unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; } + unsigned int get_bias () const { return bias; } + + byte_str_t operator [] (unsigned int index) const + { + if (unlikely ((subrs == nullptr) || index >= subrs->count)) + return Null(byte_str_t); + else + return (*subrs)[index]; + } + + protected: + unsigned int bias; + const SUBRS *subrs; +}; + +struct point_t +{ + void init () + { + x.init (); + y.init (); + } + + void set_int (int _x, int _y) + { + x.set_int (_x); + y.set_int (_y); + } + + void move_x (const number_t &dx) { x += dx; } + void move_y (const number_t &dy) { y += dy; } + void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); } + void move (const point_t &d) { move_x (d.x); move_y (d.y); } + + number_t x; + number_t y; +}; + +template <typename ARG, typename SUBRS> +struct cs_interp_env_t : interp_env_t<ARG> +{ + void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_) + { + interp_env_t<ARG>::init (str); + + context.init (str, CSType_CharString); + seen_moveto = true; + seen_hintmask = false; + hstem_count = 0; + vstem_count = 0; + hintmask_size = 0; + pt.init (); + callStack.init (); + globalSubrs.init (globalSubrs_); + localSubrs.init (localSubrs_); + } + void fini () + { + interp_env_t<ARG>::fini (); + + callStack.fini (); + globalSubrs.fini (); + localSubrs.fini (); + } + + bool in_error () const + { + return callStack.in_error () || SUPER::in_error (); + } + + bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num) + { + int n = SUPER::argStack.pop_int (); + n += biasedSubrs.get_bias (); + if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ()))) + return false; + + subr_num = (unsigned int)n; + return true; + } + + void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type) + { + unsigned int subr_num; + + if (unlikely (!popSubrNum (biasedSubrs, subr_num) + || callStack.get_count () >= kMaxCallLimit)) + { + SUPER::set_error (); + return; + } + context.str_ref = SUPER::str_ref; + callStack.push (context); + + context.init ( biasedSubrs[subr_num], type, subr_num); + SUPER::str_ref = context.str_ref; + } + + void returnFromSubr () + { + if (unlikely (SUPER::str_ref.in_error ())) + SUPER::set_error (); + context = callStack.pop (); + SUPER::str_ref = context.str_ref; + } + + void determine_hintmask_size () + { + if (!seen_hintmask) + { + vstem_count += SUPER::argStack.get_count() / 2; + hintmask_size = (hstem_count + vstem_count + 7) >> 3; + seen_hintmask = true; + } + } + + void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } + bool is_endchar () const { return endchar_flag; } + + const number_t &get_x () const { return pt.x; } + const number_t &get_y () const { return pt.y; } + const point_t &get_pt () const { return pt; } + + void moveto (const point_t &pt_ ) { pt = pt_; } + + public: + call_context_t context; + bool endchar_flag; + bool seen_moveto; + bool seen_hintmask; + + unsigned int hstem_count; + unsigned int vstem_count; + unsigned int hintmask_size; + call_stack_t callStack; + biased_subrs_t<SUBRS> globalSubrs; + biased_subrs_t<SUBRS> localSubrs; + + private: + point_t pt; + + typedef interp_env_t<ARG> SUPER; +}; + +template <typename ENV, typename PARAM> +struct path_procs_null_t +{ + static void rmoveto (ENV &env, PARAM& param) {} + static void hmoveto (ENV &env, PARAM& param) {} + static void vmoveto (ENV &env, PARAM& param) {} + static void rlineto (ENV &env, PARAM& param) {} + static void hlineto (ENV &env, PARAM& param) {} + static void vlineto (ENV &env, PARAM& param) {} + static void rrcurveto (ENV &env, PARAM& param) {} + static void rcurveline (ENV &env, PARAM& param) {} + static void rlinecurve (ENV &env, PARAM& param) {} + static void vvcurveto (ENV &env, PARAM& param) {} + static void hhcurveto (ENV &env, PARAM& param) {} + static void vhcurveto (ENV &env, PARAM& param) {} + static void hvcurveto (ENV &env, PARAM& param) {} + static void moveto (ENV &env, PARAM& param, const point_t &pt) {} + static void line (ENV &env, PARAM& param, const point_t &pt1) {} + static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {} + static void hflex (ENV &env, PARAM& param) {} + static void flex (ENV &env, PARAM& param) {} + static void hflex1 (ENV &env, PARAM& param) {} + static void flex1 (ENV &env, PARAM& param) {} +}; + +template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> > +struct cs_opset_t : opset_t<ARG> +{ + static void process_op (op_code_t op, ENV &env, PARAM& param) + { + switch (op) { + + case OpCode_return: + env.returnFromSubr (); + break; + case OpCode_endchar: + OPSET::check_width (op, env, param); + env.set_endchar (true); + OPSET::flush_args_and_op (op, env, param); + break; + + case OpCode_fixedcs: + env.argStack.push_fixed_from_substr (env.str_ref); + break; + + case OpCode_callsubr: + env.callSubr (env.localSubrs, CSType_LocalSubr); + break; + + case OpCode_callgsubr: + env.callSubr (env.globalSubrs, CSType_GlobalSubr); + break; + + case OpCode_hstem: + case OpCode_hstemhm: + OPSET::check_width (op, env, param); + OPSET::process_hstem (op, env, param); + break; + case OpCode_vstem: + case OpCode_vstemhm: + OPSET::check_width (op, env, param); + OPSET::process_vstem (op, env, param); + break; + case OpCode_hintmask: + case OpCode_cntrmask: + OPSET::check_width (op, env, param); + OPSET::process_hintmask (op, env, param); + break; + case OpCode_rmoveto: + OPSET::check_width (op, env, param); + PATH::rmoveto (env, param); + OPSET::process_post_move (op, env, param); + break; + case OpCode_hmoveto: + OPSET::check_width (op, env, param); + PATH::hmoveto (env, param); + OPSET::process_post_move (op, env, param); + break; + case OpCode_vmoveto: + OPSET::check_width (op, env, param); + PATH::vmoveto (env, param); + OPSET::process_post_move (op, env, param); + break; + case OpCode_rlineto: + PATH::rlineto (env, param); + process_post_path (op, env, param); + break; + case OpCode_hlineto: + PATH::hlineto (env, param); + process_post_path (op, env, param); + break; + case OpCode_vlineto: + PATH::vlineto (env, param); + process_post_path (op, env, param); + break; + case OpCode_rrcurveto: + PATH::rrcurveto (env, param); + process_post_path (op, env, param); + break; + case OpCode_rcurveline: + PATH::rcurveline (env, param); + process_post_path (op, env, param); + break; + case OpCode_rlinecurve: + PATH::rlinecurve (env, param); + process_post_path (op, env, param); + break; + case OpCode_vvcurveto: + PATH::vvcurveto (env, param); + process_post_path (op, env, param); + break; + case OpCode_hhcurveto: + PATH::hhcurveto (env, param); + process_post_path (op, env, param); + break; + case OpCode_vhcurveto: + PATH::vhcurveto (env, param); + process_post_path (op, env, param); + break; + case OpCode_hvcurveto: + PATH::hvcurveto (env, param); + process_post_path (op, env, param); + break; + + case OpCode_hflex: + PATH::hflex (env, param); + OPSET::process_post_flex (op, env, param); + break; + + case OpCode_flex: + PATH::flex (env, param); + OPSET::process_post_flex (op, env, param); + break; + + case OpCode_hflex1: + PATH::hflex1 (env, param); + OPSET::process_post_flex (op, env, param); + break; + + case OpCode_flex1: + PATH::flex1 (env, param); + OPSET::process_post_flex (op, env, param); + break; + + default: + SUPER::process_op (op, env); + break; + } + } + + static void process_hstem (op_code_t op, ENV &env, PARAM& param) + { + env.hstem_count += env.argStack.get_count () / 2; + OPSET::flush_args_and_op (op, env, param); + } + + static void process_vstem (op_code_t op, ENV &env, PARAM& param) + { + env.vstem_count += env.argStack.get_count () / 2; + OPSET::flush_args_and_op (op, env, param); + } + + static void process_hintmask (op_code_t op, ENV &env, PARAM& param) + { + env.determine_hintmask_size (); + if (likely (env.str_ref.avail (env.hintmask_size))) + { + OPSET::flush_hintmask (op, env, param); + env.str_ref.inc (env.hintmask_size); + } + } + + static void process_post_flex (op_code_t op, ENV &env, PARAM& param) + { + OPSET::flush_args_and_op (op, env, param); + } + + static void check_width (op_code_t op, ENV &env, PARAM& param) + {} + + static void process_post_move (op_code_t op, ENV &env, PARAM& param) + { + if (!env.seen_moveto) + { + env.determine_hintmask_size (); + env.seen_moveto = true; + } + OPSET::flush_args_and_op (op, env, param); + } + + static void process_post_path (op_code_t op, ENV &env, PARAM& param) + { + OPSET::flush_args_and_op (op, env, param); + } + + static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param) + { + OPSET::flush_args (env, param); + OPSET::flush_op (op, env, param); + } + + static void flush_args (ENV &env, PARAM& param) + { + env.pop_n_args (env.argStack.get_count ()); + } + + static void flush_op (op_code_t op, ENV &env, PARAM& param) + { + } + + static void flush_hintmask (op_code_t op, ENV &env, PARAM& param) + { + OPSET::flush_args_and_op (op, env, param); + } + + static bool is_number_op (op_code_t op) + { + switch (op) + { + case OpCode_shortint: + case OpCode_fixedcs: + case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: + case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: + case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: + case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: + return true; + + default: + /* 1-byte integer */ + return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast); + } + } + + protected: + typedef opset_t<ARG> SUPER; +}; + +template <typename PATH, typename ENV, typename PARAM> +struct path_procs_t +{ + static void rmoveto (ENV &env, PARAM& param) + { + point_t pt1 = env.get_pt (); + const number_t &dy = env.pop_arg (); + const number_t &dx = env.pop_arg (); + pt1.move (dx, dy); + PATH::moveto (env, param, pt1); + } + + static void hmoveto (ENV &env, PARAM& param) + { + point_t pt1 = env.get_pt (); + pt1.move_x (env.pop_arg ()); + PATH::moveto (env, param, pt1); + } + + static void vmoveto (ENV &env, PARAM& param) + { + point_t pt1 = env.get_pt (); + pt1.move_y (env.pop_arg ()); + PATH::moveto (env, param, pt1); + } + + static void rlineto (ENV &env, PARAM& param) + { + for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + PATH::line (env, param, pt1); + } + } + + static void hlineto (ENV &env, PARAM& param) + { + point_t pt1; + unsigned int i = 0; + for (; i + 2 <= env.argStack.get_count (); i += 2) + { + pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (i)); + PATH::line (env, param, pt1); + pt1.move_y (env.eval_arg (i+1)); + PATH::line (env, param, pt1); + } + if (i < env.argStack.get_count ()) + { + pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (i)); + PATH::line (env, param, pt1); + } + } + + static void vlineto (ENV &env, PARAM& param) + { + point_t pt1; + unsigned int i = 0; + for (; i + 2 <= env.argStack.get_count (); i += 2) + { + pt1 = env.get_pt (); + pt1.move_y (env.eval_arg (i)); + PATH::line (env, param, pt1); + pt1.move_x (env.eval_arg (i+1)); + PATH::line (env, param, pt1); + } + if (i < env.argStack.get_count ()) + { + pt1 = env.get_pt (); + pt1.move_y (env.eval_arg (i)); + PATH::line (env, param, pt1); + } + } + + static void rrcurveto (ENV &env, PARAM& param) + { + for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); + PATH::curve (env, param, pt1, pt2, pt3); + } + } + + static void rcurveline (ENV &env, PARAM& param) + { + unsigned int i = 0; + for (; i + 6 <= env.argStack.get_count (); i += 6) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); + PATH::curve (env, param, pt1, pt2, pt3); + } + for (; i + 2 <= env.argStack.get_count (); i += 2) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + PATH::line (env, param, pt1); + } + } + + static void rlinecurve (ENV &env, PARAM& param) + { + unsigned int i = 0; + unsigned int line_limit = (env.argStack.get_count () % 6); + for (; i + 2 <= line_limit; i += 2) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + PATH::line (env, param, pt1); + } + for (; i + 6 <= env.argStack.get_count (); i += 6) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); + PATH::curve (env, param, pt1, pt2, pt3); + } + } + + static void vvcurveto (ENV &env, PARAM& param) + { + unsigned int i = 0; + point_t pt1 = env.get_pt (); + if ((env.argStack.get_count () & 1) != 0) + pt1.move_x (env.eval_arg (i++)); + for (; i + 4 <= env.argStack.get_count (); i += 4) + { + pt1.move_y (env.eval_arg (i)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + point_t pt3 = pt2; + pt3.move_y (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + pt1 = env.get_pt (); + } + } + + static void hhcurveto (ENV &env, PARAM& param) + { + unsigned int i = 0; + point_t pt1 = env.get_pt (); + if ((env.argStack.get_count () & 1) != 0) + pt1.move_y (env.eval_arg (i++)); + for (; i + 4 <= env.argStack.get_count (); i += 4) + { + pt1.move_x (env.eval_arg (i)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + point_t pt3 = pt2; + pt3.move_x (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + pt1 = env.get_pt (); + } + } + + static void vhcurveto (ENV &env, PARAM& param) + { + point_t pt1, pt2, pt3; + unsigned int i = 0; + if ((env.argStack.get_count () % 8) >= 4) + { + point_t pt1 = env.get_pt (); + pt1.move_y (env.eval_arg (i)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + point_t pt3 = pt2; + pt3.move_x (env.eval_arg (i+3)); + i += 4; + + for (; i + 8 <= env.argStack.get_count (); i += 8) + { + PATH::curve (env, param, pt1, pt2, pt3); + pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (i)); + pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + pt3 = pt2; + pt3.move_y (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + + pt1 = pt3; + pt1.move_y (env.eval_arg (i+4)); + pt2 = pt1; + pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); + pt3 = pt2; + pt3.move_x (env.eval_arg (i+7)); + } + if (i < env.argStack.get_count ()) + pt3.move_y (env.eval_arg (i)); + PATH::curve (env, param, pt1, pt2, pt3); + } + else + { + for (; i + 8 <= env.argStack.get_count (); i += 8) + { + pt1 = env.get_pt (); + pt1.move_y (env.eval_arg (i)); + pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + pt3 = pt2; + pt3.move_x (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + + pt1 = pt3; + pt1.move_x (env.eval_arg (i+4)); + pt2 = pt1; + pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); + pt3 = pt2; + pt3.move_y (env.eval_arg (i+7)); + if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) + pt3.move_x (env.eval_arg (i+8)); + PATH::curve (env, param, pt1, pt2, pt3); + } + } + } + + static void hvcurveto (ENV &env, PARAM& param) + { + point_t pt1, pt2, pt3; + unsigned int i = 0; + if ((env.argStack.get_count () % 8) >= 4) + { + point_t pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (i)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + point_t pt3 = pt2; + pt3.move_y (env.eval_arg (i+3)); + i += 4; + + for (; i + 8 <= env.argStack.get_count (); i += 8) + { + PATH::curve (env, param, pt1, pt2, pt3); + pt1 = env.get_pt (); + pt1.move_y (env.eval_arg (i)); + pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + pt3 = pt2; + pt3.move_x (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + + pt1 = pt3; + pt1.move_x (env.eval_arg (i+4)); + pt2 = pt1; + pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); + pt3 = pt2; + pt3.move_y (env.eval_arg (i+7)); + } + if (i < env.argStack.get_count ()) + pt3.move_x (env.eval_arg (i)); + PATH::curve (env, param, pt1, pt2, pt3); + } + else + { + for (; i + 8 <= env.argStack.get_count (); i += 8) + { + pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (i)); + pt2 = pt1; + pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); + pt3 = pt2; + pt3.move_y (env.eval_arg (i+3)); + PATH::curve (env, param, pt1, pt2, pt3); + + pt1 = pt3; + pt1.move_y (env.eval_arg (i+4)); + pt2 = pt1; + pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); + pt3 = pt2; + pt3.move_x (env.eval_arg (i+7)); + if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) + pt3.move_y (env.eval_arg (i+8)); + PATH::curve (env, param, pt1, pt2, pt3); + } + } + } + + /* default actions to be overridden */ + static void moveto (ENV &env, PARAM& param, const point_t &pt) + { env.moveto (pt); } + + static void line (ENV &env, PARAM& param, const point_t &pt1) + { PATH::moveto (env, param, pt1); } + + static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { PATH::moveto (env, param, pt3); } + + static void hflex (ENV &env, PARAM& param) + { + if (likely (env.argStack.get_count () == 7)) + { + point_t pt1 = env.get_pt (); + pt1.move_x (env.eval_arg (0)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (1), env.eval_arg (2)); + point_t pt3 = pt2; + pt3.move_x (env.eval_arg (3)); + point_t pt4 = pt3; + pt4.move_x (env.eval_arg (4)); + point_t pt5 = pt4; + pt5.move_x (env.eval_arg (5)); + pt5.y = pt1.y; + point_t pt6 = pt5; + pt6.move_x (env.eval_arg (6)); + + curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); + } + else + env.set_error (); + } + + static void flex (ENV &env, PARAM& param) + { + if (likely (env.argStack.get_count () == 13)) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (0), env.eval_arg (1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (2), env.eval_arg (3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (4), env.eval_arg (5)); + point_t pt4 = pt3; + pt4.move (env.eval_arg (6), env.eval_arg (7)); + point_t pt5 = pt4; + pt5.move (env.eval_arg (8), env.eval_arg (9)); + point_t pt6 = pt5; + pt6.move (env.eval_arg (10), env.eval_arg (11)); + + curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); + } + else + env.set_error (); + } + + static void hflex1 (ENV &env, PARAM& param) + { + if (likely (env.argStack.get_count () == 9)) + { + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (0), env.eval_arg (1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (2), env.eval_arg (3)); + point_t pt3 = pt2; + pt3.move_x (env.eval_arg (4)); + point_t pt4 = pt3; + pt4.move_x (env.eval_arg (5)); + point_t pt5 = pt4; + pt5.move (env.eval_arg (6), env.eval_arg (7)); + point_t pt6 = pt5; + pt6.move_x (env.eval_arg (8)); + pt6.y = env.get_pt ().y; + + curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); + } + else + env.set_error (); + } + + static void flex1 (ENV &env, PARAM& param) + { + if (likely (env.argStack.get_count () == 11)) + { + point_t d; + d.init (); + for (unsigned int i = 0; i < 10; i += 2) + d.move (env.eval_arg (i), env.eval_arg (i+1)); + + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (0), env.eval_arg (1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (2), env.eval_arg (3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (4), env.eval_arg (5)); + point_t pt4 = pt3; + pt4.move (env.eval_arg (6), env.eval_arg (7)); + point_t pt5 = pt4; + pt5.move (env.eval_arg (8), env.eval_arg (9)); + point_t pt6 = pt5; + + if (fabs (d.x.to_real ()) > fabs (d.y.to_real ())) + { + pt6.move_x (env.eval_arg (10)); + pt6.y = env.get_pt ().y; + } + else + { + pt6.x = env.get_pt ().x; + pt6.move_y (env.eval_arg (10)); + } + + curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); + } + else + env.set_error (); + } + + protected: + static void curve2 (ENV &env, PARAM& param, + const point_t &pt1, const point_t &pt2, const point_t &pt3, + const point_t &pt4, const point_t &pt5, const point_t &pt6) + { + PATH::curve (env, param, pt1, pt2, pt3); + PATH::curve (env, param, pt4, pt5, pt6); + } +}; + +template <typename ENV, typename OPSET, typename PARAM> +struct cs_interpreter_t : interpreter_t<ENV> +{ + bool interpret (PARAM& param) + { + SUPER::env.set_endchar (false); + + for (;;) { + OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); + if (unlikely (SUPER::env.in_error ())) + return false; + if (SUPER::env.is_endchar ()) + break; + } + + return true; + } + + private: + typedef interpreter_t<ENV> SUPER; +}; + +} /* namespace CFF */ + +#endif /* HB_CFF_INTERP_CS_COMMON_HH */ diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh new file mode 100644 index 0000000..2c54909 --- /dev/null +++ b/src/hb-cff-interp-dict-common.hh @@ -0,0 +1,294 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF_INTERP_DICT_COMMON_HH +#define HB_CFF_INTERP_DICT_COMMON_HH + +#include "hb-cff-interp-common.hh" +#include <math.h> +#include <float.h> + +namespace CFF { + +using namespace OT; + +/* an opstr and the parsed out dict value(s) */ +struct dict_val_t : op_str_t +{ + void init () { single_val.set_int (0); } + void fini () {} + + number_t single_val; +}; + +typedef dict_val_t num_dict_val_t; + +template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {}; + +template <typename OPSTR=op_str_t> +struct top_dict_values_t : dict_values_t<OPSTR> +{ + void init () + { + dict_values_t<OPSTR>::init (); + charStringsOffset = 0; + FDArrayOffset = 0; + } + void fini () { dict_values_t<OPSTR>::fini (); } + + unsigned int calculate_serialized_op_size (const OPSTR& opstr) const + { + switch (opstr.op) + { + case OpCode_CharStrings: + case OpCode_FDArray: + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); + + default: + return opstr.str.length; + } + } + + unsigned int charStringsOffset; + unsigned int FDArrayOffset; +}; + +struct dict_opset_t : opset_t<number_t> +{ + static void process_op (op_code_t op, interp_env_t<number_t>& env) + { + switch (op) { + case OpCode_longintdict: /* 5-byte integer */ + env.argStack.push_longint_from_substr (env.str_ref); + break; + + case OpCode_BCD: /* real number */ + env.argStack.push_real (parse_bcd (env.str_ref)); + break; + + default: + opset_t<number_t>::process_op (op, env); + break; + } + } + + static double parse_bcd (byte_str_ref_t& str_ref) + { + bool neg = false; + double int_part = 0; + uint64_t frac_part = 0; + uint32_t frac_count = 0; + bool exp_neg = false; + uint32_t exp_part = 0; + bool exp_overflow = false; + enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; + enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; + const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */ + const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ + + double value = 0.0; + unsigned char byte = 0; + for (uint32_t i = 0;; i++) + { + char d; + if ((i & 1) == 0) + { + if (!str_ref.avail ()) + { + str_ref.set_error (); + return 0.0; + } + byte = str_ref[0]; + str_ref.inc (); + d = byte >> 4; + } + else + d = byte & 0x0F; + + switch (d) + { + case RESERVED: + str_ref.set_error (); + return value; + + case END: + value = (double)(neg? -int_part: int_part); + if (frac_count > 0) + { + double frac = (frac_part / pow (10.0, (double)frac_count)); + if (neg) frac = -frac; + value += frac; + } + if (unlikely (exp_overflow)) + { + if (value == 0.0) + return value; + if (exp_neg) + return neg? -DBL_MIN: DBL_MIN; + else + return neg? -DBL_MAX: DBL_MAX; + } + if (exp_part != 0) + { + if (exp_neg) + value /= pow (10.0, (double)exp_part); + else + value *= pow (10.0, (double)exp_part); + } + return value; + + case NEG: + if (i != 0) + { + str_ref.set_error (); + return 0.0; + } + neg = true; + break; + + case DECIMAL: + if (part != INT_PART) + { + str_ref.set_error (); + return value; + } + part = FRAC_PART; + break; + + case EXP_NEG: + exp_neg = true; + HB_FALLTHROUGH; + + case EXP_POS: + if (part == EXP_PART) + { + str_ref.set_error (); + return value; + } + part = EXP_PART; + break; + + default: + switch (part) { + default: + case INT_PART: + int_part = (int_part * 10) + d; + break; + + case FRAC_PART: + if (likely (frac_part <= MAX_FRACT / 10)) + { + frac_part = (frac_part * 10) + (unsigned)d; + frac_count++; + } + break; + + case EXP_PART: + if (likely (exp_part * 10 + d <= MAX_EXP)) + { + exp_part = (exp_part * 10) + d; + } + else + exp_overflow = true; + break; + } + } + } + + return value; + } + + static bool is_hint_op (op_code_t op) + { + switch (op) + { + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_ForceBold: + case OpCode_LanguageGroup: + case OpCode_ExpansionFactor: + return true; + default: + return false; + } + } +}; + +template <typename VAL=op_str_t> +struct top_dict_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval) + { + switch (op) { + case OpCode_CharStrings: + dictval.charStringsOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_FDArray: + dictval.FDArrayOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_FontMatrix: + env.clear_args (); + break; + default: + dict_opset_t::process_op (op, env); + break; + } + } +}; + +template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> +struct dict_interpreter_t : interpreter_t<ENV> +{ + bool interpret (PARAM& param) + { + param.init (); + while (SUPER::env.str_ref.avail ()) + { + OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); + if (unlikely (SUPER::env.in_error ())) + return false; + } + + return true; + } + + private: + typedef interpreter_t<ENV> SUPER; +}; + +} /* namespace CFF */ + +#endif /* HB_CFF_INTERP_DICT_COMMON_HH */ diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh new file mode 100644 index 0000000..c7209ed --- /dev/null +++ b/src/hb-cff1-interp-cs.hh @@ -0,0 +1,161 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF1_INTERP_CS_HH +#define HB_CFF1_INTERP_CS_HH + +#include "hb.hh" +#include "hb-cff-interp-cs-common.hh" + +namespace CFF { + +using namespace OT; + +typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t; + +struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs> +{ + template <typename ACC> + void init (const byte_str_t &str, ACC &acc, unsigned int fd) + { + SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + processed_width = false; + has_width = false; + arg_start = 0; + in_seac = false; + } + + void fini () { SUPER::fini (); } + + void set_width (bool has_width_) + { + if (likely (!processed_width && (SUPER::argStack.get_count () > 0))) + { + if (has_width_) + { + width = SUPER::argStack[0]; + has_width = true; + arg_start = 1; + } + } + processed_width = true; + } + + void clear_args () + { + arg_start = 0; + SUPER::clear_args (); + } + + void set_in_seac (bool _in_seac) { in_seac = _in_seac; } + + bool processed_width; + bool has_width; + unsigned int arg_start; + number_t width; + bool in_seac; + + private: + typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER; +}; + +template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM> > +struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH> +{ + /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */ + /* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */ + + static void process_op (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param) + { + switch (op) { + case OpCode_dotsection: + SUPER::flush_args_and_op (op, env, param); + break; + + case OpCode_endchar: + OPSET::check_width (op, env, param); + if (env.argStack.get_count () >= 4) + { + OPSET::process_seac (env, param); + } + OPSET::flush_args_and_op (op, env, param); + env.set_endchar (true); + break; + + default: + SUPER::process_op (op, env, param); + } + } + + static void check_width (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param) + { + if (!env.processed_width) + { + bool has_width = false; + switch (op) + { + case OpCode_endchar: + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + has_width = ((env.argStack.get_count () & 1) != 0); + break; + case OpCode_hmoveto: + case OpCode_vmoveto: + has_width = (env.argStack.get_count () > 1); + break; + case OpCode_rmoveto: + has_width = (env.argStack.get_count () > 2); + break; + default: + return; + } + env.set_width (has_width); + } + } + + static void process_seac (cff1_cs_interp_env_t &env, PARAM& param) + { + } + + static void flush_args (cff1_cs_interp_env_t &env, PARAM& param) + { + SUPER::flush_args (env, param); + env.clear_args (); /* pop off width */ + } + + private: + typedef cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH> SUPER; +}; + +template <typename OPSET, typename PARAM> +struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {}; + +} /* namespace CFF */ + +#endif /* HB_CFF1_INTERP_CS_HH */ diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh new file mode 100644 index 0000000..49e5ee7 --- /dev/null +++ b/src/hb-cff2-interp-cs.hh @@ -0,0 +1,271 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF2_INTERP_CS_HH +#define HB_CFF2_INTERP_CS_HH + +#include "hb.hh" +#include "hb-cff-interp-cs-common.hh" + +namespace CFF { + +using namespace OT; + +struct blend_arg_t : number_t +{ + void init () + { + number_t::init (); + deltas.init (); + } + + void fini () + { + number_t::fini (); + deltas.fini_deep (); + } + + void set_int (int v) { reset_blends (); number_t::set_int (v); } + void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); } + void set_real (double v) { reset_blends (); number_t::set_real (v); } + + void set_blends (unsigned int numValues_, unsigned int valueIndex_, + unsigned int numBlends, hb_array_t<const blend_arg_t> blends_) + { + numValues = numValues_; + valueIndex = valueIndex_; + deltas.resize (numBlends); + for (unsigned int i = 0; i < numBlends; i++) + deltas[i] = blends_[i]; + } + + bool blending () const { return deltas.length > 0; } + void reset_blends () + { + numValues = valueIndex = 0; + deltas.resize (0); + } + + unsigned int numValues; + unsigned int valueIndex; + hb_vector_t<number_t> deltas; +}; + +typedef interp_env_t<blend_arg_t> BlendInterpEnv; +typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t; + +struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> +{ + template <typename ACC> + void init (const byte_str_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) + { + SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + + coords = coords_; + num_coords = num_coords_; + varStore = acc.varStore; + seen_blend = false; + seen_vsindex_ = false; + scalars.init (); + do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore)); + set_ivs (acc.privateDicts[fd].ivs); + } + + void fini () + { + scalars.fini (); + SUPER::fini (); + } + + op_code_t fetch_op () + { + if (this->str_ref.avail ()) + return SUPER::fetch_op (); + + /* make up return or endchar op */ + if (this->callStack.is_empty ()) + return OpCode_endchar; + else + return OpCode_return; + } + + const blend_arg_t& eval_arg (unsigned int i) + { + blend_arg_t &arg = argStack[i]; + blend_arg (arg); + return arg; + } + + const blend_arg_t& pop_arg () + { + blend_arg_t &arg = argStack.pop (); + blend_arg (arg); + return arg; + } + + void process_blend () + { + if (!seen_blend) + { + region_count = varStore->varStore.get_region_index_count (get_ivs ()); + if (do_blend) + { + scalars.resize (region_count); + varStore->varStore.get_scalars (get_ivs (), + (int *)coords, num_coords, + &scalars[0], region_count); + } + seen_blend = true; + } + } + + void process_vsindex () + { + unsigned int index = argStack.pop_uint (); + if (unlikely (seen_vsindex () || seen_blend)) + { + set_error (); + } + else + { + set_ivs (index); + } + seen_vsindex_ = true; + } + + unsigned int get_region_count () const { return region_count; } + void set_region_count (unsigned int region_count_) { region_count = region_count_; } + unsigned int get_ivs () const { return ivs; } + void set_ivs (unsigned int ivs_) { ivs = ivs_; } + bool seen_vsindex () const { return seen_vsindex_; } + + protected: + void blend_arg (blend_arg_t &arg) + { + if (do_blend && arg.blending ()) + { + if (likely (scalars.length == arg.deltas.length)) + { + double v = arg.to_real (); + for (unsigned int i = 0; i < scalars.length; i++) + { + v += (double)scalars[i] * arg.deltas[i].to_real (); + } + arg.set_real (v); + arg.deltas.resize (0); + } + } + } + + protected: + const int *coords; + unsigned int num_coords; + const CFF2VariationStore *varStore; + unsigned int region_count; + unsigned int ivs; + hb_vector_t<float> scalars; + bool do_blend; + bool seen_vsindex_; + bool seen_blend; + + typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER; +}; +template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> > +struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> +{ + static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) + { + switch (op) { + case OpCode_callsubr: + case OpCode_callgsubr: + /* a subroutine number shoudln't be a blended value */ + if (unlikely (env.argStack.peek ().blending ())) + { + env.set_error (); + break; + } + SUPER::process_op (op, env, param); + break; + + case OpCode_blendcs: + OPSET::process_blend (env, param); + break; + + case OpCode_vsindexcs: + if (unlikely (env.argStack.peek ().blending ())) + { + env.set_error (); + break; + } + OPSET::process_vsindex (env, param); + break; + + default: + SUPER::process_op (op, env, param); + } + } + + static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) + { + unsigned int n, k; + + env.process_blend (); + k = env.get_region_count (); + n = env.argStack.pop_uint (); + /* copy the blend values into blend array of the default values */ + unsigned int start = env.argStack.get_count () - ((k+1) * n); + /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ + if (unlikely (start > env.argStack.get_count ())) + { + env.set_error (); + return; + } + for (unsigned int i = 0; i < n; i++) + { + const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k)); + env.argStack[start + i].set_blends (n, i, k, blends); + } + + /* pop off blend values leaving default values now adorned with blend values */ + env.argStack.pop (k * n); + } + + static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) + { + env.process_vsindex (); + env.clear_args (); + } + + private: + typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER; +}; + +template <typename OPSET, typename PARAM> +struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {}; + +} /* namespace CFF */ + +#endif /* HB_CFF2_INTERP_CS_HH */ diff --git a/src/hb-common.cc b/src/hb-common.cc index a67fcf8..93f5b79 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -26,10 +26,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-mutex-private.hh" -#include "hb-object-private.hh" +#include "hb-machinery.hh" #include <locale.h> #ifdef HAVE_XLOCALE_H @@ -37,22 +36,51 @@ #endif +/** + * SECTION:hb-common + * @title: hb-common + * @short_description: Common data types + * @include: hb.h + * + * Common data types used across HarfBuzz are defined here. + **/ + + /* hb_options_t */ -hb_options_union_t _hb_options; +hb_atomic_int_t _hb_options; void -_hb_options_init (void) +_hb_options_init () { hb_options_union_t u; u.i = 0; - u.opts.initialized = 1; + u.opts.initialized = true; + + const char *c = getenv ("HB_OPTIONS"); + if (c) + { + while (*c) + { + const char *p = strchr (c, ':'); + if (!p) + p = c + strlen (c); + +#define OPTION(name, symbol) \ + if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true; + + OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible); + OPTION ("aat", aat); + +#undef OPTION - char *c = getenv ("HB_OPTIONS"); - u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); + c = *p ? p + 1 : p; + } + + } /* This is idempotent and threadsafe. */ - _hb_options = u; + _hb_options.set_relaxed (u.i); } @@ -176,7 +204,7 @@ static const char canon_map[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, - '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-', 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 @@ -219,11 +247,10 @@ struct hb_language_item_t { struct hb_language_item_t *next; hb_language_t lang; - inline bool operator == (const char *s) const { - return lang_equal (lang, s); - } + bool operator == (const char *s) const + { return lang_equal (lang, s); } - inline hb_language_item_t & operator = (const char *s) { + hb_language_item_t & operator = (const char *s) { /* If a custom allocated is used calling strdup() pairs badly with a call to the custom free() in fini() below. Therefore don't call strdup(), implement its behavior. @@ -240,21 +267,21 @@ struct hb_language_item_t { return *this; } - void fini (void) { free ((void *) lang); } + void fini () { free ((void *) lang); } }; /* Thread-safe lock-free language list */ -static hb_language_item_t *langs; +static hb_atomic_ptr_t <hb_language_item_t> langs; -#ifdef HB_USE_ATEXIT +#if HB_USE_ATEXIT static void -free_langs (void) +free_langs () { retry: - hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); - if (!hb_atomic_ptr_cmpexch (&langs, first_lang, nullptr)) + hb_language_item_t *first_lang = langs; + if (unlikely (!langs.cmpexch (first_lang, nullptr))) goto retry; while (first_lang) { @@ -270,7 +297,7 @@ static hb_language_item_t * lang_find_or_insert (const char *key) { retry: - hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); + hb_language_item_t *first_lang = langs; for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) if (*lang == key) @@ -288,13 +315,14 @@ retry: return nullptr; } - if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { + if (unlikely (!langs.cmpexch (first_lang, lang))) + { lang->fini (); free (lang); goto retry; } -#ifdef HB_USE_ATEXIT +#if HB_USE_ATEXIT if (!first_lang) atexit (free_langs); /* First person registers atexit() callback. */ #endif @@ -306,14 +334,14 @@ retry: /** * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): a string representing - * ISO 639 language code + * a BCP 47 language tag * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts @str representing an ISO 639 language code to the corresponding + * Converts @str representing a BCP 47 language tag to the corresponding * #hb_language_t. * * Return value: (transfer none): - * The #hb_language_t corresponding to the ISO 639 language code. + * The #hb_language_t corresponding to the BCP 47 language tag. * * Since: 0.9.2 **/ @@ -361,24 +389,32 @@ hb_language_to_string (hb_language_t language) /** * hb_language_get_default: * + * Get default language from current locale. * + * Note that the first time this function is called, it calls + * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying + * setlocale function is, in many implementations, NOT threadsafe. To avoid + * problems, call this function once before multiple threads can call it. + * This function is only used from hb_buffer_guess_segment_properties() by + * HarfBuzz itself. * * Return value: (transfer none): * * Since: 0.9.2 **/ hb_language_t -hb_language_get_default (void) +hb_language_get_default () { - static hb_language_t default_language = HB_LANGUAGE_INVALID; + static hb_atomic_ptr_t <hb_language_t> default_language; - hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); - if (unlikely (language == HB_LANGUAGE_INVALID)) { + hb_language_t language = default_language; + if (unlikely (language == HB_LANGUAGE_INVALID)) + { language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1); - (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); + (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language); } - return default_language; + return language; } @@ -530,7 +566,6 @@ hb_script_get_horizontal_direction (hb_script_t script) /* Unicode-8.0 additions */ case HB_SCRIPT_HATRAN: - case HB_SCRIPT_OLD_HUNGARIAN: /* Unicode-9.0 additions */ case HB_SCRIPT_ADLAM: @@ -544,7 +579,9 @@ hb_script_get_horizontal_direction (hb_script_t script) /* https://github.com/harfbuzz/harfbuzz/issues/1000 */ + case HB_SCRIPT_OLD_HUNGARIAN: case HB_SCRIPT_OLD_ITALIC: + case HB_SCRIPT_RUNIC: return HB_DIRECTION_INVALID; } @@ -587,6 +624,19 @@ hb_user_data_array_t::get (hb_user_data_key_t *key) /* hb_version */ + +/** + * SECTION:hb-version + * @title: hb-version + * @short_description: Information about the version of HarfBuzz in use + * @include: hb.h + * + * These functions and macros allow accessing version of the HarfBuzz + * library used at compile- as well as run-time, and to direct code + * conditionally based on those versions, again, at compile- or run-time. + **/ + + /** * hb_version: * @major: (out): Library major version component. @@ -617,7 +667,7 @@ hb_version (unsigned int *major, * Since: 0.9.2 **/ const char * -hb_version_string (void) +hb_version_string () { return HB_VERSION_STRING; } @@ -729,48 +779,48 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv) #ifdef USE_XLOCALE -static HB_LOCALE_T C_locale; - -#ifdef HB_USE_ATEXIT -static void -free_C_locale (void) -{ -retry: - HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale); - - if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr)) - goto retry; - - if (locale) - HB_FREE_LOCALE (locale); -} +#if HB_USE_ATEXIT +static void free_static_C_locale (); #endif -static HB_LOCALE_T -get_C_locale (void) +static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T), + hb_C_locale_lazy_loader_t> { -retry: - HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale); - - if (unlikely (!C)) + static HB_LOCALE_T create () { - C = HB_CREATE_LOCALE ("C"); - - if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C)) - { - HB_FREE_LOCALE (C_locale); - goto retry; - } + HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C"); -#ifdef HB_USE_ATEXIT - atexit (free_C_locale); /* First person registers atexit() callback. */ +#if HB_USE_ATEXIT + atexit (free_static_C_locale); #endif + + return C_locale; + } + static void destroy (HB_LOCALE_T p) + { + HB_FREE_LOCALE (p); } + static HB_LOCALE_T get_null () + { + return nullptr; + } +} static_C_locale; - return C; +#if HB_USE_ATEXIT +static +void free_static_C_locale () +{ + static_C_locale.free_instance (); } #endif +static HB_LOCALE_T +get_C_locale () +{ + return static_C_locale.get_unconst (); +} +#endif /* USE_XLOCALE */ + static bool parse_float (const char **pp, const char *end, float *pv) { @@ -846,7 +896,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag) } const char *p = *pp; - while (*pp < end && ISALNUM(**pp)) + while (*pp < end && (ISALNUM(**pp) || **pp == '_')) (*pp)++; if (p == *pp || *pp - p > 4) @@ -875,15 +925,15 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) bool has_start; - feature->start = 0; - feature->end = (unsigned int) -1; + feature->start = HB_FEATURE_GLOBAL_START; + feature->end = HB_FEATURE_GLOBAL_END; if (!parse_char (pp, end, '[')) return true; has_start = parse_uint (pp, end, &feature->start); - if (parse_char (pp, end, ':')) { + if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) { parse_uint (pp, end, &feature->end); } else { if (has_start) @@ -1063,10 +1113,19 @@ hb_variation_to_string (hb_variation_t *variation, while (len && s[len - 1] == ' ') len--; s[len++] = '='; - len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value)); + len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); assert (len < ARRAY_LENGTH (s)); len = MIN (len, size - 1); memcpy (buf, s, len); buf[len] = '\0'; } + +/* If there is no visibility control, then hb-static.cc will NOT + * define anything. Instead, we get it to define one set in here + * only, so only libharfbuzz.so defines them, not other libs. */ +#ifdef HB_NO_VISIBILITY +#undef HB_NO_VISIBILITY +#include "hb-static.cc" +#define HB_NO_VISIBILITY 1 +#endif diff --git a/src/hb-common.h b/src/hb-common.h index 5dc1ebc..2b29e44 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -33,6 +33,10 @@ #ifndef HB_COMMON_H #define HB_COMMON_H +#ifndef HB_EXTERN +#define HB_EXTERN extern +#endif + #ifndef HB_BEGIN_DECLS # ifdef __cplusplus # define HB_BEGIN_DECLS extern "C" { @@ -63,6 +67,23 @@ typedef unsigned __int64 uint64_t; # include <stdint.h> #endif +#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define HB_DEPRECATED __attribute__((__deprecated__)) +#elif defined(_MSC_VER) && (_MSC_VER >= 1300) +#define HB_DEPRECATED __declspec(deprecated) +#else +#define HB_DEPRECATED +#endif + +#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead"))) +#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) +#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead")) +#else +#define HB_DEPRECATED_FOR(f) HB_DEPRECATED +#endif + + HB_BEGIN_DECLS @@ -86,8 +107,8 @@ typedef union _hb_var_int_t { typedef uint32_t hb_tag_t; -#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4)))) -#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag)) +#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF))) +#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF) #define HB_TAG_NONE HB_TAG(0,0,0,0) #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff) @@ -340,13 +361,15 @@ typedef enum HB_SCRIPT_INVALID = HB_TAG_NONE, /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t - * without risking undefined behavior. Include both a signed and unsigned max, - * since technically enums are int, and indeed, hb_script_t ends up being signed. + * without risking undefined behavior. We have two, for historical reasons. + * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed + * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well. + * * See this thread for technicalities: * * https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html */ - _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/ + _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/ _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_script_t; @@ -379,6 +402,19 @@ typedef void (*hb_destroy_func_t) (void *user_data); /* Font features and variations. */ +/** + * HB_FEATURE_GLOBAL_START + * + * Since: 2.0.0 + */ +#define HB_FEATURE_GLOBAL_START 0 +/** + * HB_FEATURE_GLOBAL_END + * + * Since: 2.0.0 + */ +#define HB_FEATURE_GLOBAL_END ((unsigned int) -1) + typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; @@ -412,6 +448,50 @@ HB_EXTERN void hb_variation_to_string (hb_variation_t *variation, char *buf, unsigned int size); +/** + * hb_color_t: + * + * Data type for holding color values. + * + * Since: 2.1.0 + */ +typedef uint32_t hb_color_t; + +#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a))) + +/** + * hb_color_get_alpha: + * + * + * + * Since: 2.1.0 + */ +#define hb_color_get_alpha(color) ((color) & 0xFF) +/** + * hb_color_get_red: + * + * + * + * Since: 2.1.0 + */ +#define hb_color_get_red(color) (((color) >> 8) & 0xFF) +/** + * hb_color_get_green: + * + * + * + * Since: 2.1.0 + */ +#define hb_color_get_green(color) (((color) >> 16) & 0xFF) +/** + * hb_color_get_blue: + * + * + * + * Since: 2.1.0 + */ +#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) + HB_END_DECLS diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 61f9c35..42ea3ea 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -26,15 +26,23 @@ * Google Author(s): Behdad Esfahbod */ -#define HB_SHAPER coretext - -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-shaper-impl-private.hh" +#include "hb.hh" +#include "hb-shaper-impl.hh" #include "hb-coretext.h" +#include "hb-aat-layout.hh" #include <math.h> + +/** + * SECTION:hb-coretext + * @title: hb-coretext + * @short_description: CoreText integration + * @include: hb-coretext.h + * + * Functions for using HarfBuzz with the CoreText fonts. + **/ + /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f @@ -91,13 +99,8 @@ _hb_cg_font_release (void *data) } -HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face) -HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font, - fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) <= .5 -) - static CTFontDescriptorRef -get_last_resort_font_desc (void) +get_last_resort_font_desc () { // TODO Handle allocation failures? CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0); @@ -211,7 +214,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) } CFURLRef original_url = nullptr; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 ATSFontRef atsFont; FSRef fsref; OSStatus status; @@ -241,7 +244,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) * process in Blink. This can be detected by the new file URL location * that the newly found font points to. */ CFURLRef new_url = nullptr; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 atsFont = CTFontGetPlatformFont (new_ct_font, NULL); status = ATSFontGetFileReference (atsFont, &fsref); if (status == noErr) @@ -270,7 +273,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) return ct_font; } -hb_coretext_shaper_face_data_t * +hb_coretext_face_data_t * _hb_coretext_shaper_face_data_create (hb_face_t *face) { CGFontRef cg_font = create_cg_font (face); @@ -281,11 +284,11 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face) return nullptr; } - return (hb_coretext_shaper_face_data_t *) cg_font; + return (hb_coretext_face_data_t *) cg_font; } void -_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) +_hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data) { CFRelease ((CGFontRef) data); } @@ -302,17 +305,17 @@ hb_coretext_face_create (CGFontRef cg_font) CGFontRef hb_coretext_face_get_cg_font (hb_face_t *face) { - if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr; - return (CGFontRef) HB_SHAPER_DATA_GET (face); + return (CGFontRef) (const void *) face->data.coretext; } -hb_coretext_shaper_font_data_t * +hb_coretext_font_data_t * _hb_coretext_shaper_font_data_create (hb_font_t *font) { hb_face_t *face = font->face; - if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr; - CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face); + const hb_coretext_face_data_t *face_data = face->data.coretext; + if (unlikely (!face_data)) return nullptr; + CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem)); @@ -322,15 +325,47 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) return nullptr; } - return (hb_coretext_shaper_font_data_t *) ct_font; + return (hb_coretext_font_data_t *) ct_font; } void -_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) +_hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data) { CFRelease ((CTFontRef) data); } +static const hb_coretext_font_data_t * +hb_coretext_font_data_sync (hb_font_t *font) +{ +retry: + const hb_coretext_font_data_t *data = font->data.coretext; + if (unlikely (!data)) return nullptr; + + if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5) + { + /* XXX-MT-bug + * Note that evaluating condition above can be dangerous if another thread + * got here first and destructed data. That's, as always, bad use pattern. + * If you modify the font (change font size), other threads must not be + * using it at the same time. However, since this check is delayed to + * when one actually tries to shape something, this is a XXX race condition + * (and the only one we have that I know of) right now. Ie. you modify the + * font size in one thread, then (supposedly safely) try to use it from two + * or more threads and BOOM! I'm not sure how to fix this. We want RCU. + */ + + /* Drop and recreate. */ + /* If someone dropped it in the mean time, throw it away and don't touch it. + * Otherwise, destruct it. */ + if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr))) + _hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data)); + else + goto retry; + } + return font->data.coretext; +} + + /* * Since: 1.7.2 */ @@ -343,13 +378,13 @@ hb_coretext_font_create (CTFontRef ct_font) hb_font_t *font = hb_font_create (face); hb_face_destroy (face); - if (unlikely (hb_object_is_inert (font))) + if (unlikely (hb_object_is_immutable (font))) return font; hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font))); /* Let there be dragons here... */ - HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font); + font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font)); return font; } @@ -357,31 +392,8 @@ hb_coretext_font_create (CTFontRef ct_font) CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font) { - if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr; - return (CTFontRef) HB_SHAPER_DATA_GET (font); -} - - - -/* - * shaper shape_plan data - */ - -struct hb_coretext_shaper_shape_plan_data_t {}; - -hb_coretext_shaper_shape_plan_data_t * -_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; -} - -void -_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) -{ + const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font); + return data ? (CTFontRef) data : nullptr; } @@ -432,183 +444,6 @@ struct range_record_t { }; -/* The following enum members are added in OS X 10.8. */ -#define kAltHalfWidthTextSelector 6 -#define kAltProportionalTextSelector 5 -#define kAlternateHorizKanaOffSelector 1 -#define kAlternateHorizKanaOnSelector 0 -#define kAlternateKanaType 34 -#define kAlternateVertKanaOffSelector 3 -#define kAlternateVertKanaOnSelector 2 -#define kCaseSensitiveLayoutOffSelector 1 -#define kCaseSensitiveLayoutOnSelector 0 -#define kCaseSensitiveLayoutType 33 -#define kCaseSensitiveSpacingOffSelector 3 -#define kCaseSensitiveSpacingOnSelector 2 -#define kContextualAlternatesOffSelector 1 -#define kContextualAlternatesOnSelector 0 -#define kContextualAlternatesType 36 -#define kContextualLigaturesOffSelector 19 -#define kContextualLigaturesOnSelector 18 -#define kContextualSwashAlternatesOffSelector 5 -#define kContextualSwashAlternatesOnSelector 4 -#define kDefaultLowerCaseSelector 0 -#define kDefaultUpperCaseSelector 0 -#define kHistoricalLigaturesOffSelector 21 -#define kHistoricalLigaturesOnSelector 20 -#define kHojoCharactersSelector 12 -#define kJIS2004CharactersSelector 11 -#define kLowerCasePetiteCapsSelector 2 -#define kLowerCaseSmallCapsSelector 1 -#define kLowerCaseType 37 -#define kMathematicalGreekOffSelector 11 -#define kMathematicalGreekOnSelector 10 -#define kNLCCharactersSelector 13 -#define kQuarterWidthTextSelector 4 -#define kScientificInferiorsSelector 4 -#define kStylisticAltEightOffSelector 17 -#define kStylisticAltEightOnSelector 16 -#define kStylisticAltEighteenOffSelector 37 -#define kStylisticAltEighteenOnSelector 36 -#define kStylisticAltElevenOffSelector 23 -#define kStylisticAltElevenOnSelector 22 -#define kStylisticAltFifteenOffSelector 31 -#define kStylisticAltFifteenOnSelector 30 -#define kStylisticAltFiveOffSelector 11 -#define kStylisticAltFiveOnSelector 10 -#define kStylisticAltFourOffSelector 9 -#define kStylisticAltFourOnSelector 8 -#define kStylisticAltFourteenOffSelector 29 -#define kStylisticAltFourteenOnSelector 28 -#define kStylisticAltNineOffSelector 19 -#define kStylisticAltNineOnSelector 18 -#define kStylisticAltNineteenOffSelector 39 -#define kStylisticAltNineteenOnSelector 38 -#define kStylisticAltOneOffSelector 3 -#define kStylisticAltOneOnSelector 2 -#define kStylisticAltSevenOffSelector 15 -#define kStylisticAltSevenOnSelector 14 -#define kStylisticAltSeventeenOffSelector 35 -#define kStylisticAltSeventeenOnSelector 34 -#define kStylisticAltSixOffSelector 13 -#define kStylisticAltSixOnSelector 12 -#define kStylisticAltSixteenOffSelector 33 -#define kStylisticAltSixteenOnSelector 32 -#define kStylisticAltTenOffSelector 21 -#define kStylisticAltTenOnSelector 20 -#define kStylisticAltThirteenOffSelector 27 -#define kStylisticAltThirteenOnSelector 26 -#define kStylisticAltThreeOffSelector 7 -#define kStylisticAltThreeOnSelector 6 -#define kStylisticAltTwelveOffSelector 25 -#define kStylisticAltTwelveOnSelector 24 -#define kStylisticAltTwentyOffSelector 41 -#define kStylisticAltTwentyOnSelector 40 -#define kStylisticAltTwoOffSelector 5 -#define kStylisticAltTwoOnSelector 4 -#define kStylisticAlternativesType 35 -#define kSwashAlternatesOffSelector 3 -#define kSwashAlternatesOnSelector 2 -#define kThirdWidthTextSelector 3 -#define kTraditionalNamesCharactersSelector 14 -#define kUpperCasePetiteCapsSelector 2 -#define kUpperCaseSmallCapsSelector 1 -#define kUpperCaseType 38 - -/* Table data courtesy of Apple. */ -static const struct feature_mapping_t { - FourCharCode otFeatureTag; - uint16_t aatFeatureType; - uint16_t selectorToEnable; - uint16_t selectorToDisable; -} feature_mappings[] = { - { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, - { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, - { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, - { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, - { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, - { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, - { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, - { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, - { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, - { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, - { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, - { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, - { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, - { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, - { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, - { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, - { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, - { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, - { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, - { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, - { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, - { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, - { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, - { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, - { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, - { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, - { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, - { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, - { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, - { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, - { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, - { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, - { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, - { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, - { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, - { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, - { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, - { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, - { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, - { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, - { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, - { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, - { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, - { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, - { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, - { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, - { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, - { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, - { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, - { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, - { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, - { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, - { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, - { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, - { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, - { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, - { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, - { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, - { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, - { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, - { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, - { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, - { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, - { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, - { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, - { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, - { 'unic', kLetterCaseType, 14, 15 }, - { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, - { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, - { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, - { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, - { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, -}; - -static int -_hb_feature_mapping_cmp (const void *key_, const void *entry_) -{ - unsigned int key = * (unsigned int *) key_; - const feature_mapping_t * entry = (const feature_mapping_t *) entry_; - return key < entry->otFeatureTag ? -1 : - key > entry->otFeatureTag ? 1 : - 0; -} - hb_bool_t _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_font_t *font, @@ -617,15 +452,15 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, unsigned int num_features) { hb_face_t *face = font->face; - CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face); - CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font); + CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; + CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font); CGFloat ct_font_size = CTFontGetSize (ct_font); CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; /* Attach marks to their bases, to match the 'ot' shaper. - * Adapted from hb-ot-shape:hb_form_clusters(). + * Adapted from a very old version of hb-ot-shape:hb_form_clusters(). * Note that this only makes us be closer to the 'ot' shaper, * but by no means the same. For example, if there's * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will @@ -641,8 +476,8 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, buffer->merge_clusters (i - 1, i + 1); } - hb_auto_t<hb_vector_t<feature_record_t> > feature_records; - hb_auto_t<hb_vector_t<range_record_t> > range_records; + hb_vector_t<feature_record_t> feature_records; + hb_vector_t<range_record_t> range_records; /* * Set up features. @@ -651,14 +486,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, if (num_features) { /* Sort features by start/end events. */ - hb_auto_t<hb_vector_t<feature_event_t> > feature_events; + hb_vector_t<feature_event_t> feature_events; for (unsigned int i = 0; i < num_features; i++) { - const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, - feature_mappings, - ARRAY_LENGTH (feature_mappings), - sizeof (feature_mappings[0]), - _hb_feature_mapping_cmp); + const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag); if (!mapping) continue; @@ -694,9 +525,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } /* Scan events and save features for each range. */ - hb_auto_t<hb_vector_t<active_feature_t> > active_features; + hb_vector_t<active_feature_t> active_features; unsigned int last_index = 0; - for (unsigned int i = 0; i < feature_events.len; i++) + for (unsigned int i = 0; i < feature_events.length; i++) { feature_event_t *event = &feature_events[i]; @@ -705,13 +536,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, /* Save a snapshot of active features and the range. */ range_record_t *range = range_records.push (); - if (active_features.len) + if (active_features.length) { CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); /* TODO sort and resolve conflicting features? */ /* active_features.qsort (); */ - for (unsigned int j = 0; j < active_features.len; j++) + for (unsigned int j = 0; j < active_features.length; j++) { CFStringRef keys[] = { kCTFontFeatureTypeIdentifierKey, @@ -767,7 +598,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } else { active_feature_t *feature = active_features.find (&event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove (feature - active_features.arrayZ ()); } } } @@ -824,7 +655,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CFStringRef string_ref = nullptr; CTLineRef line = nullptr; - if (0) + if (false) { resize_and_retry: DEBUG_MSG (CORETEXT, buffer, "Buffer resize"); @@ -899,7 +730,7 @@ resize_and_retry: CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), kCTFontAttributeName, ct_font); - if (num_features && range_records.len) + if (num_features && range_records.length) { unsigned int start = 0; range_record_t *last_range = &range_records[0]; @@ -1048,7 +879,7 @@ resize_and_retry: * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098 */ bool matched = false; - for (unsigned int i = 0; i < range_records.len; i++) + for (unsigned int i = 0; i < range_records.length; i++) if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font)) { matched = true; @@ -1235,7 +1066,7 @@ resize_and_retry: * * https://crbug.com/419769 */ - if (0) + if (false) { /* Make sure all runs had the expected direction. */ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); @@ -1311,7 +1142,7 @@ fail: if (line) CFRelease (line); - for (unsigned int i = 0; i < range_records.len; i++) + for (unsigned int i = 0; i < range_records.length; i++) if (range_records[i].font) CFRelease (range_records[i].font); @@ -1323,36 +1154,21 @@ fail: * AAT shaper */ -HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face) -HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font) - /* * shaper face data */ -struct hb_coretext_aat_shaper_face_data_t {}; +struct hb_coretext_aat_face_data_t {}; -hb_coretext_aat_shaper_face_data_t * +hb_coretext_aat_face_data_t * _hb_coretext_aat_shaper_face_data_create (hb_face_t *face) { - static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX}; - - for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++) - { - hb_blob_t *blob = face->reference_table (tags[i]); - if (hb_blob_get_length (blob)) - { - hb_blob_destroy (blob); - return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; - } - hb_blob_destroy (blob); - } - - return nullptr; + return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ? + (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; } void -_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED) +_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED) { } @@ -1361,38 +1177,16 @@ _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *d * shaper font data */ -struct hb_coretext_aat_shaper_font_data_t {}; +struct hb_coretext_aat_font_data_t {}; -hb_coretext_aat_shaper_font_data_t * +hb_coretext_aat_font_data_t * _hb_coretext_aat_shaper_font_data_create (hb_font_t *font) { - return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; -} - -void -_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED) -{ -} - - -/* - * shaper shape_plan data - */ - -struct hb_coretext_aat_shaper_shape_plan_data_t {}; - -hb_coretext_aat_shaper_shape_plan_data_t * -_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; } void -_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED) +_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED) { } diff --git a/src/hb-debug.hh b/src/hb-debug.hh index c244347..d7d0165 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh @@ -27,13 +27,60 @@ #ifndef HB_DEBUG_HH #define HB_DEBUG_HH -#include "hb-private.hh" +#include "hb.hh" +#include "hb-atomic.hh" +#include "hb-dsalgs.hh" #ifndef HB_DEBUG #define HB_DEBUG 0 #endif + +/* + * Global runtime options. + */ + +struct hb_options_t +{ + bool unused : 1; /* In-case sign bit is here. */ + bool initialized : 1; + bool uniscribe_bug_compatible : 1; + bool aat : 1; +}; + +union hb_options_union_t { + int i; + hb_options_t opts; +}; +static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), ""); + +HB_INTERNAL void +_hb_options_init (); + +extern HB_INTERNAL hb_atomic_int_t _hb_options; + +static inline hb_options_t +hb_options () +{ + /* Make a local copy, so we can access bitfield threadsafely. */ + hb_options_union_t u; + u.i = _hb_options.get_relaxed (); + + if (unlikely (!u.i)) + { + _hb_options_init (); + u.i = _hb_options.get_relaxed (); + } + + return u.opts; +} + + +/* + * Debug output (needs enabling at compile time.) + */ + static inline bool _hb_debug (unsigned int level, unsigned int max_level) @@ -126,7 +173,7 @@ _hb_debug_msg_va (const char *what, fprintf (stderr, "\n"); } -template <> inline void +template <> inline void HB_PRINTF_FUNC(7, 0) _hb_debug_msg_va<0> (const char *what HB_UNUSED, const void *obj HB_UNUSED, const char *func HB_UNUSED, @@ -145,7 +192,7 @@ _hb_debug_msg (const char *what, int level_dir, const char *message, ...) HB_PRINTF_FUNC(7, 8); -template <int max_level> static inline void +template <int max_level> static inline void HB_PRINTF_FUNC(7, 8) _hb_debug_msg (const char *what, const void *obj, const char *func, @@ -169,7 +216,7 @@ _hb_debug_msg<0> (const char *what HB_UNUSED, int level_dir HB_UNUSED, const char *message HB_UNUSED, ...) HB_PRINTF_FUNC(7, 8); -template <> inline void +template <> inline void HB_PRINTF_FUNC(7, 8) _hb_debug_msg<0> (const char *what HB_UNUSED, const void *obj HB_UNUSED, const char *func HB_UNUSED, @@ -237,7 +284,7 @@ struct hb_auto_trace_t _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap); va_end (ap); } - inline ~hb_auto_trace_t (void) + ~hb_auto_trace_t () { _hb_warn_no_return<ret_t> (returned); if (!returned) { @@ -246,14 +293,16 @@ struct hb_auto_trace_t if (plevel) --*plevel; } - inline ret_t ret (ret_t v, unsigned int line = 0) + ret_t ret (ret_t v, + const char *func = "", + unsigned int line = 0) { if (unlikely (returned)) { fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n"); return v; } - _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, + _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1, "return %s (line %d)", hb_printer_t<ret_t>().print (v), line); if (plevel) --*plevel; @@ -278,17 +327,21 @@ struct hb_auto_trace_t<0, ret_t> const char *message, ...) HB_PRINTF_FUNC(6, 7) {} - inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } + ret_t ret (ret_t v, + const char *func HB_UNUSED = nullptr, + unsigned int line HB_UNUSED = 0) { return v; } }; /* For disabled tracing; optimize out everything. * https://github.com/harfbuzz/harfbuzz/pull/605 */ template <typename ret_t> struct hb_no_trace_t { - inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } + ret_t ret (ret_t v, + const char *func HB_UNUSED = "", + unsigned int line HB_UNUSED = 0) { return v; } }; -#define return_trace(RET) return trace.ret (RET, __LINE__) +#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__) /* @@ -348,30 +401,6 @@ struct hb_no_trace_t { #define TRACE_APPLY(this) hb_no_trace_t<bool> trace #endif -#ifndef HB_DEBUG_CLOSURE -#define HB_DEBUG_CLOSURE (HB_DEBUG+0) -#endif -#if HB_DEBUG_CLOSURE -#define TRACE_CLOSURE(this) \ - hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ - (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " ") -#else -#define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED -#endif - -#ifndef HB_DEBUG_COLLECT_GLYPHS -#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) -#endif -#if HB_DEBUG_COLLECT_GLYPHS -#define TRACE_COLLECT_GLYPHS(this) \ - hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ - (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " ") -#else -#define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED -#endif - #ifndef HB_DEBUG_SANITIZE #define HB_DEBUG_SANITIZE (HB_DEBUG+0) #endif @@ -423,8 +452,6 @@ struct hb_no_trace_t { #ifndef HB_DEBUG_DISPATCH #define HB_DEBUG_DISPATCH ( \ HB_DEBUG_APPLY + \ - HB_DEBUG_CLOSURE + \ - HB_DEBUG_COLLECT_GLYPHS + \ HB_DEBUG_SANITIZE + \ HB_DEBUG_SERIALIZE + \ HB_DEBUG_SUBSET + \ diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h index eac7efb..4a5e702 100644 --- a/src/hb-deprecated.h +++ b/src/hb-deprecated.h @@ -36,10 +36,23 @@ #include "hb-font.h" #include "hb-set.h" + +/** + * SECTION:hb-deprecated + * @title: hb-deprecated + * @short_description: Deprecated API + * @include: hb.h + * + * These API have been deprecated in favor of newer API, or because they + * were deemed unnecessary. + **/ + + HB_BEGIN_DECLS #ifndef HB_DISABLE_DEPRECATED + #define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS #define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT @@ -50,14 +63,162 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t *glyph, void *user_data); -HB_EXTERN void +HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); -HB_EXTERN void +HB_EXTERN HB_DEPRECATED void hb_set_invert (hb_set_t *set); +/** + * hb_unicode_eastasian_width_func_t: + * + * Deprecated: 2.0.0 + */ +typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); + +/** + * hb_unicode_funcs_set_eastasian_width_func: + * @ufuncs: a Unicode function structure + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED void +hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_eastasian_width_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_unicode_eastasian_width: + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED unsigned int +hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); + + +/** + * hb_unicode_decompose_compatibility_func_t: + * @ufuncs: a Unicode function structure + * @u: codepoint to decompose + * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into + * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() + * + * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed. + * The complete length of the decomposition will be returned. + * + * If @u has no compatibility decomposition, zero should be returned. + * + * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any + * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations + * of this function type must ensure that they do not write past the provided array. + * + * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available. + * + * Deprecated: 2.0.0 + */ +typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t u, + hb_codepoint_t *decomposed, + void *user_data); + +/** + * HB_UNICODE_MAX_DECOMPOSITION_LEN: + * + * See Unicode 6.1 for details on the maximum decomposition length. + * + * Deprecated: 2.0.0 + */ +#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */ + +/** + * hb_unicode_funcs_set_decompose_compatibility_func: + * @ufuncs: a Unicode function structure + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED void +hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_decompose_compatibility_func_t func, + void *user_data, hb_destroy_func_t destroy); + +HB_EXTERN HB_DEPRECATED unsigned int +hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t u, + hb_codepoint_t *decomposed); + + +typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + void *user_data); +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; + +/** + * hb_font_funcs_set_glyph_h_kerning_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_v_kerning_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); + +HB_EXTERN hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); +HB_EXTERN hb_position_t +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); + +HB_EXTERN void +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + + #endif HB_END_DECLS diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index 187ab3f..aaf10a1 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -22,28 +22,22 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#include "hb-private.hh" -#include "hb-debug.hh" -#define HB_SHAPER directwrite -#include "hb-shaper-impl-private.hh" +#include "hb.hh" +#include "hb-shaper-impl.hh" #include <DWrite_1.h> #include "hb-directwrite.h" -HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, face) -HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, font) - - /* * hb-directwrite uses new/delete syntatically but as we let users * to override malloc/free, we will redefine new/delete so users * won't need to do that by their own. */ -void* operator new (size_t size) { return malloc (size); } -void* operator new [] (size_t size) { return malloc (size); } -void operator delete (void* pointer) { free (pointer); } +void* operator new (size_t size) { return malloc (size); } +void* operator new [] (size_t size) { return malloc (size); } +void operator delete (void* pointer) { free (pointer); } void operator delete [] (void* pointer) { free (pointer); } @@ -60,23 +54,25 @@ private: IDWriteFontFileStream *mFontFileStream; public: DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) - { - mFontFileStream = fontFileStream; - } + { mFontFileStream = fontFileStream; } // IUnknown interface - IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; } - IFACEMETHOD_ (ULONG, AddRef) () { return 1; } + IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) + { return S_OK; } + IFACEMETHOD_ (ULONG, AddRef) () { return 1; } IFACEMETHOD_ (ULONG, Release) () { return 1; } // IDWriteFontFileLoader methods - virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey (void const* fontFileReferenceKey, - uint32_t fontFileReferenceKeySize, - OUT IDWriteFontFileStream** fontFileStream) + virtual HRESULT STDMETHODCALLTYPE + CreateStreamFromKey (void const* fontFileReferenceKey, + uint32_t fontFileReferenceKeySize, + OUT IDWriteFontFileStream** fontFileStream) { *fontFileStream = mFontFileStream; return S_OK; } + + virtual ~DWriteFontFileLoader() {} }; class DWriteFontFileStream : public IDWriteFontFileStream @@ -92,19 +88,20 @@ public: } // IUnknown interface - IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; } - IFACEMETHOD_ (ULONG, AddRef) () { return 1; } + IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) + { return S_OK; } + IFACEMETHOD_ (ULONG, AddRef) () { return 1; } IFACEMETHOD_ (ULONG, Release) () { return 1; } // IDWriteFontFileStream methods - virtual HRESULT STDMETHODCALLTYPE ReadFileFragment (void const** fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - OUT void** fragmentContext) + virtual HRESULT STDMETHODCALLTYPE + ReadFileFragment (void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void** fragmentContext) { // We are required to do bounds checking. - if (fileOffset + fragmentSize > mSize) - return E_FAIL; + if (fileOffset + fragmentSize > mSize) return E_FAIL; // truncate the 64 bit fileOffset to size_t sized index into mData size_t index = static_cast<size_t> (fileOffset); @@ -115,18 +112,20 @@ public: return S_OK; } - virtual void STDMETHODCALLTYPE ReleaseFileFragment (void* fragmentContext) { } + virtual void STDMETHODCALLTYPE + ReleaseFileFragment (void* fragmentContext) {} - virtual HRESULT STDMETHODCALLTYPE GetFileSize (OUT UINT64* fileSize) + virtual HRESULT STDMETHODCALLTYPE + GetFileSize (OUT UINT64* fileSize) { *fileSize = mSize; return S_OK; } - virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime (OUT UINT64* lastWriteTime) - { - return E_NOTIMPL; - } + virtual HRESULT STDMETHODCALLTYPE + GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; } + + virtual ~DWriteFontFileStream() {} }; @@ -134,36 +133,33 @@ public: * shaper face data */ -struct hb_directwrite_shaper_face_data_t +struct hb_directwrite_face_data_t { IDWriteFactory *dwriteFactory; IDWriteFontFile *fontFile; - IDWriteFontFileStream *fontFileStream; - IDWriteFontFileLoader *fontFileLoader; + DWriteFontFileStream *fontFileStream; + DWriteFontFileLoader *fontFileLoader; IDWriteFontFace *fontFace; hb_blob_t *faceBlob; }; -hb_directwrite_shaper_face_data_t * +hb_directwrite_face_data_t * _hb_directwrite_shaper_face_data_create (hb_face_t *face) { - hb_directwrite_shaper_face_data_t *data = new hb_directwrite_shaper_face_data_t; + hb_directwrite_face_data_t *data = new hb_directwrite_face_data_t; if (unlikely (!data)) return nullptr; // TODO: factory and fontFileLoader should be cached separately IDWriteFactory* dwriteFactory; - DWriteCreateFactory ( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof (IDWriteFactory), - (IUnknown**) &dwriteFactory - ); + DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), + (IUnknown**) &dwriteFactory); HRESULT hr; hb_blob_t *blob = hb_face_reference_blob (face); - DWriteFontFileStream *fontFileStream = new DWriteFontFileStream ( - (uint8_t *) hb_blob_get_data (blob, nullptr), - hb_blob_get_length (blob)); + DWriteFontFileStream *fontFileStream; + fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr), + hb_blob_get_length (blob)); DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream); dwriteFactory->RegisterFontFileLoader (fontFileLoader); @@ -171,7 +167,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) IDWriteFontFile *fontFile; uint64_t fontFileKey = 0; hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey), - fontFileLoader, &fontFile); + fontFileLoader, &fontFile); #define FAIL(...) \ HB_STMT_START { \ @@ -194,7 +190,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) IDWriteFontFace *fontFace; dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0, - DWRITE_FONT_SIMULATIONS_NONE, &fontFace); + DWRITE_FONT_SIMULATIONS_NONE, &fontFace); data->dwriteFactory = dwriteFactory; data->fontFile = fontFile; @@ -207,7 +203,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) } void -_hb_directwrite_shaper_face_data_destroy (hb_directwrite_shaper_face_data_t *data) +_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data) { if (data->fontFace) data->fontFace->Release (); @@ -234,16 +230,12 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_shaper_face_data_t *dat * shaper font data */ -struct hb_directwrite_shaper_font_data_t -{ -}; +struct hb_directwrite_font_data_t {}; -hb_directwrite_shaper_font_data_t * +hb_directwrite_font_data_t * _hb_directwrite_shaper_font_data_create (hb_font_t *font) { - if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr; - - hb_directwrite_shaper_font_data_t *data = new hb_directwrite_shaper_font_data_t; + hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t; if (unlikely (!data)) return nullptr; @@ -251,41 +243,20 @@ _hb_directwrite_shaper_font_data_create (hb_font_t *font) } void -_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data) +_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data) { delete data; } -/* - * shaper shape_plan data - */ - -struct hb_directwrite_shaper_shape_plan_data_t {}; - -hb_directwrite_shaper_shape_plan_data_t * -_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; -} - -void -_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED) -{ -} - // Most of TextAnalysis is originally written by Bas Schouten for Mozilla project // but now is relicensed to MIT for HarfBuzz use -class TextAnalysis - : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink +class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink { public: - IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; } + IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) + { return S_OK; } IFACEMETHOD_ (ULONG, AddRef) () { return 1; } IFACEMETHOD_ (ULONG, Release) () { return 1; } @@ -302,7 +273,7 @@ public: uint8_t mBidiLevel; bool mIsSideways; - inline bool ContainsTextPosition (uint32_t aTextPosition) const + bool ContainsTextPosition (uint32_t aTextPosition) const { return aTextPosition >= mTextStart && aTextPosition < mTextStart + mTextLength; @@ -312,16 +283,10 @@ public: }; public: - TextAnalysis (const wchar_t* text, - uint32_t textLength, - const wchar_t* localeName, - DWRITE_READING_DIRECTION readingDirection) - : mText (text) - , mTextLength (textLength) - , mLocaleName (localeName) - , mReadingDirection (readingDirection) - , mCurrentRun (nullptr) { }; - + TextAnalysis (const wchar_t* text, uint32_t textLength, + const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection) + : mTextLength (textLength), mText (text), mLocaleName (localeName), + mReadingDirection (readingDirection), mCurrentRun (nullptr) {} ~TextAnalysis () { // delete runs, except mRunHead which is part of the TextAnalysis object @@ -333,8 +298,8 @@ public: } } - STDMETHODIMP GenerateResults (IDWriteTextAnalyzer* textAnalyzer, - Run **runHead) + STDMETHODIMP + GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead) { // Analyzes the text using the script analyzer and returns // the result as a series of runs. @@ -359,9 +324,10 @@ public: // IDWriteTextAnalysisSource implementation - IFACEMETHODIMP GetTextAtPosition (uint32_t textPosition, - OUT wchar_t const** textString, - OUT uint32_t* textLength) + IFACEMETHODIMP + GetTextAtPosition (uint32_t textPosition, + OUT wchar_t const** textString, + OUT uint32_t* textLength) { if (textPosition >= mTextLength) { @@ -377,9 +343,10 @@ public: return S_OK; } - IFACEMETHODIMP GetTextBeforePosition (uint32_t textPosition, - OUT wchar_t const** textString, - OUT uint32_t* textLength) + IFACEMETHODIMP + GetTextBeforePosition (uint32_t textPosition, + OUT wchar_t const** textString, + OUT uint32_t* textLength) { if (textPosition == 0 || textPosition > mTextLength) { @@ -397,19 +364,16 @@ public: } IFACEMETHODIMP_ (DWRITE_READING_DIRECTION) - GetParagraphReadingDirection () { return mReadingDirection; } + GetParagraphReadingDirection () { return mReadingDirection; } - IFACEMETHODIMP GetLocaleName (uint32_t textPosition, - uint32_t* textLength, - wchar_t const** localeName) - { - return S_OK; - } + IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength, + wchar_t const** localeName) + { return S_OK; } IFACEMETHODIMP - GetNumberSubstitution (uint32_t textPosition, - OUT uint32_t* textLength, - OUT IDWriteNumberSubstitution** numberSubstitution) + GetNumberSubstitution (uint32_t textPosition, + OUT uint32_t* textLength, + OUT IDWriteNumberSubstitution** numberSubstitution) { // We do not support number substitution. *numberSubstitution = nullptr; @@ -421,9 +385,8 @@ public: // IDWriteTextAnalysisSink implementation IFACEMETHODIMP - SetScriptAnalysis (uint32_t textPosition, - uint32_t textLength, - DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) + SetScriptAnalysis (uint32_t textPosition, uint32_t textLength, + DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) { SetCurrentRun (textPosition); SplitCurrentRun (textPosition); @@ -437,19 +400,19 @@ public: } IFACEMETHODIMP - SetLineBreakpoints (uint32_t textPosition, - uint32_t textLength, - const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; } + SetLineBreakpoints (uint32_t textPosition, + uint32_t textLength, + const DWRITE_LINE_BREAKPOINT* lineBreakpoints) + { return S_OK; } - IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, - uint32_t textLength, - uint8_t explicitLevel, - uint8_t resolvedLevel) { return S_OK; } + IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength, + uint8_t explicitLevel, uint8_t resolvedLevel) + { return S_OK; } IFACEMETHODIMP - SetNumberSubstitution (uint32_t textPosition, - uint32_t textLength, - IDWriteNumberSubstitution* numberSubstitution) { return S_OK; } + SetNumberSubstitution (uint32_t textPosition, uint32_t textLength, + IDWriteNumberSubstitution* numberSubstitution) + { return S_OK; } protected: Run *FetchNextRun (IN OUT uint32_t* textLength) @@ -549,15 +512,14 @@ static inline uint32_t hb_uint32_swap (const uint32_t v) static hb_bool_t _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, - hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - float lineWidth) + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + float lineWidth) { hb_face_t *face = font->face; - hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); - hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + const hb_directwrite_face_data_t *face_data = face->data.directwrite; IDWriteFactory *dwriteFactory = face_data->dwriteFactory; IDWriteFontFace *fontFace = face_data->fontFace; @@ -609,9 +571,10 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES - DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? - DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : - DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; + DWRITE_READING_DIRECTION readingDirection; + readingDirection = buffer->props.direction ? + DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : + DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; /* * There's an internal 16-bit limit on some things inside the analyzer, @@ -640,10 +603,8 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, const wchar_t localeName[20] = {0}; if (buffer->props.language != nullptr) - { mbstowcs ((wchar_t*) localeName, - hb_language_to_string (buffer->props.language), 20); - } + hb_language_to_string (buffer->props.language), 20); // TODO: it does work but doesn't care about ranges DWRITE_TYPOGRAPHIC_FEATURES typographic_features; @@ -654,27 +615,29 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, for (unsigned int i = 0; i < num_features; ++i) { typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG) - hb_uint32_swap (features[i].tag); + hb_uint32_swap (features[i].tag); typographic_features.features[i].parameter = features[i].value; } } - const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures = - (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features; + const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures; + dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features; const uint32_t featureRangeLengths[] = { textLength }; // - uint16_t* clusterMap = new uint16_t[textLength]; - DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = - new DWRITE_SHAPING_TEXT_PROPERTIES[textLength]; + uint16_t* clusterMap; + clusterMap = new uint16_t[textLength]; + DWRITE_SHAPING_TEXT_PROPERTIES* textProperties; + textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength]; retry_getglyphs: uint16_t* glyphIndices = new uint16_t[maxGlyphCount]; - DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = - new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount]; + DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties; + glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount]; hr = analyzer->GetGlyphs (textString, textLength, fontFace, false, - isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures, - featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices, - glyphProperties, &glyphCount); + isRightToLeft, &runHead->mScript, localeName, + nullptr, &dwFeatures, featureRangeLengths, 1, + maxGlyphCount, clusterMap, textProperties, + glyphIndices, glyphProperties, &glyphCount); if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))) { @@ -694,30 +657,28 @@ retry_getglyphs: /* The -2 in the following is to compensate for possible * alignment needed after the WORD array. sizeof (WORD) == 2. */ unsigned int glyphs_size = (scratch_size * sizeof (int) - 2) - / (sizeof (WORD) + - sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) + - sizeof (int) + - sizeof (DWRITE_GLYPH_OFFSET) + - sizeof (uint32_t)); + / (sizeof (WORD) + + sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) + + sizeof (int) + + sizeof (DWRITE_GLYPH_OFFSET) + + sizeof (uint32_t)); ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); #undef ALLOCATE_ARRAY int fontEmSize = font->face->get_upem (); - if (fontEmSize < 0) - fontEmSize = -fontEmSize; + if (fontEmSize < 0) fontEmSize = -fontEmSize; - if (fontEmSize < 0) - fontEmSize = -fontEmSize; + if (fontEmSize < 0) fontEmSize = -fontEmSize; double x_mult = (double) font->x_scale / fontEmSize; double y_mult = (double) font->y_scale / fontEmSize; - hr = analyzer->GetGlyphPlacements (textString, - clusterMap, textProperties, textLength, glyphIndices, - glyphProperties, glyphCount, fontFace, fontEmSize, - false, isRightToLeft, &runHead->mScript, localeName, - &dwFeatures, featureRangeLengths, 1, - glyphAdvances, glyphOffsets); + hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties, + textLength, glyphIndices, glyphProperties, + glyphCount, fontFace, fontEmSize, + false, isRightToLeft, &runHead->mScript, localeName, + &dwFeatures, featureRangeLengths, 1, + glyphAdvances, glyphOffsets); if (FAILED (hr)) FAIL ("Analyzer failed to get glyph placements."); @@ -727,12 +688,12 @@ retry_getglyphs: if (analyzer1 && lineWidth) { - DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities = new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount]; - hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, - runHead->mScript, textLength, glyphCount, textString, clusterMap, - glyphProperties, justificationOpportunities); + hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript, + textLength, glyphCount, textString, + clusterMap, glyphProperties, + justificationOpportunities); if (FAILED (hr)) FAIL ("Analyzer failed to get justification opportunities."); @@ -740,15 +701,14 @@ retry_getglyphs: float* justifiedGlyphAdvances = new float[maxGlyphCount]; DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount]; hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities, - glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets); + glyphAdvances, glyphOffsets, justifiedGlyphAdvances, + justifiedGlyphOffsets); - if (FAILED (hr)) - FAIL ("Analyzer failed to get justified glyph advances."); + if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances."); DWRITE_SCRIPT_PROPERTIES scriptProperties; hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties); - if (FAILED (hr)) - FAIL ("Analyzer failed to get script properties."); + if (FAILED (hr)) FAIL ("Analyzer failed to get script properties."); uint32_t justificationCharacter = scriptProperties.justificationCharacter; // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs @@ -758,14 +718,15 @@ retry_getglyphs: retry_getjustifiedglyphs: uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount]; float* modifiedGlyphAdvances = new float[maxGlyphCount]; - DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = - new DWRITE_GLYPH_OFFSET[maxGlyphCount]; + DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount]; uint32_t actualGlyphsCount; hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript, - textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices, - glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets, - glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices, - modifiedGlyphAdvances, modifiedGlyphOffsets); + textLength, glyphCount, maxGlyphCount, + clusterMap, glyphIndices, glyphAdvances, + justifiedGlyphAdvances, justifiedGlyphOffsets, + glyphProperties, &actualGlyphsCount, + modifiedClusterMap, modifiedGlyphIndices, + modifiedGlyphAdvances, modifiedGlyphOffsets); if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)) { @@ -805,7 +766,6 @@ retry_getglyphs: } delete [] justificationOpportunities; - } /* Ok, we've got everything we need, now compose output buffer, @@ -813,7 +773,7 @@ retry_getglyphs: /* Calculate visual-clusters. That's what we ship. */ for (unsigned int i = 0; i < glyphCount; i++) - vis_clusters[i] = -1; + vis_clusters[i] = (uint32_t) -1; for (unsigned int i = 0; i < buffer->len; i++) { uint32_t *p = @@ -821,7 +781,7 @@ retry_getglyphs: *p = MIN (*p, buffer->info[i].cluster); } for (unsigned int i = 1; i < glyphCount; i++) - if (vis_clusters[i] == -1) + if (vis_clusters[i] == (uint32_t) -1) vis_clusters[i] = vis_clusters[i - 1]; #undef utf16_index @@ -855,13 +815,11 @@ retry_getglyphs: /* TODO vertical */ pos->x_advance = x_mult * (int32_t) info->mask; - pos->x_offset = - x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32); + pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32); pos->y_offset = y_mult * info->var2.i32; } - if (isRightToLeft) - hb_buffer_reverse (buffer); + if (isRightToLeft) hb_buffer_reverse (buffer); delete [] clusterMap; delete [] glyphIndices; @@ -879,13 +837,13 @@ retry_getglyphs: hb_bool_t _hb_directwrite_shape (hb_shape_plan_t *shape_plan, - hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features) + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) { return _hb_directwrite_shape_full (shape_plan, font, buffer, - features, num_features, 0); + features, num_features, 0); } /* @@ -894,16 +852,17 @@ _hb_directwrite_shape (hb_shape_plan_t *shape_plan, hb_bool_t hb_directwrite_shape_experimental_width (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - float width) + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + float width) { static const char *shapers = "directwrite"; - hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, - &buffer->props, features, num_features, &shapers); + hb_shape_plan_t *shape_plan; + shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, + features, num_features, &shapers); hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer, - features, num_features, width); + features, num_features, width); buffer->unsafe_to_break_all (); diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh index 9586871..cb3057c 100644 --- a/src/hb-dsalgs.hh +++ b/src/hb-dsalgs.hh @@ -27,9 +27,348 @@ #ifndef HB_DSALGS_HH #define HB_DSALGS_HH -#include "hb-private.hh" +#include "hb.hh" +#include "hb-null.hh" +/* Void! For when we need a expression-type of void. */ +typedef const struct _hb_void_t *hb_void_t; +#define HB_VOID ((const _hb_void_t *) nullptr) + + +/* + * Bithacks. + */ + +/* Return the number of 1 bits in v. */ +template <typename T> +static inline HB_CONST_FUNC unsigned int +hb_popcount (T v) +{ +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) + if (sizeof (T) <= sizeof (unsigned int)) + return __builtin_popcount (v); + + if (sizeof (T) <= sizeof (unsigned long)) + return __builtin_popcountl (v); + + if (sizeof (T) <= sizeof (unsigned long long)) + return __builtin_popcountll (v); +#endif + + if (sizeof (T) <= 4) + { + /* "HACKMEM 169" */ + uint32_t y; + y = (v >> 1) &033333333333; + y = v - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); + } + + if (sizeof (T) == 8) + { + unsigned int shift = 32; + return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift)); + } + + if (sizeof (T) == 16) + { + unsigned int shift = 64; + return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift)); + } + + assert (0); + return 0; /* Shut up stupid compiler. */ +} + +/* Returns the number of bits needed to store number */ +template <typename T> +static inline HB_CONST_FUNC unsigned int +hb_bit_storage (T v) +{ + if (unlikely (!v)) return 0; + +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) + if (sizeof (T) <= sizeof (unsigned int)) + return sizeof (unsigned int) * 8 - __builtin_clz (v); + + if (sizeof (T) <= sizeof (unsigned long)) + return sizeof (unsigned long) * 8 - __builtin_clzl (v); + + if (sizeof (T) <= sizeof (unsigned long long)) + return sizeof (unsigned long long) * 8 - __builtin_clzll (v); +#endif + +#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) + if (sizeof (T) <= sizeof (unsigned int)) + { + unsigned long where; + _BitScanReverse (&where, v); + return 1 + where; + } +# if defined(_WIN64) + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanReverse64 (&where, v); + return 1 + where; + } +# endif +#endif + + if (sizeof (T) <= 4) + { + /* "bithacks" */ + const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; + const unsigned int S[] = {1, 2, 4, 8, 16}; + unsigned int r = 0; + for (int i = 4; i >= 0; i--) + if (v & b[i]) + { + v >>= S[i]; + r |= S[i]; + } + return r + 1; + } + if (sizeof (T) <= 8) + { + /* "bithacks" */ + const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL}; + const unsigned int S[] = {1, 2, 4, 8, 16, 32}; + unsigned int r = 0; + for (int i = 5; i >= 0; i--) + if (v & b[i]) + { + v >>= S[i]; + r |= S[i]; + } + return r + 1; + } + if (sizeof (T) == 16) + { + unsigned int shift = 64; + return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift : + hb_bit_storage<uint64_t> ((uint64_t) v); + } + + assert (0); + return 0; /* Shut up stupid compiler. */ +} + +/* Returns the number of zero bits in the least significant side of v */ +template <typename T> +static inline HB_CONST_FUNC unsigned int +hb_ctz (T v) +{ + if (unlikely (!v)) return 0; + +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) + if (sizeof (T) <= sizeof (unsigned int)) + return __builtin_ctz (v); + + if (sizeof (T) <= sizeof (unsigned long)) + return __builtin_ctzl (v); + + if (sizeof (T) <= sizeof (unsigned long long)) + return __builtin_ctzll (v); +#endif + +#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) + if (sizeof (T) <= sizeof (unsigned int)) + { + unsigned long where; + _BitScanForward (&where, v); + return where; + } +# if defined(_WIN64) + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanForward64 (&where, v); + return where; + } +# endif +#endif + + if (sizeof (T) <= 4) + { + /* "bithacks" */ + unsigned int c = 32; + v &= - (int32_t) v; + if (v) c--; + if (v & 0x0000FFFF) c -= 16; + if (v & 0x00FF00FF) c -= 8; + if (v & 0x0F0F0F0F) c -= 4; + if (v & 0x33333333) c -= 2; + if (v & 0x55555555) c -= 1; + return c; + } + if (sizeof (T) <= 8) + { + /* "bithacks" */ + unsigned int c = 64; + v &= - (int64_t) (v); + if (v) c--; + if (v & 0x00000000FFFFFFFFULL) c -= 32; + if (v & 0x0000FFFF0000FFFFULL) c -= 16; + if (v & 0x00FF00FF00FF00FFULL) c -= 8; + if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4; + if (v & 0x3333333333333333ULL) c -= 2; + if (v & 0x5555555555555555ULL) c -= 1; + return c; + } + if (sizeof (T) == 16) + { + unsigned int shift = 64; + return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) : + hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift; + } + + assert (0); + return 0; /* Shut up stupid compiler. */ +} + + +/* + * Tiny stuff. + */ + +template <typename T> +static inline T* hb_addressof (T& arg) +{ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + /* https://en.cppreference.com/w/cpp/memory/addressof */ + return reinterpret_cast<T*>( + &const_cast<char&>( + reinterpret_cast<const volatile char&>(arg))); +#pragma GCC diagnostic pop +} + +/* ASCII tag/character handling */ +static inline bool ISALPHA (unsigned char c) +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +static inline bool ISALNUM (unsigned char c) +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } +static inline bool ISSPACE (unsigned char c) +{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } +static inline unsigned char TOUPPER (unsigned char c) +{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } +static inline unsigned char TOLOWER (unsigned char c) +{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } + +#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; } + +static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) +{ return (a + (b - 1)) / 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]))) + + +static inline int +hb_memcmp (const void *a, const void *b, unsigned int len) +{ + /* It's illegal to pass NULL to memcmp(), even if len is zero. + * So, wrap it. + * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ + if (!len) return 0; + return memcmp (a, b, len); +} + +static inline bool +hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +{ + return (size > 0) && (count >= ((unsigned int) -1) / size); +} + +static inline unsigned int +hb_ceil_to_4 (unsigned int v) +{ + return ((v - 1) | 3) + 1; +} + +template <typename T> struct hb_is_signed; +template <> struct hb_is_signed<signed char> { enum { value = true }; }; +template <> struct hb_is_signed<signed short> { enum { value = true }; }; +template <> struct hb_is_signed<signed int> { enum { value = true }; }; +template <> struct hb_is_signed<signed long> { enum { value = true }; }; +template <> struct hb_is_signed<unsigned char> { enum { value = false }; }; +template <> struct hb_is_signed<unsigned short> { enum { value = false }; }; +template <> struct hb_is_signed<unsigned int> { enum { value = false }; }; +template <> struct hb_is_signed<unsigned long> { enum { value = false }; }; +/* We need to define hb_is_signed for the typedefs we use on pre-Visual + * Studio 2010 for the int8_t type, since __int8/__int64 is not considered + * the same as char/long. The previous lines will suffice for the other + * types, though. Note that somehow, unsigned __int8 is considered same + * as unsigned char. + * https://github.com/harfbuzz/harfbuzz/pull/1499 + */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +template <> struct hb_is_signed<__int8> { enum { value = true }; }; +#endif + +template <typename T> static inline bool +hb_in_range (T u, T lo, T hi) +{ + /* The sizeof() is here to force template instantiation. + * I'm sure there are better ways to do this but can't think of + * one right now. Declaring a variable won't work as HB_UNUSED + * is unusable on some platforms and unused types are less likely + * to generate a warning than unused variables. */ + static_assert (!hb_is_signed<T>::value, ""); + + /* The casts below are important as if T is smaller than int, + * the subtract results will become a signed int! */ + return (T)(u - lo) <= (T)(hi - lo); +} +template <typename T> static inline bool +hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) +{ + return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); +} +template <typename T> static inline bool +hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) +{ + return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); +} + + +/* + * Sort and search. + */ + +static inline void * +hb_bsearch (const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *_key, const void *_item)) +{ + int min = 0, max = (int) nmemb - 1; + while (min <= max) + { + int mid = (min + max) / 2; + const void *p = (const void *) (((const char *) base) + (mid * size)); + int c = compar (key, p); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return (void *) p; + } + return nullptr; +} + static inline void * hb_bsearch_r (const void *key, const void *base, size_t nmemb, size_t size, @@ -39,7 +378,7 @@ hb_bsearch_r (const void *key, const void *base, int min = 0, max = (int) nmemb - 1; while (min <= max) { - int mid = (min + max) / 2; + int mid = ((unsigned int) min + (unsigned int) max) / 2; const void *p = (const void *) (((const char *) base) + (mid * size)); int c = compar (key, p, arg); if (c < 0) @@ -53,8 +392,12 @@ hb_bsearch_r (const void *key, const void *base, } - -/* From https://github.com/noporpoise/sort_r */ +/* From https://github.com/noporpoise/sort_r + * With following modifications: + * + * 10 November 2018: + * https://github.com/noporpoise/sort_r/issues/7 + */ /* Isaac Turner 29 April 2014 Public Domain */ @@ -110,7 +453,7 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, /* Use median of first, middle and last items as pivot */ char *x, *y, *xend, ch; - char *pl, *pr; + char *pl, *pm, *pr; char *last = b+w*(nel-1), *tmp; char *l[3]; l[0] = b; @@ -132,13 +475,15 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, pr = last; while(pl < pr) { - for(; pl < pr; pl += w) { + pm = pl+((pr-pl+1)>>1); + for(; pl < pm; pl += w) { if(sort_r_cmpswap(pl, pr, w, compar, arg)) { pr -= w; /* pivot now at pl */ break; } } - for(; pl < pr; pr -= w) { + pm = pl+((pr-pl)>>1); + for(; pm < pr; pr -= w) { if(sort_r_cmpswap(pl, pr, w, compar, arg)) { pl += w; /* pivot now at pr */ break; @@ -158,4 +503,139 @@ static inline void hb_sort_r(void *base, size_t nel, size_t width, sort_r_simple(base, nel, width, compar, arg); } + +template <typename T, typename T2> static inline void +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2) +{ + for (unsigned int i = 1; i < len; i++) + { + unsigned int j = i; + while (j && compar (&array[j - 1], &array[i]) > 0) + j--; + if (i == j) + continue; + /* Move item i to occupy place for item j, shift what's in between. */ + { + T t = array[i]; + memmove (&array[j + 1], &array[j], (i - j) * sizeof (T)); + array[j] = t; + } + if (array2) + { + T2 t = array2[i]; + memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2)); + array2[j] = t; + } + } +} + +template <typename T> static inline void +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) +{ + hb_stable_sort (array, len, compar, (int *) nullptr); +} + +static inline hb_bool_t +hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) +{ + /* Pain because we don't know whether s is nul-terminated. */ + char buf[64]; + len = MIN (ARRAY_LENGTH (buf) - 1, len); + strncpy (buf, s, len); + buf[len] = '\0'; + + char *end; + errno = 0; + unsigned long v = strtoul (buf, &end, base); + if (errno) return false; + if (*end) return false; + *out = v; + return true; +} + + +struct HbOpOr +{ + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = true; + template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; } +}; +struct HbOpAnd +{ + static constexpr bool passthru_left = false; + static constexpr bool passthru_right = false; + template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; } +}; +struct HbOpMinus +{ + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = false; + template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; } +}; +struct HbOpXor +{ + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = true; + template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; } +}; + + +/* Compiler-assisted vectorization. */ + +/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), + * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128). + * Define that to 0 to disable. */ +template <typename elt_t, unsigned int byte_size> +struct hb_vector_size_t +{ + elt_t& operator [] (unsigned int i) { return u.v[i]; } + const elt_t& operator [] (unsigned int i) const { return u.v[i]; } + + void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } + + template <class Op> + hb_vector_size_t process (const hb_vector_size_t &o) const + { + hb_vector_size_t r; +#if HB_VECTOR_SIZE + if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) + for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) + Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]); + else +#endif + for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) + Op::process (r.u.v[i], u.v[i], o.u.v[i]); + return r; + } + hb_vector_size_t operator | (const hb_vector_size_t &o) const + { return process<HbOpOr> (o); } + hb_vector_size_t operator & (const hb_vector_size_t &o) const + { return process<HbOpAnd> (o); } + hb_vector_size_t operator ^ (const hb_vector_size_t &o) const + { return process<HbOpXor> (o); } + hb_vector_size_t operator ~ () const + { + hb_vector_size_t r; +#if HB_VECTOR_SIZE && 0 + if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) + for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) + r.u.vec[i] = ~u.vec[i]; + else +#endif + for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) + r.u.v[i] = ~u.v[i]; + return r; + } + + private: + static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, ""); + union { + elt_t v[byte_size / sizeof (elt_t)]; +#if HB_VECTOR_SIZE + hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)]; +#endif + } u; +}; + + #endif /* HB_DSALGS_HH */ diff --git a/src/hb-face.cc b/src/hb-face.cc index 2fef09d..375ef92 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -26,23 +26,35 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-face-private.hh" -#include "hb-blob-private.hh" -#include "hb-open-file-private.hh" -#include "hb-ot-head-table.hh" -#include "hb-ot-maxp-table.hh" +#include "hb-face.hh" +#include "hb-blob.hh" +#include "hb-open-file.hh" +#include "hb-ot-face.hh" +#include "hb-ot-cmap-table.hh" +/** + * SECTION:hb-face + * @title: hb-face + * @short_description: Font face objects + * @include: hb.h + * + * Font face is objects represent a single face in a font family. + * More exactly, a font face represents a single face in a binary font file. + * Font faces are typically built from a binary blob and a face index. + * Font faces are used to create fonts. + **/ + /** - * hb_face_count: Get number of faces on the blob - * @blob: + * hb_face_count: + * @blob: a blob. * + * Get number of faces in a blob. * - * - * Return value: Number of faces on the blob + * Return value: Number of faces in @blob * * Since: 1.7.7 **/ @@ -52,36 +64,33 @@ hb_face_count (hb_blob_t *blob) if (unlikely (!blob)) return 0; - hb_blob_t *sanitized = OT::Sanitizer<OT::OpenTypeFontFile> ().sanitize (blob); + /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */ + /* Make API signature const after. */ + hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)); const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> (); + unsigned int ret = ot.get_face_count (); + hb_blob_destroy (sanitized); - return ot.get_face_count (); + return ret; } /* * hb_face_t */ -const hb_face_t _hb_face_nil = { +DEFINE_NULL_INSTANCE (hb_face_t) = +{ HB_OBJECT_HEADER_STATIC, - true, /* immutable */ - nullptr, /* reference_table_func */ nullptr, /* user_data */ nullptr, /* destroy */ 0, /* index */ - 1000, /* upem */ - 0, /* num_glyphs */ + HB_ATOMIC_INT_INIT (1000), /* upem */ + HB_ATOMIC_INT_INIT (0), /* num_glyphs */ - { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - }, - - nullptr, /* shape_plans */ + /* Zero for the rest is fine. */ }; @@ -114,8 +123,10 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, face->user_data = user_data; face->destroy = destroy; - face->upem = 0; - face->num_glyphs = (unsigned int) -1; + face->num_glyphs.set_relaxed (-1); + + face->data.init0 (face); + face->table.init0 (face); return face; } @@ -159,11 +170,12 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void return hb_blob_reference (data->blob); const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); - const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); + unsigned int base_offset; + const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset); const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); - hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length); + hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length); return blob; } @@ -188,7 +200,7 @@ hb_face_create (hb_blob_t *blob, if (unlikely (!blob)) blob = hb_blob_get_empty (); - hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (hb_blob_reference (blob)), index); + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index); if (unlikely (!closure)) return hb_face_get_empty (); @@ -212,9 +224,9 @@ hb_face_create (hb_blob_t *blob, * Since: 0.9.2 **/ hb_face_t * -hb_face_get_empty (void) +hb_face_get_empty () { - return const_cast<hb_face_t *> (&_hb_face_nil); + return const_cast<hb_face_t *> (&Null(hb_face_t)); } @@ -255,9 +267,8 @@ hb_face_destroy (hb_face_t *face) node = next; } -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT + face->data.fini (); + face->table.fini (); if (face->destroy) face->destroy (face->user_data); @@ -301,7 +312,7 @@ hb_face_set_user_data (hb_face_t *face, * Since: 0.9.2 **/ void * -hb_face_get_user_data (hb_face_t *face, +hb_face_get_user_data (const hb_face_t *face, hb_user_data_key_t *key) { return hb_object_get_user_data (face, key); @@ -318,10 +329,10 @@ hb_face_get_user_data (hb_face_t *face, void hb_face_make_immutable (hb_face_t *face) { - if (unlikely (hb_object_is_inert (face))) + if (hb_object_is_immutable (face)) return; - face->immutable = true; + hb_object_make_immutable (face); } /** @@ -335,9 +346,9 @@ hb_face_make_immutable (hb_face_t *face) * Since: 0.9.2 **/ hb_bool_t -hb_face_is_immutable (hb_face_t *face) +hb_face_is_immutable (const hb_face_t *face) { - return face->immutable; + return hb_object_is_immutable (face); } @@ -353,8 +364,8 @@ hb_face_is_immutable (hb_face_t *face) * Since: 0.9.2 **/ hb_blob_t * -hb_face_reference_table (hb_face_t *face, - hb_tag_t tag) +hb_face_reference_table (const hb_face_t *face, + hb_tag_t tag) { return face->reference_table (tag); } @@ -388,7 +399,7 @@ void hb_face_set_index (hb_face_t *face, unsigned int index) { - if (face->immutable) + if (hb_object_is_immutable (face)) return; face->index = index; @@ -405,7 +416,7 @@ hb_face_set_index (hb_face_t *face, * Since: 0.9.2 **/ unsigned int -hb_face_get_index (hb_face_t *face) +hb_face_get_index (const hb_face_t *face) { return face->index; } @@ -423,10 +434,10 @@ void hb_face_set_upem (hb_face_t *face, unsigned int upem) { - if (face->immutable) + if (hb_object_is_immutable (face)) return; - face->upem = upem; + face->upem.set_relaxed (upem); } /** @@ -440,20 +451,11 @@ hb_face_set_upem (hb_face_t *face, * Since: 0.9.2 **/ unsigned int -hb_face_get_upem (hb_face_t *face) +hb_face_get_upem (const hb_face_t *face) { return face->get_upem (); } -void -hb_face_t::load_upem (void) const -{ - hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head)); - const OT::head *head_table = head_blob->as<OT::head> (); - upem = head_table->get_upem (); - hb_blob_destroy (head_blob); -} - /** * hb_face_set_glyph_count: * @face: a face. @@ -467,10 +469,10 @@ void hb_face_set_glyph_count (hb_face_t *face, unsigned int glyph_count) { - if (face->immutable) + if (hb_object_is_immutable (face)) return; - face->num_glyphs = glyph_count; + face->num_glyphs.set_relaxed (glyph_count); } /** @@ -484,23 +486,17 @@ hb_face_set_glyph_count (hb_face_t *face, * Since: 0.9.7 **/ unsigned int -hb_face_get_glyph_count (hb_face_t *face) +hb_face_get_glyph_count (const hb_face_t *face) { return face->get_num_glyphs (); } -void -hb_face_t::load_num_glyphs (void) const -{ - hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp)); - const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> (); - num_glyphs = maxp_table->get_num_glyphs (); - hb_blob_destroy (maxp_blob); -} - /** * hb_face_get_table_tags: * @face: a face. + * @start_offset: index of first tag to return. + * @table_count: input length of @table_tags array, output number of items written. + * @table_tags: array to write tags into. * * Retrieves table tags for a face, if possible. * @@ -509,7 +505,7 @@ hb_face_t::load_num_glyphs (void) const * Since: 1.6.0 **/ unsigned int -hb_face_get_table_tags (hb_face_t *face, +hb_face_get_table_tags (const hb_face_t *face, unsigned int start_offset, unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */) @@ -528,3 +524,200 @@ hb_face_get_table_tags (hb_face_t *face, return ot_face.get_table_tags (start_offset, table_count, table_tags); } + + +/* + * Character set. + */ + + +/** + * hb_face_collect_unicodes: + * @face: font face. + * @out: set to add Unicode characters covered by @face to. + * + * Since: 1.9.0 + */ +void +hb_face_collect_unicodes (hb_face_t *face, + hb_set_t *out) +{ + face->table.cmap->collect_unicodes (out); +} + +/** + * hb_face_collect_variation_selectors: + * @face: font face. + * @out: set to add Variation Selector characters covered by @face to. + * + * + * + * Since: 1.9.0 + */ +void +hb_face_collect_variation_selectors (hb_face_t *face, + hb_set_t *out) +{ + face->table.cmap->collect_variation_selectors (out); +} + +/** + * hb_face_collect_variation_unicodes: + * @face: font face. + * @out: set to add Unicode characters for @variation_selector covered by @face to. + * + * + * + * Since: 1.9.0 + */ +void +hb_face_collect_variation_unicodes (hb_face_t *face, + hb_codepoint_t variation_selector, + hb_set_t *out) +{ + face->table.cmap->collect_variation_unicodes (variation_selector, out); +} + + + +/* + * face-builder: A face that has add_table(). + */ + +struct hb_face_builder_data_t +{ + struct table_entry_t + { + int cmp (hb_tag_t t) const + { + if (t < tag) return -1; + if (t > tag) return -1; + return 0; + } + + hb_tag_t tag; + hb_blob_t *blob; + }; + + hb_vector_t<table_entry_t> tables; +}; + +static hb_face_builder_data_t * +_hb_face_builder_data_create () +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t)); + if (unlikely (!data)) + return nullptr; + + data->tables.init (); + + return data; +} + +static void +_hb_face_builder_data_destroy (void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + for (unsigned int i = 0; i < data->tables.length; i++) + hb_blob_destroy (data->tables[i].blob); + + data->tables.fini (); + + free (data); +} + +static hb_blob_t * +_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) +{ + + unsigned int table_count = data->tables.length; + unsigned int face_length = table_count * 16 + 12; + + for (unsigned int i = 0; i < table_count; i++) + face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob)); + + char *buf = (char *) malloc (face_length); + if (unlikely (!buf)) + return nullptr; + + hb_serialize_context_t c (buf, face_length); + c.propagate_error (data->tables); + OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> (); + + bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2')); + hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; + + bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ()); + + c.end_serialize (); + + if (unlikely (!ret)) + { + free (buf); + return nullptr; + } + + return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free); +} + +static hb_blob_t * +_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + if (!tag) + return _hb_face_builder_data_reference_blob (data); + + hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag); + if (entry) + return hb_blob_reference (entry->blob); + + return nullptr; +} + + +/** + * hb_face_builder_create: + * + * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). + * After tables are added to the face, it can be compiled to a binary + * font file by calling hb_face_reference_blob(). + * + * Return value: (transfer full): New face. + * + * Since: 1.9.0 + **/ +hb_face_t * +hb_face_builder_create () +{ + hb_face_builder_data_t *data = _hb_face_builder_data_create (); + if (unlikely (!data)) return hb_face_get_empty (); + + return hb_face_create_for_tables (_hb_face_builder_reference_table, + data, + _hb_face_builder_data_destroy); +} + +/** + * hb_face_builder_add_table: + * + * Add table for @tag with data provided by @blob to the face. @face must + * be created using hb_face_builder_create(). + * + * Since: 1.9.0 + **/ +hb_bool_t +hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return false; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + hb_face_builder_data_t::table_entry_t *entry = data->tables.push (); + + entry->tag = tag; + entry->blob = hb_blob_reference (blob); + + return true; +} diff --git a/src/hb-face.h b/src/hb-face.h index 983ee56..e8ff090 100644 --- a/src/hb-face.h +++ b/src/hb-face.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-blob.h" +#include "hb-set.h" HB_BEGIN_DECLS @@ -76,19 +77,19 @@ hb_face_set_user_data (hb_face_t *face, hb_bool_t replace); HB_EXTERN void * -hb_face_get_user_data (hb_face_t *face, +hb_face_get_user_data (const hb_face_t *face, hb_user_data_key_t *key); HB_EXTERN void hb_face_make_immutable (hb_face_t *face); HB_EXTERN hb_bool_t -hb_face_is_immutable (hb_face_t *face); +hb_face_is_immutable (const hb_face_t *face); HB_EXTERN hb_blob_t * -hb_face_reference_table (hb_face_t *face, - hb_tag_t tag); +hb_face_reference_table (const hb_face_t *face, + hb_tag_t tag); HB_EXTERN hb_blob_t * hb_face_reference_blob (hb_face_t *face); @@ -98,28 +99,60 @@ hb_face_set_index (hb_face_t *face, unsigned int index); HB_EXTERN unsigned int -hb_face_get_index (hb_face_t *face); +hb_face_get_index (const hb_face_t *face); HB_EXTERN void hb_face_set_upem (hb_face_t *face, unsigned int upem); HB_EXTERN unsigned int -hb_face_get_upem (hb_face_t *face); +hb_face_get_upem (const hb_face_t *face); HB_EXTERN void hb_face_set_glyph_count (hb_face_t *face, unsigned int glyph_count); HB_EXTERN unsigned int -hb_face_get_glyph_count (hb_face_t *face); +hb_face_get_glyph_count (const hb_face_t *face); HB_EXTERN unsigned int -hb_face_get_table_tags (hb_face_t *face, +hb_face_get_table_tags (const hb_face_t *face, unsigned int start_offset, unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */); + +/* + * Character set. + */ + +HB_EXTERN void +hb_face_collect_unicodes (hb_face_t *face, + hb_set_t *out); + +HB_EXTERN void +hb_face_collect_variation_selectors (hb_face_t *face, + hb_set_t *out); + +HB_EXTERN void +hb_face_collect_variation_unicodes (hb_face_t *face, + hb_codepoint_t variation_selector, + hb_set_t *out); + + +/* + * Builder face. + */ + +HB_EXTERN hb_face_t * +hb_face_builder_create (void); + +HB_EXTERN hb_bool_t +hb_face_builder_add_table (hb_face_t *face, + hb_tag_t tag, + hb_blob_t *blob); + + HB_END_DECLS #endif /* HB_FACE_H */ diff --git a/src/hb-face-private.hh b/src/hb-face.hh index 43e7b1c..68834ba 100644 --- a/src/hb-face-private.hh +++ b/src/hb-face.hh @@ -26,47 +26,48 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_FACE_PRIVATE_HH -#define HB_FACE_PRIVATE_HH +#ifndef HB_FACE_HH +#define HB_FACE_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-object-private.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" +#include "hb-shaper.hh" +#include "hb-shape-plan.hh" +#include "hb-ot-face.hh" /* * hb_face_t */ -struct hb_face_t { - hb_object_header_t header; - ASSERT_POD (); +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, face); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT - hb_bool_t immutable; +struct hb_face_t +{ + hb_object_header_t header; hb_reference_table_func_t reference_table_func; void *user_data; hb_destroy_func_t destroy; unsigned int index; /* Face index in a collection, zero-based. */ - mutable unsigned int upem; /* Units-per-EM. */ - mutable unsigned int num_glyphs; /* Number of glyphs. */ - - struct hb_shaper_data_t shaper_data; /* Various shaper data. */ + mutable hb_atomic_int_t upem; /* Units-per-EM. */ + mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */ - /* Various non-shaping data. */ - /* ... */ + hb_shaper_object_dataset_t<hb_face_t> data;/* Various shaper data. */ + hb_ot_face_t table; /* All the face's tables. */ /* Cache */ - struct plan_node_t { + struct plan_node_t + { hb_shape_plan_t *shape_plan; plan_node_t *next; - } *shape_plans; + }; + hb_atomic_ptr_t<plan_node_t> shape_plans; - - inline hb_blob_t *reference_table (hb_tag_t tag) const + hb_blob_t *reference_table (hb_tag_t tag) const { hb_blob_t *blob; @@ -80,32 +81,29 @@ struct hb_face_t { return blob; } - inline HB_PURE_FUNC unsigned int get_upem (void) const + HB_PURE_FUNC unsigned int get_upem () const { - if (unlikely (!upem)) - load_upem (); - return upem; + unsigned int ret = upem.get_relaxed (); + if (unlikely (!ret)) + { + return load_upem (); + } + return ret; } - inline unsigned int get_num_glyphs (void) const + unsigned int get_num_glyphs () const { - if (unlikely (num_glyphs == (unsigned int) -1)) - load_num_glyphs (); - return num_glyphs; + unsigned int ret = num_glyphs.get_relaxed (); + if (unlikely (ret == (unsigned int) -1)) + return load_num_glyphs (); + return ret; } private: - HB_INTERNAL void load_upem (void) const; - HB_INTERNAL void load_num_glyphs (void) const; + HB_INTERNAL unsigned int load_upem () const; + HB_INTERNAL unsigned int load_num_glyphs () const; }; - -extern HB_INTERNAL const hb_face_t _hb_face_nil; - -#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT -#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS +DECLARE_NULL_INSTANCE (hb_face_t); -#endif /* HB_FACE_PRIVATE_HH */ +#endif /* HB_FACE_HH */ diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc index 3f09c3f..09f0290 100644 --- a/src/hb-fallback-shape.cc +++ b/src/hb-fallback-shape.cc @@ -24,28 +24,23 @@ * Google Author(s): Behdad Esfahbod */ -#define HB_SHAPER fallback -#include "hb-shaper-impl-private.hh" - - -HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face) -HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font) +#include "hb-shaper-impl.hh" /* * shaper face data */ -struct hb_fallback_shaper_face_data_t {}; +struct hb_fallback_face_data_t {}; -hb_fallback_shaper_face_data_t * +hb_fallback_face_data_t * _hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED) { - return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return (hb_fallback_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED) +_hb_fallback_shaper_face_data_destroy (hb_fallback_face_data_t *data HB_UNUSED) { } @@ -54,38 +49,16 @@ _hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_U * shaper font data */ -struct hb_fallback_shaper_font_data_t {}; +struct hb_fallback_font_data_t {}; -hb_fallback_shaper_font_data_t * +hb_fallback_font_data_t * _hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED) { - return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; -} - -void -_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED) -{ -} - - -/* - * shaper shape_plan data - */ - -struct hb_fallback_shaper_shape_plan_data_t {}; - -hb_fallback_shaper_shape_plan_data_t * -_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return (hb_fallback_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED) +_hb_fallback_shaper_font_data_destroy (hb_fallback_font_data_t *data HB_UNUSED) { } diff --git a/src/hb-font.cc b/src/hb-font.cc index 4d62b9e..817a1a7 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -26,9 +26,25 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-font-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" + +#include "hb-ot.h" + + +/** + * SECTION:hb-font + * @title: hb-font + * @short_description: Font objects + * @include: hb.h + * + * Font objects represent a font face at a certain size and other + * parameters (pixels per EM, points per EM, variation settings.) + * Fonts are created from font faces, and are used as input to + * hb_shape() among other things. + **/ /* @@ -38,23 +54,23 @@ static hb_bool_t hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_font_extents_t *metrics, + hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (metrics, 0, sizeof (*metrics)); + memset (extents, 0, sizeof (*extents)); return false; } static hb_bool_t -hb_font_get_font_h_extents_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_font_extents_t *metrics, - void *user_data HB_UNUSED) +hb_font_get_font_h_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_font_extents_t *extents, + void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_font_h_extents (metrics); + hb_bool_t ret = font->parent->get_font_h_extents (extents); if (ret) { - metrics->ascender = font->parent_scale_y_distance (metrics->ascender); - metrics->descender = font->parent_scale_y_distance (metrics->descender); - metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap); + extents->ascender = font->parent_scale_y_distance (extents->ascender); + extents->descender = font->parent_scale_y_distance (extents->descender); + extents->line_gap = font->parent_scale_y_distance (extents->line_gap); } return ret; } @@ -62,23 +78,23 @@ hb_font_get_font_h_extents_parent (hb_font_t *font, static hb_bool_t hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_font_extents_t *metrics, + hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (metrics, 0, sizeof (*metrics)); + memset (extents, 0, sizeof (*extents)); return false; } static hb_bool_t -hb_font_get_font_v_extents_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_font_extents_t *metrics, - void *user_data HB_UNUSED) +hb_font_get_font_v_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_font_extents_t *extents, + void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_font_v_extents (metrics); + hb_bool_t ret = font->parent->get_font_v_extents (extents); if (ret) { - metrics->ascender = font->parent_scale_x_distance (metrics->ascender); - metrics->descender = font->parent_scale_x_distance (metrics->descender); - metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap); + extents->ascender = font->parent_scale_x_distance (extents->ascender); + extents->descender = font->parent_scale_x_distance (extents->descender); + extents->line_gap = font->parent_scale_x_distance (extents->line_gap); } return ret; } @@ -86,7 +102,7 @@ hb_font_get_font_v_extents_parent (hb_font_t *font, static hb_bool_t hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t unicode, + hb_codepoint_t unicode HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { @@ -94,20 +110,53 @@ hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_nominal_glyph_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t unicode, - hb_codepoint_t *glyph, - void *user_data HB_UNUSED) +hb_font_get_nominal_glyph_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) { + if (font->has_nominal_glyphs_func_set ()) + { + return font->get_nominal_glyphs (1, &unicode, 0, glyph, 0); + } return font->parent->get_nominal_glyph (unicode, glyph); } +#define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default +static unsigned int +hb_font_get_nominal_glyphs_default (hb_font_t *font, + void *font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) +{ + if (font->has_nominal_glyph_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + if (!font->get_nominal_glyph (*first_unicode, first_glyph)) + return i; + + first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + } + return count; + } + + return font->parent->get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); +} + static hb_bool_t hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, + hb_codepoint_t unicode HB_UNUSED, + hb_codepoint_t variation_selector HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { @@ -115,12 +164,12 @@ hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_variation_glyph_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, - hb_codepoint_t *glyph, - void *user_data HB_UNUSED) +hb_font_get_variation_glyph_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) { return font->parent->get_variation_glyph (unicode, variation_selector, glyph); } @@ -129,42 +178,118 @@ hb_font_get_variation_glyph_parent (hb_font_t *font, static hb_position_t hb_font_get_glyph_h_advance_nil (hb_font_t *font, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, void *user_data HB_UNUSED) { return font->x_scale; } static hb_position_t -hb_font_get_glyph_h_advance_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_advance_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) { + if (font->has_glyph_h_advances_func_set ()) + { + hb_position_t ret; + font->get_glyph_h_advances (1, &glyph, 0, &ret, 0); + return ret; + } return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); } static hb_position_t hb_font_get_glyph_v_advance_nil (hb_font_t *font, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, void *user_data HB_UNUSED) { /* TODO use font_extents.ascender+descender */ return font->y_scale; } static hb_position_t -hb_font_get_glyph_v_advance_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_advance_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) { + if (font->has_glyph_v_advances_func_set ()) + { + hb_position_t ret; + font->get_glyph_v_advances (1, &glyph, 0, &ret, 0); + return ret; + } return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); } +#define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default +static void +hb_font_get_glyph_h_advances_default (hb_font_t* font, + void* font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride, + void *user_data HB_UNUSED) +{ + if (font->has_glyph_h_advance_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->get_glyph_h_advance (*first_glyph); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } + return; + } + + font->parent->get_glyph_h_advances (count, + first_glyph, glyph_stride, + first_advance, advance_stride); + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->parent_scale_x_distance (*first_advance); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } +} + +#define hb_font_get_glyph_v_advances_nil hb_font_get_glyph_v_advances_default +static void +hb_font_get_glyph_v_advances_default (hb_font_t* font, + void* font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride, + void *user_data HB_UNUSED) +{ + if (font->has_glyph_v_advance_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->get_glyph_v_advance (*first_glyph); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } + return; + } + + font->parent->get_glyph_v_advances (count, + first_glyph, glyph_stride, + first_advance, advance_stride); + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->parent_scale_y_distance (*first_advance); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } +} + static hb_bool_t hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, hb_position_t *x, hb_position_t *y, void *user_data HB_UNUSED) @@ -173,12 +298,12 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, return true; } static hb_bool_t -hb_font_get_glyph_h_origin_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_origin_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); if (ret) @@ -189,7 +314,7 @@ hb_font_get_glyph_h_origin_parent (hb_font_t *font, static hb_bool_t hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, hb_position_t *x, hb_position_t *y, void *user_data HB_UNUSED) @@ -198,12 +323,12 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_glyph_v_origin_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_origin_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); if (ret) @@ -214,18 +339,18 @@ hb_font_get_glyph_v_origin_parent (hb_font_t *font, static hb_position_t hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, + hb_codepoint_t left_glyph HB_UNUSED, + hb_codepoint_t right_glyph HB_UNUSED, void *user_data HB_UNUSED) { return 0; } static hb_position_t -hb_font_get_glyph_h_kerning_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_kerning_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) { return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); } @@ -233,18 +358,18 @@ hb_font_get_glyph_h_kerning_parent (hb_font_t *font, static hb_position_t hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t top_glyph, - hb_codepoint_t bottom_glyph, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, void *user_data HB_UNUSED) { return 0; } static hb_position_t -hb_font_get_glyph_v_kerning_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t top_glyph, - hb_codepoint_t bottom_glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_kerning_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) { return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); } @@ -252,7 +377,7 @@ hb_font_get_glyph_v_kerning_parent (hb_font_t *font, static hb_bool_t hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { @@ -260,11 +385,11 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_glyph_extents_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_glyph_extents_t *extents, - void *user_data HB_UNUSED) +hb_font_get_glyph_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); if (ret) { @@ -277,8 +402,8 @@ hb_font_get_glyph_extents_parent (hb_font_t *font, static hb_bool_t hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t glyph, - unsigned int point_index, + hb_codepoint_t glyph HB_UNUSED, + unsigned int point_index HB_UNUSED, hb_position_t *x, hb_position_t *y, void *user_data HB_UNUSED) @@ -287,13 +412,13 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_glyph_contour_point_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - unsigned int point_index, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_contour_point_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); if (ret) @@ -304,7 +429,7 @@ hb_font_get_glyph_contour_point_parent (hb_font_t *font, static hb_bool_t hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - hb_codepoint_t glyph, + hb_codepoint_t glyph HB_UNUSED, char *name, unsigned int size, void *user_data HB_UNUSED) { @@ -312,11 +437,11 @@ hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_glyph_name_parent (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - char *name, unsigned int size, - void *user_data HB_UNUSED) +hb_font_get_glyph_name_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) { return font->parent->get_glyph_name (glyph, name, size); } @@ -324,7 +449,8 @@ hb_font_get_glyph_name_parent (hb_font_t *font, static hb_bool_t hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, - const char *name, int len, /* -1 means nul-terminated */ + const char *name HB_UNUSED, + int len HB_UNUSED, /* -1 means nul-terminated */ hb_codepoint_t *glyph, void *user_data HB_UNUSED) { @@ -332,20 +458,19 @@ hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED, return false; } static hb_bool_t -hb_font_get_glyph_from_name_parent (hb_font_t *font, - void *font_data HB_UNUSED, - const char *name, int len, /* -1 means nul-terminated */ - hb_codepoint_t *glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_from_name_default (hb_font_t *font, + void *font_data HB_UNUSED, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) { return font->parent->get_glyph_from_name (name, len, glyph); } -static const hb_font_funcs_t _hb_font_funcs_nil = { +DEFINE_NULL_INSTANCE (hb_font_funcs_t) = +{ HB_OBJECT_HEADER_STATIC, - true, /* immutable */ - { #define HB_FONT_FUNC_IMPLEMENT(name) nullptr, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS @@ -364,10 +489,9 @@ static const hb_font_funcs_t _hb_font_funcs_nil = { } } }; -static const hb_font_funcs_t _hb_font_funcs_parent = { - HB_OBJECT_HEADER_STATIC, - true, /* immutable */ +static const hb_font_funcs_t _hb_font_funcs_default = { + HB_OBJECT_HEADER_STATIC, { #define HB_FONT_FUNC_IMPLEMENT(name) nullptr, @@ -381,7 +505,7 @@ static const hb_font_funcs_t _hb_font_funcs_parent = { }, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent, +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -399,14 +523,14 @@ static const hb_font_funcs_t _hb_font_funcs_parent = { * Since: 0.9.2 **/ hb_font_funcs_t * -hb_font_funcs_create (void) +hb_font_funcs_create () { hb_font_funcs_t *ffuncs; if (!(ffuncs = hb_object_create<hb_font_funcs_t> ())) return hb_font_funcs_get_empty (); - ffuncs->get = _hb_font_funcs_parent.get; + ffuncs->get = _hb_font_funcs_default.get; return ffuncs; } @@ -421,9 +545,9 @@ hb_font_funcs_create (void) * Since: 0.9.2 **/ hb_font_funcs_t * -hb_font_funcs_get_empty (void) +hb_font_funcs_get_empty () { - return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent); + return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_default); } /** @@ -517,10 +641,10 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, void hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) { - if (unlikely (hb_object_is_inert (ffuncs))) + if (hb_object_is_immutable (ffuncs)) return; - ffuncs->immutable = true; + hb_object_make_immutable (ffuncs); } /** @@ -536,7 +660,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) hb_bool_t hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) { - return ffuncs->immutable; + return hb_object_is_immutable (ffuncs); } @@ -548,7 +672,7 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (ffuncs->immutable) { \ + if (hb_object_is_immutable (ffuncs)) { \ if (destroy) \ destroy (user_data); \ return; \ @@ -562,9 +686,9 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ ffuncs->user_data.name = user_data; \ ffuncs->destroy.name = destroy; \ } else { \ - ffuncs->get.f.name = hb_font_get_##name##_parent; \ - ffuncs->user_data.name = nullptr; \ - ffuncs->destroy.name = nullptr; \ + ffuncs->get.f.name = hb_font_get_##name##_default; \ + ffuncs->user_data.name = nullptr; \ + ffuncs->destroy.name = nullptr; \ } \ } @@ -572,11 +696,16 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT bool +hb_font_t::has_func_set (unsigned int i) +{ + return this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]; +} + +bool hb_font_t::has_func (unsigned int i) { - if (parent && parent != hb_font_get_empty () && parent->has_func (i)) - return true; - return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i]; + return has_func_set (i) || + (parent && parent != &_hb_Null_hb_font_t && parent->has_func (i)); } /* Public getters */ @@ -718,6 +847,43 @@ hb_font_get_glyph_v_advance (hb_font_t *font, } /** + * hb_font_get_glyph_h_advances: + * @font: a font. + * + * + * + * Since: 1.8.6 + **/ +void +hb_font_get_glyph_h_advances (hb_font_t* font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) +{ + font->get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); +} +/** + * hb_font_get_glyph_v_advances: + * @font: a font. + * + * + * + * Since: 1.8.6 + **/ +void +hb_font_get_glyph_v_advances (hb_font_t* font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) +{ + font->get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); +} + +/** * hb_font_get_glyph_h_origin: * @font: a font. * @glyph: @@ -770,6 +936,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font, * Return value: * * Since: 0.9.2 + * Deprecated: 2.0.0 **/ hb_position_t hb_font_get_glyph_h_kerning (hb_font_t *font, @@ -789,6 +956,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font, * Return value: * * Since: 0.9.2 + * Deprecated: 2.0.0 **/ hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, @@ -888,7 +1056,7 @@ hb_font_get_glyph_from_name (hb_font_t *font, * hb_font_get_extents_for_direction: * @font: a font. * @direction: - * @extents: + * @extents: (out): * * * @@ -921,6 +1089,26 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, { return font->get_glyph_advance_for_direction (glyph, direction, x, y); } +/** + * hb_font_get_glyph_advances_for_direction: + * @font: a font. + * @direction: + * + * + * + * Since: 1.8.6 + **/ +HB_EXTERN void +hb_font_get_glyph_advances_for_direction (hb_font_t* font, + hb_direction_t direction, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) +{ + font->get_glyph_advances_for_direction (direction, count, first_glyph, glyph_stride, first_advance, advance_stride); +} /** * hb_font_get_glyph_origin_for_direction: @@ -997,6 +1185,7 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, * * * Since: 0.9.2 + * Deprecated: 2.0.0 **/ void hb_font_get_glyph_kerning_for_direction (hb_font_t *font, @@ -1100,6 +1289,49 @@ hb_font_glyph_from_string (hb_font_t *font, * hb_font_t */ +DEFINE_NULL_INSTANCE (hb_font_t) = +{ + HB_OBJECT_HEADER_STATIC, + + nullptr, /* parent */ + const_cast<hb_face_t *> (&_hb_Null_hb_face_t), + + 1000, /* x_scale */ + 1000, /* y_scale */ + + 0, /* x_ppem */ + 0, /* y_ppem */ + 0, /* ptem */ + + 0, /* num_coords */ + nullptr, /* coords */ + + const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t), + + /* Zero for the rest is fine. */ +}; + + +static hb_font_t * +_hb_font_create (hb_face_t *face) +{ + hb_font_t *font; + + if (unlikely (!face)) + face = hb_face_get_empty (); + if (!(font = hb_object_create<hb_font_t> ())) + return hb_font_get_empty (); + + hb_face_make_immutable (face); + font->parent = hb_font_get_empty (); + font->face = hb_face_reference (face); + font->klass = hb_font_funcs_get_empty (); + font->data.init0 (font); + font->x_scale = font->y_scale = hb_face_get_upem (face); + + return font; +} + /** * hb_font_create: (Xconstructor) * @face: a face. @@ -1113,19 +1345,10 @@ hb_font_glyph_from_string (hb_font_t *font, hb_font_t * hb_font_create (hb_face_t *face) { - hb_font_t *font; - - if (unlikely (!face)) - face = hb_face_get_empty (); - if (!(font = hb_object_create<hb_font_t> ())) - return hb_font_get_empty (); + hb_font_t *font = _hb_font_create (face); - hb_face_make_immutable (face); - font->parent = hb_font_get_empty (); - font->face = hb_face_reference (face); - font->klass = hb_font_funcs_get_empty (); - - font->x_scale = font->y_scale = hb_face_get_upem (face); + /* Install our in-house, very lightweight, funcs. */ + hb_ot_font_set_funcs (font); return font; } @@ -1146,9 +1369,9 @@ hb_font_create_sub_font (hb_font_t *parent) if (unlikely (!parent)) parent = hb_font_get_empty (); - hb_font_t *font = hb_font_create (parent->face); + hb_font_t *font = _hb_font_create (parent->face); - if (unlikely (hb_object_is_inert (font))) + if (unlikely (hb_object_is_immutable (font))) return font; font->parent = hb_font_reference (parent); @@ -1185,38 +1408,9 @@ hb_font_create_sub_font (hb_font_t *parent) * Since: 0.9.2 **/ hb_font_t * -hb_font_get_empty (void) +hb_font_get_empty () { - static const hb_font_t _hb_font_nil = { - HB_OBJECT_HEADER_STATIC, - - true, /* immutable */ - - nullptr, /* parent */ - const_cast<hb_face_t *> (&_hb_face_nil), - - 1000, /* x_scale */ - 1000, /* y_scale */ - - 0, /* x_ppem */ - 0, /* y_ppem */ - 0, /* ptem */ - - 0, /* num_coords */ - nullptr, /* coords */ - - const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */ - nullptr, /* user_data */ - nullptr, /* destroy */ - - { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - } - }; - - return const_cast<hb_font_t *> (&_hb_font_nil); + return const_cast<hb_font_t *> (&Null(hb_font_t)); } /** @@ -1248,9 +1442,7 @@ hb_font_destroy (hb_font_t *font) { if (!hb_object_destroy (font)) return; -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT + font->data.fini (); if (font->destroy) font->destroy (font->user_data); @@ -1317,13 +1509,13 @@ hb_font_get_user_data (hb_font_t *font, void hb_font_make_immutable (hb_font_t *font) { - if (unlikely (hb_object_is_inert (font))) + if (hb_object_is_immutable (font)) return; if (font->parent) hb_font_make_immutable (font->parent); - font->immutable = true; + hb_object_make_immutable (font); } /** @@ -1339,7 +1531,7 @@ hb_font_make_immutable (hb_font_t *font) hb_bool_t hb_font_is_immutable (hb_font_t *font) { - return font->immutable; + return hb_object_is_immutable (font); } /** @@ -1355,7 +1547,7 @@ void hb_font_set_parent (hb_font_t *font, hb_font_t *parent) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; if (!parent) @@ -1397,7 +1589,7 @@ void hb_font_set_face (hb_font_t *font, hb_face_t *face) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; if (unlikely (!face)) @@ -1444,7 +1636,8 @@ hb_font_set_funcs (hb_font_t *font, void *font_data, hb_destroy_func_t destroy) { - if (font->immutable) { + if (hb_object_is_immutable (font)) + { if (destroy) destroy (font_data); return; @@ -1479,7 +1672,8 @@ hb_font_set_funcs_data (hb_font_t *font, hb_destroy_func_t destroy) { /* Destroy user_data? */ - if (font->immutable) { + if (hb_object_is_immutable (font)) + { if (destroy) destroy (font_data); return; @@ -1508,7 +1702,7 @@ hb_font_set_scale (hb_font_t *font, int x_scale, int y_scale) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; font->x_scale = x_scale; @@ -1549,7 +1743,7 @@ hb_font_set_ppem (hb_font_t *font, unsigned int x_ppem, unsigned int y_ppem) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; font->x_ppem = x_ppem; @@ -1578,16 +1772,18 @@ hb_font_get_ppem (hb_font_t *font, /** * hb_font_set_ptem: * @font: a font. - * @ptem: + * @ptem: font size in points. * - * Sets "point size" of the font. + * Sets "point size" of the font. Set to 0 to unset. + * + * There are 72 points in an inch. * * Since: 1.6.0 **/ void hb_font_set_ptem (hb_font_t *font, float ptem) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; font->ptem = ptem; @@ -1634,7 +1830,7 @@ hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; if (!variations_length) @@ -1665,7 +1861,7 @@ hb_font_set_var_coords_design (hb_font_t *font, const float *coords, unsigned int coords_length) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr; @@ -1686,7 +1882,7 @@ hb_font_set_var_coords_normalized (hb_font_t *font, const int *coords, /* 2.14 normalized */ unsigned int coords_length) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr; @@ -1718,8 +1914,6 @@ hb_font_get_var_coords_normalized (hb_font_t *font, } -#ifndef HB_DISABLE_DEPRECATED - /* * Deprecated get_glyph_func(): */ @@ -1806,9 +2000,9 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font, /** * hb_font_funcs_set_glyph_func: * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @func: (closure user_data) (destroy destroy) (scope notified): callback function. + * @user_data: data to pass to @func. + * @destroy: function to call when @user_data is not needed anymore. * * Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and * hb_font_funcs_set_variation_glyph_func() instead. @@ -1842,5 +2036,3 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline, trampoline_destroy); } - -#endif /* HB_DISABLE_DEPRECATED */ diff --git a/src/hb-font.h b/src/hb-font.h index c95b61d..e2086d8 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -110,7 +110,7 @@ typedef struct hb_glyph_extents_t /* func types */ typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data, - hb_font_extents_t *metrics, + hb_font_extents_t *extents, void *user_data); typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t; typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t; @@ -125,6 +125,14 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void * hb_codepoint_t *glyph, void *user_data); +typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data); + typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -132,6 +140,16 @@ typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t; typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t; +typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data); +typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t; +typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t; + typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, @@ -139,12 +157,6 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; -typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - void *user_data); -typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; -typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; - typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -217,6 +229,22 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); /** + * hb_font_funcs_set_nominal_glyphs_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 2.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs, + hb_font_get_nominal_glyphs_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** * hb_font_funcs_set_variation_glyph_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): @@ -265,7 +293,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_h_origin_func: + * hb_font_funcs_set_glyph_h_advances_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: @@ -273,15 +301,15 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, * * * - * Since: 0.9.2 + * Since: 1.8.6 **/ HB_EXTERN void -hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_h_origin_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_advances_func_t func, + void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_v_origin_func: + * hb_font_funcs_set_glyph_v_advances_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: @@ -289,15 +317,15 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, * * * - * Since: 0.9.2 + * Since: 1.8.6 **/ HB_EXTERN void -hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_v_origin_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_advances_func_t func, + void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_h_kerning_func: + * hb_font_funcs_set_glyph_h_origin_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: @@ -308,12 +336,12 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, * Since: 0.9.2 **/ HB_EXTERN void -hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_h_kerning_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_v_kerning_func: + * hb_font_funcs_set_glyph_v_origin_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: @@ -324,9 +352,9 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, * Since: 0.9.2 **/ HB_EXTERN void -hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_v_kerning_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_extents_func: @@ -417,6 +445,21 @@ HB_EXTERN hb_position_t hb_font_get_glyph_v_advance (hb_font_t *font, hb_codepoint_t glyph); +HB_EXTERN void +hb_font_get_glyph_h_advances (hb_font_t* font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride); +HB_EXTERN void +hb_font_get_glyph_v_advances (hb_font_t* font, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride); + HB_EXTERN hb_bool_t hb_font_get_glyph_h_origin (hb_font_t *font, hb_codepoint_t glyph, @@ -426,13 +469,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y); -HB_EXTERN hb_position_t -hb_font_get_glyph_h_kerning (hb_font_t *font, - hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); -HB_EXTERN hb_position_t -hb_font_get_glyph_v_kerning (hb_font_t *font, - hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); - HB_EXTERN hb_bool_t hb_font_get_glyph_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -472,6 +508,14 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, hb_direction_t direction, hb_position_t *x, hb_position_t *y); HB_EXTERN void +hb_font_get_glyph_advances_for_direction (hb_font_t* font, + hb_direction_t direction, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride); +HB_EXTERN void hb_font_get_glyph_origin_for_direction (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, @@ -487,12 +531,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, hb_direction_t direction, hb_position_t *x, hb_position_t *y); -HB_EXTERN void -hb_font_get_glyph_kerning_for_direction (hb_font_t *font, - hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y); - HB_EXTERN hb_bool_t hb_font_get_glyph_extents_for_origin (hb_font_t *font, hb_codepoint_t glyph, diff --git a/src/hb-font-private.hh b/src/hb-font.hh index 7ba16cd..aaa0fd9 100644 --- a/src/hb-font-private.hh +++ b/src/hb-font.hh @@ -26,15 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_FONT_PRIVATE_HH -#define HB_FONT_PRIVATE_HH +#ifndef HB_FONT_HH +#define HB_FONT_HH -#include "hb-private.hh" - -#include "hb-object-private.hh" -#include "hb-face-private.hh" -#include "hb-shaper-private.hh" +#include "hb.hh" +#include "hb-face.hh" +#include "hb-shaper.hh" /* @@ -45,9 +43,12 @@ HB_FONT_FUNC_IMPLEMENT (font_h_extents) \ HB_FONT_FUNC_IMPLEMENT (font_v_extents) \ HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \ + HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \ HB_FONT_FUNC_IMPLEMENT (variation_glyph) \ HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \ HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ @@ -58,11 +59,9 @@ HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ /* ^--- Add new callbacks here */ -struct hb_font_funcs_t { +struct hb_font_funcs_t +{ hb_object_header_t header; - ASSERT_POD (); - - hb_bool_t immutable; struct { #define HB_FONT_FUNC_IMPLEMENT(name) void *name; @@ -87,21 +86,23 @@ struct hb_font_funcs_t { #define HB_FONT_FUNC_IMPLEMENT(name) +1 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT - ]) (void); + ]) (); } get; }; - +DECLARE_NULL_INSTANCE (hb_font_funcs_t); /* * hb_font_t */ -struct hb_font_t { - hb_object_header_t header; - ASSERT_POD (); +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, font); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT - hb_bool_t immutable; +struct hb_font_t +{ + hb_object_header_t header; hb_font_t *parent; hb_face_t *face; @@ -122,44 +123,46 @@ struct hb_font_t { void *user_data; hb_destroy_func_t destroy; - struct hb_shaper_data_t shaper_data; + hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */ /* Convert from font-space to user-space */ - inline int dir_scale (hb_direction_t direction) + int dir_scale (hb_direction_t direction) { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; } - inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); } - inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); } - inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); } - inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); } - inline float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } - inline float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } - inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) + hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); } + hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); } + hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); } + hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); } + float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } + float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } + hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) { return em_scale (v, dir_scale (direction)); } /* Convert from parent-font user-space to our user-space */ - inline hb_position_t parent_scale_x_distance (hb_position_t v) { + hb_position_t parent_scale_x_distance (hb_position_t v) + { if (unlikely (parent && parent->x_scale != x_scale)) return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale); return v; } - inline hb_position_t parent_scale_y_distance (hb_position_t v) { + hb_position_t parent_scale_y_distance (hb_position_t v) + { if (unlikely (parent && parent->y_scale != y_scale)) return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale); return v; } - inline hb_position_t parent_scale_x_position (hb_position_t v) { - return parent_scale_x_distance (v); - } - inline hb_position_t parent_scale_y_position (hb_position_t v) { - return parent_scale_y_distance (v); - } + hb_position_t parent_scale_x_position (hb_position_t v) + { return parent_scale_x_distance (v); } + hb_position_t parent_scale_y_position (hb_position_t v) + { return parent_scale_y_distance (v); } - inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) { + void parent_scale_distance (hb_position_t *x, hb_position_t *y) + { *x = parent_scale_x_distance (*x); *y = parent_scale_y_distance (*y); } - inline void parent_scale_position (hb_position_t *x, hb_position_t *y) { + void parent_scale_position (hb_position_t *x, hb_position_t *y) + { *x = parent_scale_x_position (*x); *y = parent_scale_y_position (*y); } @@ -168,27 +171,35 @@ struct hb_font_t { /* Public getters */ HB_INTERNAL bool has_func (unsigned int i); + HB_INTERNAL bool has_func_set (unsigned int i); /* has_* ... */ #define HB_FONT_FUNC_IMPLEMENT(name) \ bool \ - has_##name##_func (void) \ + has_##name##_func () \ { \ hb_font_funcs_t *funcs = this->klass; \ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \ return has_func (i); \ + } \ + bool \ + has_##name##_func_set () \ + { \ + hb_font_funcs_t *funcs = this->klass; \ + unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \ + return has_func_set (i); \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT - inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents) + hb_bool_t get_font_h_extents (hb_font_extents_t *extents) { memset (extents, 0, sizeof (*extents)); return klass->get.f.font_h_extents (this, user_data, extents, klass->user_data.font_h_extents); } - inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents) + hb_bool_t get_font_v_extents (hb_font_extents_t *extents) { memset (extents, 0, sizeof (*extents)); return klass->get.f.font_v_extents (this, user_data, @@ -196,13 +207,13 @@ struct hb_font_t { klass->user_data.font_v_extents); } - inline bool has_glyph (hb_codepoint_t unicode) + bool has_glyph (hb_codepoint_t unicode) { hb_codepoint_t glyph; return get_nominal_glyph (unicode, &glyph); } - inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode, + hb_bool_t get_nominal_glyph (hb_codepoint_t unicode, hb_codepoint_t *glyph) { *glyph = 0; @@ -210,9 +221,21 @@ struct hb_font_t { unicode, glyph, klass->user_data.nominal_glyph); } + unsigned int get_nominal_glyphs (unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) + { + return klass->get.f.nominal_glyphs (this, user_data, + count, + first_unicode, unicode_stride, + first_glyph, glyph_stride, + klass->user_data.nominal_glyphs); + } - inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) + hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) { *glyph = 0; return klass->get.f.variation_glyph (this, user_data, @@ -220,21 +243,47 @@ struct hb_font_t { klass->user_data.variation_glyph); } - inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) + hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) { return klass->get.f.glyph_h_advance (this, user_data, glyph, klass->user_data.glyph_h_advance); } - inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) + hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) { return klass->get.f.glyph_v_advance (this, user_data, glyph, klass->user_data.glyph_v_advance); } - inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, + void get_glyph_h_advances (unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride) + { + return klass->get.f.glyph_h_advances (this, user_data, + count, + first_glyph, glyph_stride, + first_advance, advance_stride, + klass->user_data.glyph_h_advances); + } + + void get_glyph_v_advances (unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride) + { + return klass->get.f.glyph_v_advances (this, user_data, + count, + first_glyph, glyph_stride, + first_advance, advance_stride, + klass->user_data.glyph_v_advances); + } + + hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { *x = *y = 0; @@ -243,8 +292,8 @@ struct hb_font_t { klass->user_data.glyph_h_origin); } - inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { *x = *y = 0; return klass->get.f.glyph_v_origin (this, user_data, @@ -252,21 +301,23 @@ struct hb_font_t { klass->user_data.glyph_v_origin); } - inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) + hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph) { return klass->get.f.glyph_h_kerning (this, user_data, left_glyph, right_glyph, klass->user_data.glyph_h_kerning); } - inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) + hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph) { return klass->get.f.glyph_v_kerning (this, user_data, top_glyph, bottom_glyph, klass->user_data.glyph_v_kerning); } - inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph, + hb_bool_t get_glyph_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) { memset (extents, 0, sizeof (*extents)); @@ -276,7 +327,7 @@ struct hb_font_t { klass->user_data.glyph_extents); } - inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, + hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y) { *x = *y = 0; @@ -286,8 +337,8 @@ struct hb_font_t { klass->user_data.glyph_contour_point); } - inline hb_bool_t get_glyph_name (hb_codepoint_t glyph, - char *name, unsigned int size) + hb_bool_t get_glyph_name (hb_codepoint_t glyph, + char *name, unsigned int size) { if (size) *name = '\0'; return klass->get.f.glyph_name (this, user_data, @@ -296,8 +347,8 @@ struct hb_font_t { klass->user_data.glyph_name); } - inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */ - hb_codepoint_t *glyph) + hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) { *glyph = 0; if (len == -1) len = strlen (name); @@ -310,7 +361,7 @@ struct hb_font_t { /* A bit higher-level, and with fallback */ - inline void get_h_extents_with_fallback (hb_font_extents_t *extents) + void get_h_extents_with_fallback (hb_font_extents_t *extents) { if (!get_font_h_extents (extents)) { @@ -319,7 +370,7 @@ struct hb_font_t { extents->line_gap = 0; } } - inline void get_v_extents_with_fallback (hb_font_extents_t *extents) + void get_v_extents_with_fallback (hb_font_extents_t *extents) { if (!get_font_v_extents (extents)) { @@ -329,8 +380,8 @@ struct hb_font_t { } } - inline void get_extents_for_direction (hb_direction_t direction, - hb_font_extents_t *extents) + void get_extents_for_direction (hb_direction_t direction, + hb_font_extents_t *extents) { if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) get_h_extents_with_fallback (extents); @@ -338,21 +389,31 @@ struct hb_font_t { get_v_extents_with_fallback (extents); } - inline void get_glyph_advance_for_direction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + void get_glyph_advance_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { - if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + *x = *y = 0; + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) *x = get_glyph_h_advance (glyph); - *y = 0; - } else { - *x = 0; + else *y = get_glyph_v_advance (glyph); - } + } + void get_glyph_advances_for_direction (hb_direction_t direction, + unsigned int count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); + else + get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); } - inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void guess_v_origin_minus_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { *x = get_glyph_h_advance (glyph) / 2; @@ -362,8 +423,8 @@ struct hb_font_t { *y = extents.ascender; } - inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { if (!get_glyph_h_origin (glyph, x, y) && get_glyph_v_origin (glyph, x, y)) @@ -373,8 +434,8 @@ struct hb_font_t { *x -= dx; *y -= dy; } } - inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { if (!get_glyph_v_origin (glyph, x, y) && get_glyph_h_origin (glyph, x, y)) @@ -385,9 +446,9 @@ struct hb_font_t { } } - inline void get_glyph_origin_for_direction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + void get_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) get_glyph_h_origin_with_fallback (glyph, x, y); @@ -395,8 +456,8 @@ struct hb_font_t { get_glyph_v_origin_with_fallback (glyph, x, y); } - inline void add_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void add_glyph_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -405,8 +466,8 @@ struct hb_font_t { *x += origin_x; *y += origin_y; } - inline void add_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void add_glyph_v_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -415,9 +476,9 @@ struct hb_font_t { *x += origin_x; *y += origin_y; } - inline void add_glyph_origin_for_direction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + void add_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -427,8 +488,8 @@ struct hb_font_t { *y += origin_y; } - inline void subtract_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void subtract_glyph_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -437,8 +498,8 @@ struct hb_font_t { *x -= origin_x; *y -= origin_y; } - inline void subtract_glyph_v_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + void subtract_glyph_v_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -447,9 +508,9 @@ struct hb_font_t { *x -= origin_x; *y -= origin_y; } - inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + void subtract_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; @@ -459,22 +520,22 @@ struct hb_font_t { *y -= origin_y; } - inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { - *x = get_glyph_h_kerning (first_glyph, second_glyph); *y = 0; + *x = get_glyph_h_kerning (first_glyph, second_glyph); } else { *x = 0; *y = get_glyph_v_kerning (first_glyph, second_glyph); } } - inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph, - hb_direction_t direction, - hb_glyph_extents_t *extents) + hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents) { hb_bool_t ret = get_glyph_extents (glyph, extents); @@ -484,9 +545,9 @@ struct hb_font_t { return ret; } - inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) + hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y); @@ -497,7 +558,7 @@ struct hb_font_t { } /* Generates gidDDD if glyph has no name. */ - inline void + void glyph_to_string (hb_codepoint_t glyph, char *s, unsigned int size) { @@ -508,7 +569,7 @@ struct hb_font_t { } /* Parses gidDDD and uniUUUU strings automatically. */ - inline hb_bool_t + hb_bool_t glyph_from_string (const char *s, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph) { @@ -538,28 +599,19 @@ struct hb_font_t { return false; } - inline hb_position_t em_scale (int16_t v, int scale) + hb_position_t em_scale (int16_t v, int scale) { int upem = face->get_upem (); int64_t scaled = v * (int64_t) scale; scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */ return (hb_position_t) (scaled / upem); } - inline hb_position_t em_scalef (float v, int scale) - { - return (hb_position_t) round (v * scale / face->get_upem ()); - } - inline float em_fscale (int16_t v, int scale) - { - return (float) v * scale / face->get_upem (); - } + hb_position_t em_scalef (float v, int scale) + { return (hb_position_t) round (v * scale / face->get_upem ()); } + float em_fscale (int16_t v, int scale) + { return (float) v * scale / face->get_upem (); } }; - -#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT -#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS +DECLARE_NULL_INSTANCE (hb_font_t); -#endif /* HB_FONT_PRIVATE_HH */ +#endif /* HB_FONT_HH */ diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 7caafba..1900f30 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -27,47 +27,58 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-debug.hh" +#include "hb.hh" #include "hb-ft.h" -#include "hb-font-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" +#include "hb-cache.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_TRUETYPE_TABLES_H +/** + * SECTION:hb-ft + * @title: hb-ft + * @short_description: FreeType integration + * @include: hb-ft.h + * + * Functions for using HarfBuzz with the FreeType library to provide face and + * font data. + **/ + + /* TODO: * * In general, this file does a fine job of what it's supposed to do. * There are, however, things that need more work: * - * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. - * Have not investigated. - * * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything * would work fine. However, we also abuse this API for performing in font-space, * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode * for that, such that no rounding etc happens. As such, we don't set ppem, and * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale - * ourselves, like we do in uniscribe, etc. + * ourselves. * * - We don't handle / allow for emboldening / obliqueing. * * - In the future, we should add constructors to create fonts in font space? - * - * - FT_Load_Glyph() is extremely costly. Do something about it? */ struct hb_ft_font_t { + mutable hb_mutex_t lock; FT_Face ft_face; int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + + mutable hb_atomic_int_t cached_x_scale; + mutable hb_advance_cache_t advance_cache; }; static hb_ft_font_t * @@ -78,12 +89,16 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) if (unlikely (!ft_font)) return nullptr; + ft_font->lock.init (); ft_font->ft_face = ft_face; ft_font->symbol = symbol; ft_font->unref = unref; ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + ft_font->cached_x_scale.set (0); + ft_font->advance_cache.init (); + return ft_font; } @@ -98,9 +113,13 @@ _hb_ft_font_destroy (void *data) { hb_ft_font_t *ft_font = (hb_ft_font_t *) data; + ft_font->advance_cache.fini (); + if (ft_font->unref) _hb_ft_face_destroy (ft_font->ft_face); + ft_font->lock.fini (); + free (ft_font); } @@ -116,7 +135,7 @@ _hb_ft_font_destroy (void *data) void hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) { - if (font->immutable) + if (hb_object_is_immutable (font)) return; if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) @@ -168,6 +187,7 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode); if (unlikely (!g)) @@ -191,6 +211,32 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, return true; } +static unsigned int +hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED, + void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + unsigned int done; + for (done = 0; + done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode)); + done++) + { + first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + } + /* We don't need to do ft_font->symbol dance here, since HB calls the singular + * nominal_glyph() for what we don't handle here. */ + return done; +} + + static hb_bool_t hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, void *font_data, @@ -200,6 +246,7 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); if (unlikely (!g)) @@ -209,22 +256,45 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, return true; } -static hb_position_t -hb_ft_get_glyph_h_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; - FT_Fixed v; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + int load_flags = ft_font->load_flags; + int mult = font->x_scale < 0 ? -1 : +1; - if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) - return 0; + if (font->x_scale != ft_font->cached_x_scale.get ()) + { + ft_font->advance_cache.clear (); + ft_font->cached_x_scale.set (font->x_scale); + } - if (font->x_scale < 0) - v = -v; + for (unsigned int i = 0; i < count; i++) + { + FT_Fixed v = 0; + hb_codepoint_t glyph = *first_glyph; - return (v + (1<<9)) >> 10; + unsigned int cv; + if (ft_font->advance_cache.get (glyph, &cv)) + v = cv; + else + { + FT_Get_Advance (ft_face, glyph, load_flags, &v); + ft_font->advance_cache.set (glyph, v); + } + + *first_advance = (v * mult + (1<<9)) >> 10; + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } } static hb_position_t @@ -234,6 +304,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Fixed v; if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) @@ -256,6 +327,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -274,23 +346,6 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, return true; } -static hb_position_t -hb_ft_get_glyph_h_kerning (hb_font_t *font, - void *font_data, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, - void *user_data HB_UNUSED) -{ - const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; - FT_Vector kerningv; - - FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; - if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) - return 0; - - return kerningv.x; -} - static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font, void *font_data, @@ -299,6 +354,7 @@ hb_ft_get_glyph_extents (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -331,6 +387,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -356,8 +413,10 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; - hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); + hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); if (ret && (size && !*name)) ret = false; @@ -372,6 +431,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (len < 0) @@ -404,10 +464,11 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; - metrics->ascender = ft_face->size->metrics.ascender; - metrics->descender = ft_face->size->metrics.descender; - metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender); + metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); + metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); + metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); if (font->y_scale < 0) { metrics->ascender = -metrics->ascender; @@ -417,41 +478,25 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, return true; } -static hb_font_funcs_t *static_ft_funcs = nullptr; - -#ifdef HB_USE_ATEXIT -static -void free_static_ft_funcs (void) -{ -retry: - hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr)) - goto retry; - - hb_font_funcs_destroy (ft_funcs); -} +#if HB_USE_ATEXIT +static void free_static_ft_funcs (); #endif -static void -_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) +static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t> { -retry: - hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs); - - if (unlikely (!funcs)) + static hb_font_funcs_t *create () { - funcs = hb_font_funcs_create (); + hb_font_funcs_t *funcs = hb_font_funcs_create (); hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr); hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr); //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr); - //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr); hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr); hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr); hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr); @@ -459,20 +504,35 @@ retry: hb_font_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) { - hb_font_funcs_destroy (funcs); - goto retry; - } +#if HB_USE_ATEXIT + atexit (free_static_ft_funcs); +#endif -#ifdef HB_USE_ATEXIT - atexit (free_static_ft_funcs); /* First person registers atexit() callback. */ + return funcs; + } +} static_ft_funcs; + +#if HB_USE_ATEXIT +static +void free_static_ft_funcs () +{ + static_ft_funcs.free_instance (); +} #endif - }; +static hb_font_funcs_t * +_hb_ft_get_font_funcs () +{ + return static_ft_funcs.get_unconst (); +} + +static void +_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) +{ bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL; hb_font_set_funcs (font, - funcs, + _hb_ft_get_font_funcs (), _hb_ft_font_create (ft_face, symbol, unref), _hb_ft_font_destroy); } @@ -498,7 +558,10 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); if (error) + { + free (buffer); return nullptr; + } return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, @@ -681,47 +744,47 @@ hb_ft_font_create_referenced (FT_Face ft_face) return hb_ft_font_create (ft_face, _hb_ft_face_destroy); } +#if HB_USE_ATEXIT +static void free_static_ft_library (); +#endif -/* Thread-safe, lock-free, FT_Library */ +static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library), + hb_ft_library_lazy_loader_t> +{ + static FT_Library create () + { + FT_Library l; + if (FT_Init_FreeType (&l)) + return nullptr; -static FT_Library ft_library; +#if HB_USE_ATEXIT + atexit (free_static_ft_library); +#endif -#ifdef HB_USE_ATEXIT + return l; + } + static void destroy (FT_Library l) + { + FT_Done_FreeType (l); + } + static FT_Library get_null () + { + return nullptr; + } +} static_ft_library; + +#if HB_USE_ATEXIT static -void free_ft_library (void) +void free_static_ft_library () { -retry: - FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); - if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr)) - goto retry; - - FT_Done_FreeType (library); + static_ft_library.free_instance (); } #endif static FT_Library -get_ft_library (void) +get_ft_library () { -retry: - FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); - - if (unlikely (!library)) - { - /* Not found; allocate one. */ - if (FT_Init_FreeType (&library)) - return nullptr; - - if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) { - FT_Done_FreeType (library); - goto retry; - } - -#ifdef HB_USE_ATEXIT - atexit (free_ft_library); /* First person registers atexit() callback. */ -#endif - } - - return library; + return static_ft_library.get_unconst (); } static void diff --git a/src/hb-glib.cc b/src/hb-glib.cc index 246380a..5763754 100644 --- a/src/hb-glib.cc +++ b/src/hb-glib.cc @@ -26,11 +26,21 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-glib.h" -#include "hb-unicode-private.hh" +#include "hb-machinery.hh" + + +/** + * SECTION:hb-glib + * @title: hb-glib + * @short_description: GLib integration + * @include: hb-glib.h + * + * Functions for using HarfBuzz with the GLib library to provide Unicode data. + **/ #if !GLIB_CHECK_VERSION(2,29,14) @@ -201,14 +211,6 @@ hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode); } -static unsigned int -hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return g_unichar_iswide (unicode) ? 2 : 1; -} - static hb_unicode_general_category_t hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -333,81 +335,49 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, return ret; } -static unsigned int -hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ -#if GLIB_CHECK_VERSION(2,29,12) - return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN); -#endif - - /* If the user doesn't have GLib >= 2.29.12 we have to perform - * a round trip to UTF-8 and the associated memory management dance. */ - gchar utf8[6]; - gchar *utf8_decomposed, *c; - gsize utf8_len, utf8_decomposed_len, i; - /* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */ - utf8_len = g_unichar_to_utf8 (u, utf8); - utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD); - utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1); +#if HB_USE_ATEXIT +static void free_static_glib_funcs (); +#endif - assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN); +static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t> +{ + static hb_unicode_funcs_t *create () + { + hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); - for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c)) - *decomposed++ = g_utf8_get_char (c); + hb_unicode_funcs_set_combining_class_func (funcs, hb_glib_unicode_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_glib_unicode_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_glib_unicode_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_glib_unicode_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_glib_unicode_compose, nullptr, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_glib_unicode_decompose, nullptr, nullptr); - g_free (utf8_decomposed); + hb_unicode_funcs_make_immutable (funcs); - return utf8_decomposed_len; -} +#if HB_USE_ATEXIT + atexit (free_static_glib_funcs); +#endif -static hb_unicode_funcs_t *static_glib_funcs = nullptr; + return funcs; + } +} static_glib_funcs; -#ifdef HB_USE_ATEXIT +#if HB_USE_ATEXIT static -void free_static_glib_funcs (void) +void free_static_glib_funcs () { -retry: - hb_unicode_funcs_t *glib_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs); - if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, glib_funcs, nullptr)) - goto retry; - - hb_unicode_funcs_destroy (glib_funcs); + static_glib_funcs.free_instance (); } #endif hb_unicode_funcs_t * -hb_glib_get_unicode_funcs (void) +hb_glib_get_unicode_funcs () { -retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs); - - if (unlikely (!funcs)) - { - funcs = hb_unicode_funcs_create (nullptr); - -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT - - hb_unicode_funcs_make_immutable (funcs); - - if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, nullptr, funcs)) { - hb_unicode_funcs_destroy (funcs); - goto retry; - } + return static_glib_funcs.get_unconst (); +} -#ifdef HB_USE_ATEXIT - atexit (free_static_glib_funcs); /* First person registers atexit() callback. */ -#endif - }; - return hb_unicode_funcs_reference (funcs); -} #if GLIB_CHECK_VERSION(2,31,10) diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl index ca458a3..e3a9a6b 100644 --- a/src/hb-gobject-enums.cc.tmpl +++ b/src/hb-gobject-enums.cc.tmpl @@ -25,7 +25,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" /* g++ didn't like older gtype.h gcc-only code path. */ #include <glib.h> @@ -46,7 +46,7 @@ /*** BEGIN value-header ***/ GType -@enum_name@_get_type (void) +@enum_name@_get_type () { static gsize type_id = 0; diff --git a/src/hb-gobject-enums.h.tmpl b/src/hb-gobject-enums.h.tmpl index 606727c..7ef9dfc 100644 --- a/src/hb-gobject-enums.h.tmpl +++ b/src/hb-gobject-enums.h.tmpl @@ -43,7 +43,7 @@ HB_BEGIN_DECLS /*** BEGIN value-header ***/ HB_EXTERN GType -@enum_name@_get_type (void) G_GNUC_CONST; +@enum_name@_get_type () G_GNUC_CONST; #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) /*** END value-header ***/ diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc index a96c358..3cff880 100644 --- a/src/hb-gobject-structs.cc +++ b/src/hb-gobject-structs.cc @@ -24,7 +24,19 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" + + +/** + * SECTION:hb-gobject + * @title: hb-gobject + * @short_description: GObject integration + * @include: hb-gobject.h + * + * Functions for using HarfBuzz with the GObject library to provide + * type data. + **/ + /* g++ didn't like older gtype.h gcc-only code path. */ #include <glib.h> @@ -39,7 +51,7 @@ #define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \ GType \ -hb_gobject_##name##_get_type (void) \ +hb_gobject_##name##_get_type () \ { \ static gsize type_id = 0; \ if (g_once_init_enter (&type_id)) { \ @@ -52,7 +64,7 @@ hb_gobject_##name##_get_type (void) \ } #define HB_DEFINE_OBJECT_TYPE(name) \ - HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy); + HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy) #define HB_DEFINE_VALUE_TYPE(name) \ static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \ @@ -63,7 +75,7 @@ hb_gobject_##name##_get_type (void) \ return c; \ } \ static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \ - HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy); + HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy) HB_DEFINE_OBJECT_TYPE (buffer) HB_DEFINE_OBJECT_TYPE (blob) @@ -71,6 +83,7 @@ HB_DEFINE_OBJECT_TYPE (face) HB_DEFINE_OBJECT_TYPE (font) HB_DEFINE_OBJECT_TYPE (font_funcs) HB_DEFINE_OBJECT_TYPE (set) +HB_DEFINE_OBJECT_TYPE (map) HB_DEFINE_OBJECT_TYPE (shape_plan) HB_DEFINE_OBJECT_TYPE (unicode_funcs) HB_DEFINE_VALUE_TYPE (feature) diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h index 302dc95..800beed 100644 --- a/src/hb-gobject-structs.h +++ b/src/hb-gobject-structs.h @@ -90,6 +90,10 @@ hb_gobject_set_get_type (void); #define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ()) HB_EXTERN GType +hb_gobject_map_get_type (void); +#define HB_GOBJECT_TYPE_MAP (hb_gobject_map_get_type ()) + +HB_EXTERN GType hb_gobject_shape_plan_get_type (void); #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ()) diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index c20f6be..a1c602c 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -26,37 +26,46 @@ * Google Author(s): Behdad Esfahbod */ -#define HB_SHAPER graphite2 -#include "hb-shaper-impl-private.hh" +#include "hb-shaper-impl.hh" #include "hb-graphite2.h" #include <graphite2/Segment.h> +#include "hb-ot-layout.h" -HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face) -HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font) + +/** + * SECTION:hb-graphite2 + * @title: hb-graphite2 + * @short_description: Graphite2 integration + * @include: hb-graphite2.h + * + * Functions for using HarfBuzz with the Graphite2 fonts. + **/ /* * shaper face data */ -typedef struct hb_graphite2_tablelist_t { +typedef struct hb_graphite2_tablelist_t +{ struct hb_graphite2_tablelist_t *next; hb_blob_t *blob; unsigned int tag; } hb_graphite2_tablelist_t; -struct hb_graphite2_shaper_face_data_t { +struct hb_graphite2_face_data_t +{ hb_face_t *face; gr_face *grface; - hb_graphite2_tablelist_t *tlist; + hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist; }; static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len) { - hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data; + hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; hb_graphite2_tablelist_t *tlist = face_data->tlist; hb_blob_t *blob = nullptr; @@ -80,10 +89,10 @@ static const void *hb_graphite2_get_table (const void *data, unsigned int tag, s p->tag = tag; retry: - hb_graphite2_tablelist_t *tlist = (hb_graphite2_tablelist_t *) hb_atomic_ptr_get (&face_data->tlist); + hb_graphite2_tablelist_t *tlist = face_data->tlist; p->next = tlist; - if (!hb_atomic_ptr_cmpexch (&face_data->tlist, tlist, p)) + if (unlikely (!face_data->tlist.cmpexch (tlist, p))) goto retry; } @@ -93,7 +102,33 @@ retry: return d; } -hb_graphite2_shaper_face_data_t * +static void hb_graphite2_release_table(const void *data, const void *table_buffer) +{ + hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; + hb_graphite2_tablelist_t *tlist = face_data->tlist; + + hb_graphite2_tablelist_t *prev = nullptr; + hb_graphite2_tablelist_t *curr = tlist; + while (curr) + { + if (hb_blob_get_data(curr->blob, nullptr) == table_buffer) + { + if (prev == nullptr) + face_data->tlist.cmpexch(tlist, curr->next); + else + prev->next = curr->next; + hb_blob_destroy(curr->blob); + free(curr); + break; + } + prev = curr; + curr = curr->next; + } +} + +static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table }; + +hb_graphite2_face_data_t * _hb_graphite2_shaper_face_data_create (hb_face_t *face) { hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF); @@ -106,12 +141,12 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) } hb_blob_destroy (silf_blob); - hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t)); + hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t)); if (unlikely (!data)) return nullptr; data->face = face; - data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll); + data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll); if (unlikely (!data->grface)) { free (data); @@ -122,7 +157,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) } void -_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data) +_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data) { hb_graphite2_tablelist_t *tlist = data->tlist; @@ -145,8 +180,8 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data) gr_face * hb_graphite2_face_get_gr_face (hb_face_t *face) { - if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return nullptr; - return HB_SHAPER_DATA_GET (face)->grface; + const hb_graphite2_face_data_t *data = face->data.graphite2; + return data ? data->grface : nullptr; } @@ -154,52 +189,33 @@ hb_graphite2_face_get_gr_face (hb_face_t *face) * shaper font data */ -struct hb_graphite2_shaper_font_data_t {}; +struct hb_graphite2_font_data_t {}; -hb_graphite2_shaper_font_data_t * +hb_graphite2_font_data_t * _hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED) { - return (hb_graphite2_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data HB_UNUSED) +_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED) { } -/* +/** + * hb_graphite2_font_get_gr_font: + * * Since: 0.9.10 + * Deprecated: 1.4.2 */ gr_font * -hb_graphite2_font_get_gr_font (hb_font_t *font) +hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED) { return nullptr; } /* - * shaper shape_plan data - */ - -struct hb_graphite2_shaper_shape_plan_data_t {}; - -hb_graphite2_shaper_shape_plan_data_t * -_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; -} - -void -_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED) -{ -} - - -/* * shaper */ @@ -213,14 +229,14 @@ struct hb_graphite2_cluster_t { }; hb_bool_t -_hb_graphite2_shape (hb_shape_plan_t *shape_plan, +_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features) { hb_face_t *face = font->face; - gr_face *grface = HB_SHAPER_DATA_GET (face)->grface; + gr_face *grface = face->data.graphite2->grface; const char *lang = hb_language_to_string (hb_buffer_get_language (buffer)); const char *lang_end = lang ? strchr (lang, '-') : nullptr; @@ -249,11 +265,16 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan, /* TODO ensure_native_direction. */ - hb_tag_t script_tag[2]; - hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]); + hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT]; + unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT; + hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer), + HB_LANGUAGE_INVALID, + &count, + script_tag, + nullptr, nullptr); seg = gr_make_seg (nullptr, grface, - script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1], + count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT, feats, gr_utf32, chars, buffer->len, 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h index 05c55de..1720191 100644 --- a/src/hb-graphite2.h +++ b/src/hb-graphite2.h @@ -41,7 +41,7 @@ hb_graphite2_face_get_gr_face (hb_face_t *face); #ifndef HB_DISABLE_DEPRECATED -HB_EXTERN gr_font * +HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font * hb_graphite2_font_get_gr_font (hb_font_t *font); #endif diff --git a/src/hb-icu.cc b/src/hb-icu.cc index c52e165..c26c91d 100644 --- a/src/hb-icu.cc +++ b/src/hb-icu.cc @@ -27,11 +27,11 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-icu.h" -#include "hb-unicode-private.hh" +#include "hb-machinery.hh" #include <unicode/uchar.h> #include <unicode/unorm2.h> @@ -40,6 +40,16 @@ #include <unicode/uversion.h> +/** + * SECTION:hb-icu + * @title: hb-icu + * @short_description: ICU integration + * @include: hb-icu.h + * + * Functions for using HarfBuzz with the ICU library to provide Unicode data. + **/ + + hb_script_t hb_icu_script_to_script (UScriptCode script) { @@ -55,7 +65,8 @@ hb_icu_script_from_script (hb_script_t script) if (unlikely (script == HB_SCRIPT_INVALID)) return USCRIPT_INVALID_CODE; - for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++) + unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT); + for (unsigned int i = 0; i < numScriptCode; i++) if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script)) return (UScriptCode) i; @@ -72,25 +83,6 @@ hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) u_getCombiningClass (unicode); } -static unsigned int -hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH)) - { - case U_EA_WIDE: - case U_EA_FULLWIDTH: - return 2; - case U_EA_NEUTRAL: - case U_EA_AMBIGUOUS: - case U_EA_HALFWIDTH: - case U_EA_NARROW: - return 1; - } - return 1; -} - static hb_unicode_general_category_t hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -164,10 +156,6 @@ hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, return hb_icu_script_to_script (scriptCode); } -#if U_ICU_VERSION_MAJOR_NUM >= 49 -static const UNormalizer2 *normalizer; -#endif - static hb_bool_t hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t a, @@ -177,6 +165,7 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if U_ICU_VERSION_MAJOR_NUM >= 49 { + const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; UChar32 ret = unorm2_composePair (normalizer, a, b); if (ret < 0) return false; *ab = ret; @@ -222,6 +211,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if U_ICU_VERSION_MAJOR_NUM >= 49 { + const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; UChar decomposed[4]; int len; UErrorCode icu_err = U_ZERO_ERROR; @@ -310,90 +300,51 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, return ret; } -static unsigned int -hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ - UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1]; - unsigned int len; - int32_t utf32_len; - hb_bool_t err; - UErrorCode icu_err; - - /* Copy @u into a UTF-16 array to be passed to ICU. */ - len = 0; - err = false; - U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err); - if (err) - return 0; - - /* Normalise the codepoint using NFKD mode. */ - icu_err = U_ZERO_ERROR; - len = unorm2_normalize (unorm2_getNFKDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err); - if (U_FAILURE (icu_err)) - return 0; - /* Convert the decomposed form from UTF-16 to UTF-32. */ - icu_err = U_ZERO_ERROR; - u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err); - if (U_FAILURE (icu_err)) - return 0; - - return utf32_len; -} - - -static hb_unicode_funcs_t *static_icu_funcs = nullptr; - -#ifdef HB_USE_ATEXIT -static -void free_static_icu_funcs (void) -{ -retry: - hb_unicode_funcs_t *icu_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs); - if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, icu_funcs, nullptr)) - goto retry; - - hb_unicode_funcs_destroy (icu_funcs); -} +#if HB_USE_ATEXIT +static void free_static_icu_funcs (); #endif -hb_unicode_funcs_t * -hb_icu_get_unicode_funcs (void) +static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t> { -retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs); - - if (unlikely (!funcs)) + static hb_unicode_funcs_t *create () { + void *user_data = nullptr; #if U_ICU_VERSION_MAJOR_NUM >= 49 - if (!hb_atomic_ptr_get (&normalizer)) { - UErrorCode icu_err = U_ZERO_ERROR; - /* We ignore failure in getNFCInstace(). */ - (void) hb_atomic_ptr_cmpexch (&normalizer, nullptr, unorm2_getNFCInstance (&icu_err)); - } + UErrorCode icu_err = U_ZERO_ERROR; + user_data = (void *) unorm2_getNFCInstance (&icu_err); + assert (user_data); #endif - funcs = hb_unicode_funcs_create (nullptr); + hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, nullptr, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT + hb_unicode_funcs_set_combining_class_func (funcs, hb_icu_unicode_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_icu_unicode_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_icu_unicode_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_icu_unicode_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_icu_unicode_compose, user_data, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_icu_unicode_decompose, user_data, nullptr); hb_unicode_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, nullptr, funcs)) { - hb_unicode_funcs_destroy (funcs); - goto retry; - } +#if HB_USE_ATEXIT + atexit (free_static_icu_funcs); +#endif + + return funcs; + } +} static_icu_funcs; -#ifdef HB_USE_ATEXIT - atexit (free_static_icu_funcs); /* First person registers atexit() callback. */ +#if HB_USE_ATEXIT +static +void free_static_icu_funcs () +{ + static_icu_funcs.free_instance (); +} #endif - }; - return hb_unicode_funcs_reference (funcs); +hb_unicode_funcs_t * +hb_icu_get_unicode_funcs () +{ + return static_icu_funcs.get_unconst (); } diff --git a/src/hb-iter.hh b/src/hb-iter.hh new file mode 100644 index 0000000..c4ab26d --- /dev/null +++ b/src/hb-iter.hh @@ -0,0 +1,153 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_ITER_HH +#define HB_ITER_HH + +#include "hb.hh" +#include "hb-null.hh" + + +/* Unified iterator object. + * + * The goal of this template is to make the same iterator interface + * available to all types, and make it very easy and compact to use. + * hb_iter_tator objects are small, light-weight, objects that can be + * copied by value. If the collection / object being iterated on + * is writable, then the iterator returns lvalues, otherwise it + * returns rvalues. + */ + +/* Base class for all iterators. */ +template <typename Iter, typename Item = typename Iter::__item_type__> +struct hb_iter_t +{ + typedef Iter iter_t; + typedef iter_t const_iter_t; + typedef Item item_t; + static constexpr unsigned item_size = hb_static_size (Item); + + private: + /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + const iter_t* thiz () const { return static_cast<const iter_t *> (this); } + iter_t* thiz () { return static_cast< iter_t *> (this); } + public: + + /* Operators. */ + operator iter_t () { return iter(); } + explicit_operator bool () const { return more (); } + item_t& operator * () const { return item (); } + item_t& operator [] (signed i) const { return item_at ((unsigned) i); } + iter_t& operator += (unsigned count) { forward (count); return *thiz(); } + iter_t& operator ++ () { next (); return *thiz(); } + iter_t& operator -= (unsigned count) { rewind (count); return *thiz(); } + iter_t& operator -- () { prev (); return *thiz(); } + iter_t operator + (unsigned count) { iter_t c (*thiz()); c += count; return c; } + iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; } + iter_t operator - (unsigned count) { iter_t c (*thiz()); c -= count; return c; } + iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; } + + /* Methods. */ + iter_t iter () const { return *thiz(); } + const_iter_t const_iter () const { return iter (); } + item_t& item () const { return thiz()->__item__ (); } + item_t& item_at (unsigned i) const { return thiz()->__item_at__ (i); } + bool more () const { return thiz()->__more__ (); } + unsigned len () const { return thiz()->__len__ (); } + void next () { thiz()->__next__ (); } + void forward (unsigned n) { thiz()->__forward__ (n); } + void prev () { thiz()->__prev__ (); } + void rewind (unsigned n) { thiz()->__rewind__ (n); } + bool random_access () const { return thiz()->__random_access__ (); } + + protected: + hb_iter_t () {} + hb_iter_t (const hb_iter_t &o HB_UNUSED) {} + void operator = (const hb_iter_t &o HB_UNUSED) {} +}; + +/* Base class for sorted iterators. Does not enforce anything. + * Just for class taxonomy and requirements. */ +template <typename Iter, typename Item = typename Iter::__item_type__> +struct hb_sorted_iter_t : hb_iter_t<Iter, Item> +{ + protected: + hb_sorted_iter_t () {} + hb_sorted_iter_t (const hb_sorted_iter_t &o) : hb_iter_t<Iter, Item> (o) {} + void operator = (const hb_sorted_iter_t &o HB_UNUSED) {} +}; + +/* Mixin to fill in what the subclass doesn't provide. */ +template <typename iter_t, typename item_t = typename iter_t::__item_type__> +struct hb_iter_mixin_t +{ + private: + /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + const iter_t* thiz () const { return static_cast<const iter_t *> (this); } + iter_t* thiz () { return static_cast< iter_t *> (this); } + public: + + /* Access: Implement __item__(), or __item_at__() if random-access. */ + item_t& __item__ () const { return thiz()->item_at (0); } + item_t& __item_at__ (unsigned i) const { return *(thiz() + i); } + + /* Termination: Implement __more__(), or __len__() if random-access. */ + bool __more__ () const { return thiz()->__len__ (); } + unsigned __len__ () const + { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; } + + /* Advancing: Implement __next__(), or __forward__() if random-access. */ + void __next__ () { thiz()->forward (1); } + void __forward__ (unsigned n) { while (n--) thiz()->next (); } + + /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */ + void __prev__ () { thiz()->rewind (1); } + void __rewind__ (unsigned n) { while (n--) thiz()->prev (); } + + /* Random access: Return true if item_at(), len(), forward() are fast. */ + bool __random_access__ () const { return false; } +}; + + +/* Functions operating on iterators or iteratables. */ + +template <typename C, typename V> inline void +hb_fill (const C& c, const V &v) +{ + for (typename C::iter_t i (c); i; i++) + hb_assign (*i, v); +} + +template <typename S, typename D> inline bool +hb_copy (hb_iter_t<D> &id, hb_iter_t<S> &is) +{ + for (; id && is; ++id, ++is) + *id = *is; + return !is; +} + + +#endif /* HB_ITER_HH */ diff --git a/src/hb-kern.hh b/src/hb-kern.hh new file mode 100644 index 0000000..fd5bb9e --- /dev/null +++ b/src/hb-kern.hh @@ -0,0 +1,139 @@ +/* + * Copyright © 2017 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): Behdad Esfahbod + */ + +#ifndef HB_KERN_HH +#define HB_KERN_HH + +#include "hb-open-type.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout-gpos-table.hh" + + +namespace OT { + + +template <typename Driver> +struct hb_kern_machine_t +{ + hb_kern_machine_t (const Driver &driver_, + bool crossStream_ = false) : + driver (driver_), + crossStream (crossStream_) {} + + HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW + void kern (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t kern_mask, + bool scale = true) const + { + OT::hb_ot_apply_context_t c (1, font, buffer); + c.set_lookup_mask (kern_mask); + c.set_lookup_props (OT::LookupFlag::IgnoreMarks); + OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; + skippy_iter.init (&c); + + bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + for (unsigned int idx = 0; idx < count;) + { + if (!(info[idx].mask & kern_mask)) + { + idx++; + continue; + } + + skippy_iter.reset (idx, 1); + if (!skippy_iter.next ()) + { + idx++; + continue; + } + + unsigned int i = idx; + unsigned int j = skippy_iter.idx; + + hb_position_t kern = driver.get_kerning (info[i].codepoint, + info[j].codepoint); + + + if (likely (!kern)) + goto skip; + + if (horizontal) + { + if (scale) + kern = font->em_scale_x (kern); + if (crossStream) + { + pos[j].y_offset = kern; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + else + { + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + pos[i].x_advance += kern1; + pos[j].x_advance += kern2; + pos[j].x_offset += kern2; + } + } + else + { + if (scale) + kern = font->em_scale_y (kern); + if (crossStream) + { + pos[j].x_offset = kern; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + else + { + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + pos[i].y_advance += kern1; + pos[j].y_advance += kern2; + pos[j].y_offset += kern2; + } + } + + buffer->unsafe_to_break (i, j + 1); + + skip: + idx = skippy_iter.idx; + } + } + + const Driver &driver; + bool crossStream; +}; + + +} /* namespace OT */ + + +#endif /* HB_KERN_HH */ diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh new file mode 100644 index 0000000..b22c238 --- /dev/null +++ b/src/hb-machinery.hh @@ -0,0 +1,931 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012,2018 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_MACHINERY_HH +#define HB_MACHINERY_HH + +#include "hb.hh" +#include "hb-blob.hh" + +#include "hb-array.hh" +#include "hb-vector.hh" + + +/* + * Casts + */ + +/* Cast to struct T, reference to reference */ +template<typename Type, typename TObject> +static inline const Type& CastR(const TObject &X) +{ return reinterpret_cast<const Type&> (X); } +template<typename Type, typename TObject> +static inline Type& CastR(TObject &X) +{ return reinterpret_cast<Type&> (X); } + +/* Cast to struct T, pointer to pointer */ +template<typename Type, typename TObject> +static inline const Type* CastP(const TObject *X) +{ return reinterpret_cast<const Type*> (X); } +template<typename Type, typename TObject> +static inline Type* CastP(TObject *X) +{ return reinterpret_cast<Type*> (X); } + +/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory + * location pointed to by P plus Ofs bytes. */ +template<typename Type> +static inline const Type& StructAtOffset(const void *P, unsigned int offset) +{ return * reinterpret_cast<const Type*> ((const char *) P + offset); } +template<typename Type> +static inline Type& StructAtOffset(void *P, unsigned int offset) +{ return * reinterpret_cast<Type*> ((char *) P + offset); } +template<typename Type> +static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) +{ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return * reinterpret_cast<Type*> ((char *) P + offset); +#pragma GCC diagnostic pop +} +template<typename Type> +static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) +{ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return * reinterpret_cast<Type*> ((char *) P + offset); +#pragma GCC diagnostic pop +} + +/* StructAfter<T>(X) returns the struct T& that is placed after X. + * Works with X of variable size also. X must implement get_size() */ +template<typename Type, typename TObject> +static inline const Type& StructAfter(const TObject &X) +{ return StructAtOffset<Type>(&X, X.get_size()); } +template<typename Type, typename TObject> +static inline Type& StructAfter(TObject &X) +{ return StructAtOffset<Type>(&X, X.get_size()); } + + +/* + * Size checking + */ + +/* Check _assertion in a method environment */ +#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ + void _instance_assertion_on_line_##_line () const \ + { static_assert ((_assertion), ""); } +# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) +# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) + +/* Check that _code compiles in a method environment */ +#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ + void _compiles_assertion_on_line_##_line () const \ + { _code; } +# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) +# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) + + +#define DEFINE_SIZE_STATIC(size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ + unsigned int get_size () const { return (size); } \ + static constexpr unsigned null_size = (size); \ + static constexpr unsigned min_size = (size); \ + static constexpr unsigned static_size = (size) + +#define DEFINE_SIZE_UNION(size, _member) \ + DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \ + DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \ + static constexpr unsigned null_size = (size); \ + static constexpr unsigned min_size = (size) + +#define DEFINE_SIZE_MIN(size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ + static constexpr unsigned null_size = (size); \ + static constexpr unsigned min_size = (size) + +#define DEFINE_SIZE_UNBOUNDED(size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ + static constexpr unsigned min_size = (size) + +#define DEFINE_SIZE_ARRAY(size, array) \ + DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \ + static constexpr unsigned null_size = (size); \ + static constexpr unsigned min_size = (size) + +#define DEFINE_SIZE_ARRAY_SIZED(size, array) \ + unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ + DEFINE_SIZE_ARRAY(size, array) + + +/* + * Dispatch + */ + +template <typename Context, typename Return, unsigned int MaxDebugDepth> +struct hb_dispatch_context_t +{ + static constexpr unsigned max_debug_depth = MaxDebugDepth; + typedef Return return_t; + template <typename T, typename F> + bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; } + static return_t no_dispatch_return_value () { return Context::default_return_value (); } + static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; } +}; + + +/* + * Sanitize + * + * + * === Introduction === + * + * The sanitize machinery is at the core of our zero-cost font loading. We + * mmap() font file into memory and create a blob out of it. Font subtables + * are returned as a readonly sub-blob of the main font blob. These table + * blobs are then sanitized before use, to ensure invalid memory access does + * not happen. The toplevel sanitize API use is like, eg. to load the 'head' + * table: + * + * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face); + * + * The blob then can be converted to a head table struct with: + * + * const head *head_table = head_blob->as<head> (); + * + * What the reference_table does is, to call hb_face_reference_table() to load + * the table blob, sanitize it and return either the sanitized blob, or empty + * blob if sanitization failed. The blob->as() function returns the null + * object of its template type argument if the blob is empty. Otherwise, it + * just casts the blob contents to the desired type. + * + * Sanitizing a blob of data with a type T works as follows (with minor + * simplification): + * + * - Cast blob content to T*, call sanitize() method of it, + * - If sanitize succeeded, return blob. + * - Otherwise, if blob is not writable, try making it writable, + * or copy if cannot be made writable in-place, + * - Call sanitize() again. Return blob if sanitize succeeded. + * - Return empty blob otherwise. + * + * + * === The sanitize() contract === + * + * The sanitize() method of each object type shall return true if it's safe to + * call other methods of the object, and false otherwise. + * + * Note that what sanitize() checks for might align with what the specification + * describes as valid table data, but does not have to be. In particular, we + * do NOT want to be pedantic and concern ourselves with validity checks that + * are irrelevant to our use of the table. On the contrary, we want to be + * lenient with error handling and accept invalid data to the extent that it + * does not impose extra burden on us. + * + * Based on the sanitize contract, one can see that what we check for depends + * on how we use the data in other table methods. Ie. if other table methods + * assume that offsets do NOT point out of the table data block, then that's + * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On + * the other hand, if other methods do such checks themselves, then sanitize() + * does not have to bother with them (glyf/local work this way). The choice + * depends on the table structure and sanitize() performance. For example, to + * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard + * to avoid such costs during font loading. By postponing such checks to the + * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime + * cost to O(used-glyphs). As such, this is preferred. + * + * The same argument can be made re GSUB/GPOS/GDEF, but there, the table + * structure is so complicated that by checking all offsets at sanitize() time, + * we make the code much simpler in other methods, as offsets and referenced + * objects do not need to be validated at each use site. + */ + +/* This limits sanitizing time on really broken fonts. */ +#ifndef HB_SANITIZE_MAX_EDITS +#define HB_SANITIZE_MAX_EDITS 32 +#endif +#ifndef HB_SANITIZE_MAX_OPS_FACTOR +#define HB_SANITIZE_MAX_OPS_FACTOR 8 +#endif +#ifndef HB_SANITIZE_MAX_OPS_MIN +#define HB_SANITIZE_MAX_OPS_MIN 16384 +#endif +#ifndef HB_SANITIZE_MAX_OPS_MAX +#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF +#endif + +struct hb_sanitize_context_t : + hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE> +{ + hb_sanitize_context_t () : + debug_depth (0), + start (nullptr), end (nullptr), + max_ops (0), + writable (false), edit_count (0), + blob (nullptr), + num_glyphs (65536), + num_glyphs_set (false) {} + + const char *get_name () { return "SANITIZE"; } + template <typename T, typename F> + bool may_dispatch (const T *obj HB_UNUSED, const F *format) + { return format->sanitize (this); } + template <typename T> + return_t dispatch (const T &obj) { return obj.sanitize (this); } + static return_t default_return_value () { return true; } + static return_t no_dispatch_return_value () { return false; } + bool stop_sublookup_iteration (const return_t r) const { return !r; } + + void init (hb_blob_t *b) + { + this->blob = hb_blob_reference (b); + this->writable = false; + } + + void set_num_glyphs (unsigned int num_glyphs_) + { + num_glyphs = num_glyphs_; + num_glyphs_set = true; + } + unsigned int get_num_glyphs () { return num_glyphs; } + + void set_max_ops (int max_ops_) { max_ops = max_ops_; } + + template <typename T> + void set_object (const T *obj) + { + reset_object (); + + if (!obj) return; + + const char *obj_start = (const char *) obj; + if (unlikely (obj_start < this->start || this->end <= obj_start)) + this->start = this->end = nullptr; + else + { + this->start = obj_start; + this->end = obj_start + MIN<uintptr_t> (this->end - obj_start, obj->get_size ()); + } + } + + void reset_object () + { + this->start = this->blob->data; + this->end = this->start + this->blob->length; + assert (this->start <= this->end); /* Must not overflow. */ + } + + void start_processing () + { + reset_object (); + this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, + (unsigned) HB_SANITIZE_MAX_OPS_MIN); + this->edit_count = 0; + this->debug_depth = 0; + + DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + } + + void end_processing () + { + DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, + "end [%p..%p] %u edit requests", + this->start, this->end, this->edit_count); + + hb_blob_destroy (this->blob); + this->blob = nullptr; + this->start = this->end = nullptr; + } + + bool check_range (const void *base, + unsigned int len) const + { + const char *p = (const char *) base; + bool ok = this->start <= p && + p <= this->end && + (unsigned int) (this->end - p) >= len && + this->max_ops-- > 0; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s", + p, p + len, len, + this->start, this->end, + ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } + + template <typename T> + bool check_range (const T *base, + unsigned int a, + unsigned int b) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b); + } + + template <typename T> + bool check_range (const T *base, + unsigned int a, + unsigned int b, + unsigned int c) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b, c); + } + + template <typename T> + bool check_array (const T *base, unsigned int len) const + { + return this->check_range (base, len, hb_static_size (T)); + } + + template <typename T> + bool check_array (const T *base, + unsigned int a, + unsigned int b) const + { + return this->check_range (base, a, b, hb_static_size (T)); + } + + template <typename Type> + bool check_struct (const Type *obj) const + { return likely (this->check_range (obj, obj->min_size)); } + + bool may_edit (const void *base, unsigned int len) + { + if (this->edit_count >= HB_SANITIZE_MAX_EDITS) + return false; + + const char *p = (const char *) base; + this->edit_count++; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->edit_count, + p, p + len, len, + this->start, this->end, + this->writable ? "GRANTED" : "DENIED"); + + return this->writable; + } + + template <typename Type, typename ValueType> + bool try_set (const Type *obj, const ValueType &v) + { + if (this->may_edit (obj, hb_static_size (Type))) + { + hb_assign (* const_cast<Type *> (obj), v); + return true; + } + return false; + } + + template <typename Type> + hb_blob_t *sanitize_blob (hb_blob_t *blob) + { + bool sane; + + init (blob); + + retry: + DEBUG_MSG_FUNC (SANITIZE, start, "start"); + + start_processing (); + + if (unlikely (!start)) + { + end_processing (); + return blob; + } + + Type *t = CastP<Type> (const_cast<char *> (start)); + + sane = t->sanitize (this); + if (sane) + { + if (edit_count) + { + DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count); + + /* sanitize again to ensure no toe-stepping */ + edit_count = 0; + sane = t->sanitize (this); + if (edit_count) { + DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count); + sane = false; + } + } + } + else + { + if (edit_count && !writable) { + start = hb_blob_get_data_writable (blob, nullptr); + end = start + blob->length; + + if (start) + { + writable = true; + /* ok, we made it writable by relocating. try again */ + DEBUG_MSG_FUNC (SANITIZE, start, "retry"); + goto retry; + } + } + } + + end_processing (); + + DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED"); + if (sane) + { + hb_blob_make_immutable (blob); + return blob; + } + else + { + hb_blob_destroy (blob); + return hb_blob_get_empty (); + } + } + + template <typename Type> + hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag) + { + if (!num_glyphs_set) + set_num_glyphs (hb_face_get_glyph_count (face)); + return sanitize_blob<Type> (hb_face_reference_table (face, tableTag)); + } + + mutable unsigned int debug_depth; + const char *start, *end; + mutable int max_ops; + private: + bool writable; + unsigned int edit_count; + hb_blob_t *blob; + unsigned int num_glyphs; + bool num_glyphs_set; +}; + +struct hb_sanitize_with_object_t +{ + template <typename T> + hb_sanitize_with_object_t (hb_sanitize_context_t *c, + const T& obj) : c (c) + { c->set_object (obj); } + ~hb_sanitize_with_object_t () + { c->reset_object (); } + + private: + hb_sanitize_context_t *c; +}; + + +/* + * Serialize + */ + +struct hb_serialize_context_t +{ + hb_serialize_context_t (void *start_, unsigned int size) + { + this->start = (char *) start_; + this->end = this->start + size; + reset (); + } + + bool in_error () const { return !this->successful; } + + void reset () + { + this->successful = true; + this->head = this->start; + this->debug_depth = 0; + } + + bool propagate_error (bool e) + { return this->successful = this->successful && e; } + template <typename T> bool propagate_error (const T &obj) + { return this->successful = this->successful && !obj.in_error (); } + template <typename T> bool propagate_error (const T *obj) + { return this->successful = this->successful && !obj->in_error (); } + template <typename T1, typename T2> bool propagate_error (T1 &o1, T2 &o2) + { return propagate_error (o1) && propagate_error (o2); } + template <typename T1, typename T2> bool propagate_error (T1 *o1, T2 *o2) + { return propagate_error (o1) && propagate_error (o2); } + template <typename T1, typename T2, typename T3> + bool propagate_error (T1 &o1, T2 &o2, T3 &o3) + { return propagate_error (o1) && propagate_error (o2, o3); } + template <typename T1, typename T2, typename T3> + bool propagate_error (T1 *o1, T2 *o2, T3 *o3) + { return propagate_error (o1) && propagate_error (o2, o3); } + + /* To be called around main operation. */ + template <typename Type> + Type *start_serialize () + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + + return start_embed<Type> (); + } + void end_serialize () + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, + "end [%p..%p] serialized %d bytes; %s", + this->start, this->end, + (int) (this->head - this->start), + this->successful ? "successful" : "UNSUCCESSFUL"); + } + + unsigned int length () const { return this->head - this->start; } + + void align (unsigned int alignment) + { + unsigned int l = length () % alignment; + if (l) + allocate_size<void> (alignment - l); + } + + template <typename Type> + Type *start_embed (const Type *_ HB_UNUSED = nullptr) const + { + Type *ret = reinterpret_cast<Type *> (this->head); + return ret; + } + + template <typename Type> + Type *allocate_size (unsigned int size) + { + if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) { + this->successful = false; + return nullptr; + } + memset (this->head, 0, size); + char *ret = this->head; + this->head += size; + return reinterpret_cast<Type *> (ret); + } + + template <typename Type> + Type *allocate_min () + { + return this->allocate_size<Type> (Type::min_size); + } + + template <typename Type> + Type *embed (const Type &obj) + { + unsigned int size = obj.get_size (); + Type *ret = this->allocate_size<Type> (size); + if (unlikely (!ret)) return nullptr; + memcpy (ret, &obj, size); + return ret; + } + template <typename Type> + hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; } + + template <typename Type> + Type *extend_size (Type &obj, unsigned int size) + { + assert (this->start <= (char *) &obj); + assert ((char *) &obj <= this->head); + assert ((char *) &obj + size >= this->head); + if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr; + return reinterpret_cast<Type *> (&obj); + } + + template <typename Type> + Type *extend_min (Type &obj) { return extend_size (obj, obj.min_size); } + + template <typename Type> + Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); } + + /* Output routines. */ + template <typename Type> + Type *copy () const + { + assert (this->successful); + unsigned int len = this->head - this->start; + void *p = malloc (len); + if (p) + memcpy (p, this->start, len); + return reinterpret_cast<Type *> (p); + } + hb_bytes_t copy_bytes () const + { + assert (this->successful); + unsigned int len = this->head - this->start; + void *p = malloc (len); + if (p) + memcpy (p, this->start, len); + else + return hb_bytes_t (); + return hb_bytes_t ((char *) p, len); + } + hb_blob_t *copy_blob () const + { + assert (this->successful); + return hb_blob_create (this->start, + this->head - this->start, + HB_MEMORY_MODE_DUPLICATE, + nullptr, nullptr); + } + + public: + unsigned int debug_depth; + char *start, *end, *head; + bool successful; +}; + + + +/* + * Big-endian integers. + */ + +template <typename Type, int Bytes> struct BEInt; + +template <typename Type> +struct BEInt<Type, 1> +{ + public: + void set (Type V) { v = V; } + operator Type () const { return v; } + private: uint8_t v; +}; +template <typename Type> +struct BEInt<Type, 2> +{ + public: + void set (Type V) + { + v[0] = (V >> 8) & 0xFF; + v[1] = (V ) & 0xFF; + } + operator Type () const + { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ + struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap16 (((packed_uint16_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint16_t *) this)->v; +#endif +#endif + return (v[0] << 8) + + (v[1] ); + } + private: uint8_t v[2]; +}; +template <typename Type> +struct BEInt<Type, 3> +{ + public: + void set (Type V) + { + v[0] = (V >> 16) & 0xFF; + v[1] = (V >> 8) & 0xFF; + v[2] = (V ) & 0xFF; + } + operator Type () const + { + return (v[0] << 16) + + (v[1] << 8) + + (v[2] ); + } + private: uint8_t v[3]; +}; +template <typename Type> +struct BEInt<Type, 4> +{ + public: + typedef Type type; + void set (Type V) + { + v[0] = (V >> 24) & 0xFF; + v[1] = (V >> 16) & 0xFF; + v[2] = (V >> 8) & 0xFF; + v[3] = (V ) & 0xFF; + } + operator Type () const + { + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); + } + private: uint8_t v[4]; +}; + + +/* + * Lazy loaders. + */ + +template <typename Data, unsigned int WheresData> +struct hb_data_wrapper_t +{ + static_assert (WheresData > 0, ""); + + Data * get_data () const + { return *(((Data **) (void *) this) - WheresData); } + + bool is_inert () const { return !get_data (); } + + template <typename Stored, typename Subclass> + Stored * call_create () const { return Subclass::create (get_data ()); } +}; +template <> +struct hb_data_wrapper_t<void, 0> +{ + bool is_inert () const { return false; } + + template <typename Stored, typename Funcs> + Stored * call_create () const { return Funcs::create (); } +}; + +template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; }; +template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; }; + +template <typename Returned, + typename Subclass = void, + typename Data = void, + unsigned int WheresData = 0, + typename Stored = Returned> +struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> +{ + typedef typename hb_non_void_t<Subclass, + hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored> + >::value Funcs; + + void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ + void init () { instance.set_relaxed (nullptr); } + void fini () { do_destroy (instance.get ()); } + + void free_instance () + { + retry: + Stored *p = instance.get (); + if (unlikely (p && !cmpexch (p, nullptr))) + goto retry; + do_destroy (p); + } + + static void do_destroy (Stored *p) + { + if (p && p != const_cast<Stored *> (Funcs::get_null ())) + Funcs::destroy (p); + } + + const Returned * operator -> () const { return get (); } + const Returned & operator * () const { return *get (); } + explicit_operator bool () const + { return get_stored () != Funcs::get_null (); } + template <typename C> operator const C * () const { return get (); } + + Stored * get_stored () const + { + retry: + Stored *p = this->instance.get (); + if (unlikely (!p)) + { + if (unlikely (this->is_inert ())) + return const_cast<Stored *> (Funcs::get_null ()); + + p = this->template call_create<Stored, Funcs> (); + if (unlikely (!p)) + p = const_cast<Stored *> (Funcs::get_null ()); + + if (unlikely (!cmpexch (nullptr, p))) + { + do_destroy (p); + goto retry; + } + } + return p; + } + Stored * get_stored_relaxed () const + { + return this->instance.get_relaxed (); + } + + bool cmpexch (Stored *current, Stored *value) const + { + /* This *must* be called when there are no other threads accessing. */ + return this->instance.cmpexch (current, value); + } + + const Returned * get () const { return Funcs::convert (get_stored ()); } + const Returned * get_relaxed () const { return Funcs::convert (get_stored_relaxed ()); } + Returned * get_unconst () const { return const_cast<Returned *> (Funcs::convert (get_stored ())); } + + /* To be possibly overloaded by subclasses. */ + static Returned* convert (Stored *p) { return p; } + + /* By default null/init/fini the object. */ + static const Stored* get_null () { return &Null(Stored); } + static Stored *create (Data *data) + { + Stored *p = (Stored *) calloc (1, sizeof (Stored)); + if (likely (p)) + p->init (data); + return p; + } + static Stored *create () + { + Stored *p = (Stored *) calloc (1, sizeof (Stored)); + if (likely (p)) + p->init (); + return p; + } + static void destroy (Stored *p) + { + p->fini (); + free (p); + } + +// private: + /* Must only have one pointer. */ + hb_atomic_ptr_t<Stored *> instance; +}; + +/* Specializations. */ + +template <typename T, unsigned int WheresFace> +struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, + hb_face_lazy_loader_t<T, WheresFace>, + hb_face_t, WheresFace> {}; + +template <typename T, unsigned int WheresFace> +struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, + hb_table_lazy_loader_t<T, WheresFace>, + hb_face_t, WheresFace, + hb_blob_t> +{ + static hb_blob_t *create (hb_face_t *face) + { return hb_sanitize_context_t ().reference_table<T> (face); } + static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } + + static const hb_blob_t *get_null () + { return hb_blob_get_empty (); } + + static const T* convert (const hb_blob_t *blob) + { return blob->as<T> (); } + + hb_blob_t* get_blob () const { return this->get_stored (); } +}; + +template <typename Subclass> +struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass> +{ + static void destroy (hb_font_funcs_t *p) + { hb_font_funcs_destroy (p); } + static const hb_font_funcs_t *get_null () + { return hb_font_funcs_get_empty (); } +}; +template <typename Subclass> +struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass> +{ + static void destroy (hb_unicode_funcs_t *p) + { hb_unicode_funcs_destroy (p); } + static const hb_unicode_funcs_t *get_null () + { return hb_unicode_funcs_get_empty (); } +}; + + +#endif /* HB_MACHINERY_HH */ diff --git a/src/hb-map.cc b/src/hb-map.cc index e3ddae4..a2c770c 100644 --- a/src/hb-map.cc +++ b/src/hb-map.cc @@ -24,10 +24,19 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-map-private.hh" +#include "hb-map.hh" -/* Public API */ +/** + * SECTION:hb-map + * @title: hb-map + * @short_description: Object representing integer to integer mapping + * @include: hb.h + * + * Map objects are integer-to-integer hash-maps. Currently they are + * not used in the HarfBuzz public API, but are provided for client's + * use if desired. + **/ /** @@ -38,7 +47,7 @@ * Since: 1.7.7 **/ hb_map_t * -hb_map_create (void) +hb_map_create () { hb_map_t *map; @@ -58,7 +67,7 @@ hb_map_create (void) * Since: 1.7.7 **/ hb_map_t * -hb_map_get_empty (void) +hb_map_get_empty () { return const_cast<hb_map_t *> (&Null(hb_map_t)); } @@ -157,8 +166,6 @@ hb_map_allocation_successful (const hb_map_t *map) * * * - * Return value: - * * Since: 1.7.7 **/ void @@ -188,7 +195,7 @@ hb_map_get (const hb_map_t *map, /** * hb_map_del: * @map: a map. - * @codepoint: + * @key: * * * @@ -204,7 +211,7 @@ hb_map_del (hb_map_t *map, /** * hb_map_has: * @map: a map. - * @codepoint: + * @key: * * * diff --git a/src/hb-map-private.hh b/src/hb-map.hh index d3d4dde..02d5406 100644 --- a/src/hb-map-private.hh +++ b/src/hb-map.hh @@ -24,11 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_MAP_PRIVATE_HH -#define HB_MAP_PRIVATE_HH +#ifndef HB_MAP_HH +#define HB_MAP_HH -#include "hb-private.hh" -#include "hb-object-private.hh" +#include "hb.hh" template <typename T> @@ -45,13 +44,17 @@ inline uint32_t Hash (const T &v) struct hb_map_t { + HB_NO_COPY_ASSIGN (hb_map_t); + hb_map_t () { init (); } + ~hb_map_t () { fini (); } + struct item_t { hb_codepoint_t key; hb_codepoint_t value; - inline bool is_unused (void) const { return key == INVALID; } - inline bool is_tombstone (void) const { return key != INVALID && value == INVALID; } + bool is_unused () const { return key == INVALID; } + bool is_tombstone () const { return key != INVALID && value == INVALID; } }; hb_object_header_t header; @@ -62,7 +65,7 @@ struct hb_map_t unsigned int prime; item_t *items; - inline void init_shallow (void) + void init_shallow () { successful = true; population = occupancy = 0; @@ -70,26 +73,30 @@ struct hb_map_t prime = 0; items = nullptr; } - inline void init (void) + void init () { hb_object_init (this); init_shallow (); } - inline void fini_shallow (void) + void fini_shallow () { free (items); + items = nullptr; } - inline void fini (void) + void fini () { + population = occupancy = 0; hb_object_fini (this); fini_shallow (); } - inline bool resize (void) + bool in_error () const { return !successful; } + + bool resize () { if (unlikely (!successful)) return false; - unsigned int power = _hb_bit_storage (population * 2 + 8); + unsigned int power = hb_bit_storage (population * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -119,7 +126,7 @@ struct hb_map_t return true; } - inline void set (hb_codepoint_t key, hb_codepoint_t value) + void set (hb_codepoint_t key, hb_codepoint_t value) { if (unlikely (!successful)) return; if (unlikely (key == INVALID)) return; @@ -144,46 +151,36 @@ struct hb_map_t population++; } - inline hb_codepoint_t get (hb_codepoint_t key) const + hb_codepoint_t get (hb_codepoint_t key) const { if (unlikely (!items)) return INVALID; unsigned int i = bucket_for (key); return items[i].key == key ? items[i].value : INVALID; } - inline void del (hb_codepoint_t key) - { - set (key, INVALID); - } - inline bool has (hb_codepoint_t key) const - { - return get (key) != INVALID; - } + void del (hb_codepoint_t key) { set (key, INVALID); } + + bool has (hb_codepoint_t key) const + { return get (key) != INVALID; } - inline hb_codepoint_t operator [] (unsigned int key) const + hb_codepoint_t operator [] (unsigned int key) const { return get (key); } - static const hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID; + static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID; - inline void clear (void) + void clear () { memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t)); population = occupancy = 0; } - inline bool is_empty (void) const - { - return population != 0; - } + bool is_empty () const { return population == 0; } - inline unsigned int get_population () const - { - return population; - } + unsigned int get_population () const { return population; } protected: - inline unsigned int bucket_for (hb_codepoint_t key) const + unsigned int bucket_for (hb_codepoint_t key) const { unsigned int i = Hash (key) % prime; unsigned int step = 0; @@ -199,7 +196,7 @@ struct hb_map_t return tombstone == INVALID ? i : tombstone; } - static inline unsigned int prime_for (unsigned int shift) + static unsigned int prime_for (unsigned int shift) { /* Following comment and table copied from glib. */ /* Each table size has an associated prime modulo (the first prime @@ -252,4 +249,4 @@ struct hb_map_t }; -#endif /* HB_MAP_PRIVATE_HH */ +#endif /* HB_MAP_HH */ diff --git a/src/hb-mutex-private.hh b/src/hb-mutex.hh index 14bde31..35f1fde 100644 --- a/src/hb-mutex-private.hh +++ b/src/hb-mutex.hh @@ -29,10 +29,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_MUTEX_PRIVATE_HH -#define HB_MUTEX_PRIVATE_HH +#ifndef HB_MUTEX_HH +#define HB_MUTEX_HH -#include "hb-private.hh" +#include "hb.hh" /* mutex */ @@ -48,7 +48,7 @@ /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ -#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) +#elif !defined(HB_NO_MT) && defined(_WIN32) #include <windows.h> typedef CRITICAL_SECTION hb_mutex_impl_t; @@ -131,11 +131,19 @@ struct hb_mutex_t hb_mutex_impl_t m; - inline void init (void) { hb_mutex_impl_init (&m); } - inline void lock (void) { hb_mutex_impl_lock (&m); } - inline void unlock (void) { hb_mutex_impl_unlock (&m); } - inline void fini (void) { hb_mutex_impl_finish (&m); } + void init () { hb_mutex_impl_init (&m); } + void lock () { hb_mutex_impl_lock (&m); } + void unlock () { hb_mutex_impl_unlock (&m); } + void fini () { hb_mutex_impl_finish (&m); } +}; + +struct hb_lock_t +{ + hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); } + ~hb_lock_t () { mutex.unlock (); } + private: + hb_mutex_t &mutex; }; -#endif /* HB_MUTEX_PRIVATE_HH */ +#endif /* HB_MUTEX_HH */ diff --git a/src/hb-null.hh b/src/hb-null.hh new file mode 100644 index 0000000..204c2fe --- /dev/null +++ b/src/hb-null.hh @@ -0,0 +1,204 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_NULL_HH +#define HB_NULL_HH + +#include "hb.hh" + + +/* + * Static pools + */ + +/* Global nul-content Null pool. Enlarge as necessary. */ + +#define HB_NULL_POOL_SIZE 9880 + +/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size, + * otherwise return sizeof(T). */ + +/* The hard way... + * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol + */ + +template<bool> struct _hb_bool_type {}; + +template <typename T, typename B> +struct _hb_null_size +{ enum { value = sizeof (T) }; }; +template <typename T> +struct _hb_null_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> > +{ enum { value = T::null_size }; }; + +template <typename T> +struct hb_null_size +{ enum { value = _hb_null_size<T, _hb_bool_type<true> >::value }; }; +#define hb_null_size(T) hb_null_size<T>::value + +/* These doesn't belong here, but since is copy/paste from above, put it here. */ + +/* hb_static_size (T) + * Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */ + +template <typename T, typename B> +struct _hb_static_size +{ enum { value = sizeof (T) }; }; +template <typename T> +struct _hb_static_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> > +{ enum { value = T::static_size }; }; + +template <typename T> +struct hb_static_size +{ enum { value = _hb_static_size<T, _hb_bool_type<true> >::value }; }; +#define hb_static_size(T) hb_static_size<T>::value + + +/* hb_assign (obj, value) + * Calls obj.set (value) if obj.min_size is defined and value has different type + * from obj, or obj = v otherwise. */ + +template <typename T, typename V, typename B> +struct _hb_assign +{ static inline void value (T &o, const V v) { o = v; } }; +template <typename T, typename V> +struct _hb_assign<T, V, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> > +{ static inline void value (T &o, const V v) { o.set (v); } }; +template <typename T> +struct _hb_assign<T, T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> > +{ static inline void value (T &o, const T v) { o = v; } }; + +template <typename T, typename V> +static inline void hb_assign (T &o, const V v) +{ _hb_assign<T, V, _hb_bool_type<true> >::value (o, v); } + + +/* + * Null() + */ + +extern HB_INTERNAL +hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)]; + +/* Generic nul-content Null objects. */ +template <typename Type> +static inline Type const & Null () { + static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); + return *reinterpret_cast<Type const *> (_hb_NullPool); +} +template <typename QType> +struct NullHelper +{ + typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type; + static const Type & get_null () { return Null<Type> (); } +}; +#define Null(Type) NullHelper<Type>::get_null () + +/* Specializations for arbitrary-content Null objects expressed in bytes. */ +#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \ + } /* Close namespace. */ \ + extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \ + template <> \ + /*static*/ inline const Namespace::Type& Null<Namespace::Type> () { \ + return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \ + } \ + namespace Namespace { \ + static_assert (true, "Just so we take semicolon after.") +#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ + const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size] + +/* Specializations for arbitrary-content Null objects expressed as struct initializer. */ +#define DECLARE_NULL_INSTANCE(Type) \ + extern HB_INTERNAL const Type _hb_Null_##Type; \ + template <> \ + /*static*/ inline const Type& Null<Type> () { \ + return _hb_Null_##Type; \ + } \ +static_assert (true, "Just so we take semicolon after.") +#define DEFINE_NULL_INSTANCE(Type) \ + const Type _hb_Null_##Type + +/* Global writable pool. Enlarge as necessary. */ + +/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool + * for correct operation. It only exist to catch and divert program logic bugs instead of + * causing bad memory access. So, races there are not actually introducing incorrectness + * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */ +extern HB_INTERNAL +/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)]; + +/* CRAP pool: Common Region for Access Protection. */ +template <typename Type> +static inline Type& Crap () { + static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); + Type *obj = reinterpret_cast<Type *> (_hb_CrapPool); + memcpy (obj, &Null(Type), sizeof (*obj)); + return *obj; +} +template <typename QType> +struct CrapHelper +{ + typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type; + static Type & get_crap () { return Crap<Type> (); } +}; +#define Crap(Type) CrapHelper<Type>::get_crap () + +template <typename Type> +struct CrapOrNullHelper { + static Type & get () { return Crap(Type); } +}; +template <typename Type> +struct CrapOrNullHelper<const Type> { + static const Type & get () { return Null(Type); } +}; +#define CrapOrNull(Type) CrapOrNullHelper<Type>::get () + + +/* + * hb_nonnull_ptr_t + */ + +template <typename P> +struct hb_nonnull_ptr_t +{ + typedef typename hb_remove_pointer (P) T; + + hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {} + T * operator = (T *v_) { return v = v_; } + T * operator -> () const { return get (); } + T & operator * () const { return *get (); } + T ** operator & () const { return &v; } + /* Only auto-cast to const types. */ + template <typename C> operator const C * () const { return get (); } + operator const char * () const { return (const char *) get (); } + T * get () const { return v ? v : const_cast<T *> (&Null(T)); } + T * get_raw () const { return v; } + + T *v; +}; + + +#endif /* HB_NULL_HH */ diff --git a/src/hb-object-private.hh b/src/hb-object.hh index fc48a91..68520f2 100644 --- a/src/hb-object-private.hh +++ b/src/hb-object.hh @@ -29,17 +29,116 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OBJECT_PRIVATE_HH -#define HB_OBJECT_PRIVATE_HH +#ifndef HB_OBJECT_HH +#define HB_OBJECT_HH -#include "hb-private.hh" -#include "hb-debug.hh" +#include "hb.hh" +#include "hb-atomic.hh" +#include "hb-mutex.hh" +#include "hb-vector.hh" -#include "hb-atomic-private.hh" -#include "hb-mutex-private.hh" +/* + * Lockable set + */ + +template <typename item_t, typename lock_t> +struct hb_lockable_set_t +{ + hb_vector_t<item_t> items; + + void init () { items.init (); } + + template <typename T> + item_t *replace_or_insert (T v, lock_t &l, bool replace) + { + l.lock (); + item_t *item = items.find (v); + if (item) { + if (replace) { + item_t old = *item; + *item = v; + l.unlock (); + old.fini (); + } + else { + item = nullptr; + l.unlock (); + } + } else { + item = items.push (v); + l.unlock (); + } + return item; + } + + template <typename T> + void remove (T v, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (item) + { + item_t old = *item; + *item = items[items.length - 1]; + items.pop (); + l.unlock (); + old.fini (); + } else { + l.unlock (); + } + } + + template <typename T> + bool find (T v, item_t *i, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (item) + *i = *item; + l.unlock (); + return !!item; + } -/* reference_count */ + template <typename T> + item_t *find_or_insert (T v, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (!item) { + item = items.push (v); + } + l.unlock (); + return item; + } + + void fini (lock_t &l) + { + if (!items.length) + { + /* No need to lock. */ + items.fini (); + return; + } + l.lock (); + while (items.length) + { + item_t old = items[items.length - 1]; + items.pop (); + l.unlock (); + old.fini (); + l.lock (); + } + items.fini (); + l.unlock (); + } + +}; + + +/* + * Reference-count. + */ #define HB_REFERENCE_COUNT_INERT_VALUE 0 #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD @@ -47,16 +146,16 @@ struct hb_reference_count_t { - hb_atomic_int_t ref_count; + mutable hb_atomic_int_t ref_count; - inline void init (int v) { ref_count.set_unsafe (v); } - inline int get_unsafe (void) const { return ref_count.get_unsafe (); } - inline int inc (void) { return ref_count.inc (); } - inline int dec (void) { return ref_count.dec (); } - inline void fini (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } + void init (int v = 1) { ref_count.set_relaxed (v); } + int get_relaxed () const { return ref_count.get_relaxed (); } + int inc () const { return ref_count.inc (); } + int dec () const { return ref_count.dec (); } + void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); } - inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } - inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } + bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; } + bool is_valid () const { return ref_count.get_relaxed () > 0; } }; @@ -69,16 +168,16 @@ struct hb_user_data_array_t void *data; hb_destroy_func_t destroy; - inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } - inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } + bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } + bool operator == (hb_user_data_item_t &other) const { return key == other.key; } - void fini (void) { if (destroy) destroy (data); } + void fini () { if (destroy) destroy (data); } }; hb_mutex_t lock; hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; - inline void init (void) { lock.init (); items.init (); } + void init () { lock.init (); items.init (); } HB_INTERNAL bool set (hb_user_data_key_t *key, void * data, @@ -87,25 +186,31 @@ struct hb_user_data_array_t HB_INTERNAL void *get (hb_user_data_key_t *key); - inline void fini (void) { items.fini (lock); lock.fini (); } + void fini () { items.fini (lock); lock.fini (); } }; -/* object_header */ +/* + * Object header + */ struct hb_object_header_t { hb_reference_count_t ref_count; - hb_user_data_array_t *user_data; - -#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, nullptr} - - private: - ASSERT_POD (); + mutable hb_atomic_int_t writable; + hb_atomic_ptr_t<hb_user_data_array_t> user_data; }; +#define HB_OBJECT_HEADER_STATIC \ + { \ + HB_REFERENCE_COUNT_INIT, \ + HB_ATOMIC_INT_INIT (false), \ + HB_ATOMIC_PTR_INIT (nullptr) \ + } -/* object */ +/* + * Object + */ template <typename Type> static inline void hb_object_trace (const Type *obj, const char *function) @@ -113,11 +218,11 @@ static inline void hb_object_trace (const Type *obj, const char *function) DEBUG_MSG (OBJECT, (void *) obj, "%s refcount=%d", function, - obj ? obj->header.ref_count.get_unsafe () : 0); + obj ? obj->header.ref_count.get_relaxed () : 0); } template <typename Type> -static inline Type *hb_object_create (void) +static inline Type *hb_object_create () { Type *obj = (Type *) calloc (1, sizeof (Type)); @@ -131,8 +236,9 @@ static inline Type *hb_object_create (void) template <typename Type> static inline void hb_object_init (Type *obj) { - obj->header.ref_count.init (1); - obj->header.user_data = nullptr; + obj->header.ref_count.init (); + obj->header.writable.set_relaxed (true); + obj->header.user_data.init (); } template <typename Type> static inline bool hb_object_is_inert (const Type *obj) @@ -145,6 +251,16 @@ static inline bool hb_object_is_valid (const Type *obj) return likely (obj->header.ref_count.is_valid ()); } template <typename Type> +static inline bool hb_object_is_immutable (const Type *obj) +{ + return !obj->header.writable.get_relaxed (); +} +template <typename Type> +static inline void hb_object_make_immutable (const Type *obj) +{ + obj->header.writable.set_relaxed (false); +} +template <typename Type> static inline Type *hb_object_reference (Type *obj) { hb_object_trace (obj, HB_FUNC); @@ -171,10 +287,12 @@ template <typename Type> static inline void hb_object_fini (Type *obj) { obj->header.ref_count.fini (); /* Do this before user_data */ - if (obj->header.user_data) + hb_user_data_array_t *user_data = obj->header.user_data.get (); + if (user_data) { - obj->header.user_data->fini (); - free (obj->header.user_data); + user_data->fini (); + free (user_data); + user_data = nullptr; } } template <typename Type> @@ -189,14 +307,14 @@ static inline bool hb_object_set_user_data (Type *obj, assert (hb_object_is_valid (obj)); retry: - hb_user_data_array_t *user_data = (hb_user_data_array_t *) hb_atomic_ptr_get (&obj->header.user_data); + hb_user_data_array_t *user_data = obj->header.user_data.get (); if (unlikely (!user_data)) { user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1); if (unlikely (!user_data)) return false; user_data->init (); - if (unlikely (!hb_atomic_ptr_cmpexch (&obj->header.user_data, nullptr, user_data))) + if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data))) { user_data->fini (); free (user_data); @@ -211,11 +329,14 @@ template <typename Type> static inline void *hb_object_get_user_data (Type *obj, hb_user_data_key_t *key) { - if (unlikely (!obj || hb_object_is_inert (obj) || !obj->header.user_data)) + if (unlikely (!obj || hb_object_is_inert (obj))) return nullptr; assert (hb_object_is_valid (obj)); - return obj->header.user_data->get (key); + hb_user_data_array_t *user_data = obj->header.user_data.get (); + if (!user_data) + return nullptr; + return user_data->get (key); } -#endif /* HB_OBJECT_PRIVATE_HH */ +#endif /* HB_OBJECT_HH */ diff --git a/src/hb-open-file-private.hh b/src/hb-open-file.hh index 2965b46..32a223c 100644 --- a/src/hb-open-file-private.hh +++ b/src/hb-open-file.hh @@ -26,10 +26,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OPEN_FILE_PRIVATE_HH -#define HB_OPEN_FILE_PRIVATE_HH +#ifndef HB_OPEN_FILE_HH +#define HB_OPEN_FILE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-head-table.hh" @@ -54,8 +54,7 @@ struct TTCHeader; typedef struct TableRecord { - int cmp (Tag t) const - { return -t.cmp (tag); } + int cmp (Tag t) const { return -t.cmp (tag); } static int cmp (const void *pa, const void *pb) { @@ -64,7 +63,7 @@ typedef struct TableRecord return b->cmp (a->tag); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -83,13 +82,10 @@ typedef struct OffsetTable { friend struct OpenTypeFontFile; - inline unsigned int get_table_count (void) const - { return tables.len; } - inline const TableRecord& get_table (unsigned int i) const - { - return tables[i]; - } - inline unsigned int get_table_tags (unsigned int start_offset, + unsigned int get_table_count () const { return tables.len; } + const TableRecord& get_table (unsigned int i) const + { return tables[i]; } + unsigned int get_table_tags (unsigned int start_offset, unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */) const { @@ -107,18 +103,13 @@ typedef struct OffsetTable } return tables.len; } - inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const + bool find_table_index (hb_tag_t tag, unsigned int *table_index) const { Tag t; t.set (tag); - /* Linear-search for small tables to work around fonts with unsorted - * table list. */ - int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t); - if (table_index) - *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i; - return i != -1; + return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); } - inline const TableRecord& get_table_by_tag (hb_tag_t tag) const + const TableRecord& get_table_by_tag (hb_tag_t tag) const { unsigned int table_index; find_table_index (tag, &table_index); @@ -127,11 +118,10 @@ typedef struct OffsetTable public: - inline bool serialize (hb_serialize_context_t *c, - hb_tag_t sfnt_tag, - Supplier<hb_tag_t> &tags, - Supplier<hb_blob_t *> &blobs, - unsigned int table_count) + template <typename item_t> + bool serialize (hb_serialize_context_t *c, + hb_tag_t sfnt_tag, + hb_array_t<item_t> items) { TRACE_SERIALIZE (this); /* Alloc 12 for the OTHeader. */ @@ -140,17 +130,17 @@ typedef struct OffsetTable sfnt_version.set (sfnt_tag); /* Take space for numTables, searchRange, entrySelector, RangeShift * and the TableRecords themselves. */ - if (unlikely (!tables.serialize (c, table_count))) return_trace (false); + if (unlikely (!tables.serialize (c, items.length))) return_trace (false); const char *dir_end = (const char *) c->head; HBUINT32 *checksum_adjustment = nullptr; /* Write OffsetTables, alloc for and write actual table blobs. */ - for (unsigned int i = 0; i < table_count; i++) + for (unsigned int i = 0; i < tables.len; i++) { TableRecord &rec = tables.arrayZ[i]; - hb_blob_t *blob = blobs[i]; - rec.tag.set (tags[i]); + hb_blob_t *blob = items[i].blob; + rec.tag.set (items[i].tag); rec.length.set (hb_blob_get_length (blob)); rec.offset.serialize (c, this); @@ -160,12 +150,12 @@ typedef struct OffsetTable memcpy (start, hb_blob_get_data (blob, nullptr), rec.length); - /* 4-byte allignment. */ - if (rec.length % 4) - c->allocate_size<void> (4 - rec.length % 4); + /* 4-byte alignment. */ + c->align (4); const char *end = (const char *) c->head; - if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size) + if (items[i].tag == HB_OT_TAG_head && + (unsigned) (end - start) >= head::static_size) { head *h = (head *) start; checksum_adjustment = &h->checkSumAdjustment; @@ -174,8 +164,6 @@ typedef struct OffsetTable rec.checkSum.set_for_data (start, end - start); } - tags += table_count; - blobs += table_count; tables.qsort (); @@ -186,7 +174,7 @@ typedef struct OffsetTable /* The following line is a slower version of the following block. */ //checksum.set_for_data (this, (const char *) c->head - (const char *) this); checksum.set_for_data (this, dir_end - (const char *) this); - for (unsigned int i = 0; i < table_count; i++) + for (unsigned int i = 0; i < items.length; i++) { TableRecord &rec = tables.arrayZ[i]; checksum.set (checksum + rec.checkSum); @@ -198,7 +186,7 @@ typedef struct OffsetTable return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && tables.sanitize (c)); @@ -221,10 +209,10 @@ struct TTCHeaderVersion1 { friend struct TTCHeader; - inline unsigned int get_face_count (void) const { return table.len; } - inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } + unsigned int get_face_count () const { return table.len; } + const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (table.sanitize (c, this)); @@ -247,7 +235,7 @@ struct TTCHeader private: - inline unsigned int get_face_count (void) const + unsigned int get_face_count () const { switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ @@ -255,7 +243,7 @@ struct TTCHeader default:return 0; } } - inline const OpenTypeFontFace& get_face (unsigned int i) const + const OpenTypeFontFace& get_face (unsigned int i) const { switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ @@ -264,7 +252,7 @@ struct TTCHeader } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!u.header.version.sanitize (c))) return_trace (false); @@ -286,6 +274,165 @@ struct TTCHeader } u; }; +/* + * Mac Resource Fork + * + * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html + */ + +struct ResourceRecord +{ + const OpenTypeFontFace & get_face (const void *data_base) const + { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); } + + bool sanitize (hb_sanitize_context_t *c, + const void *data_base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + offset.sanitize (c, data_base) && + get_face (data_base).sanitize (c)); + } + + protected: + HBUINT16 id; /* Resource ID. */ + HBINT16 nameOffset; /* Offset from beginning of resource name list + * to resource name, -1 means there is none. */ + HBUINT8 attrs; /* Resource attributes */ + NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24> + offset; /* Offset from beginning of data block to + * data for this resource */ + HBUINT32 reserved; /* Reserved for handle to resource */ + public: + DEFINE_SIZE_STATIC (12); +}; + +#define HB_TAG_sfnt HB_TAG ('s','f','n','t') + +struct ResourceTypeRecord +{ + unsigned int get_resource_count () const + { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; } + + bool is_sfnt () const { return tag == HB_TAG_sfnt; } + + const ResourceRecord& get_resource_record (unsigned int i, + const void *type_base) const + { return (type_base+resourcesZ).as_array (get_resource_count ())[i]; } + + bool sanitize (hb_sanitize_context_t *c, + const void *type_base, + const void *data_base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + resourcesZ.sanitize (c, type_base, + get_resource_count (), + data_base)); + } + + protected: + Tag tag; /* Resource type. */ + HBUINT16 resCountM1; /* Number of resources minus 1. */ + NNOffsetTo<UnsizedArrayOf<ResourceRecord> > + resourcesZ; /* Offset from beginning of resource type list + * to reference item list for this type. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct ResourceMap +{ + unsigned int get_face_count () const + { + unsigned int count = get_type_count (); + for (unsigned int i = 0; i < count; i++) + { + const ResourceTypeRecord& type = get_type_record (i); + if (type.is_sfnt ()) + return type.get_resource_count (); + } + return 0; + } + + const OpenTypeFontFace& get_face (unsigned int idx, + const void *data_base) const + { + unsigned int count = get_type_count (); + for (unsigned int i = 0; i < count; i++) + { + const ResourceTypeRecord& type = get_type_record (i); + /* The check for idx < count is here because ResourceRecord is NOT null-safe. + * Because an offset of 0 there does NOT mean null. */ + if (type.is_sfnt () && idx < type.get_resource_count ()) + return type.get_resource_record (idx, &(this+typeList)).get_face (data_base); + } + return Null (OpenTypeFontFace); + } + + bool sanitize (hb_sanitize_context_t *c, const void *data_base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + typeList.sanitize (c, this, + &(this+typeList), + data_base)); + } + + private: + unsigned int get_type_count () const { return (this+typeList).lenM1 + 1; } + + const ResourceTypeRecord& get_type_record (unsigned int i) const + { return (this+typeList)[i]; } + + protected: + HBUINT8 reserved0[16]; /* Reserved for copy of resource header */ + HBUINT32 reserved1; /* Reserved for handle to next resource map */ + HBUINT16 resreved2; /* Reserved for file reference number */ + HBUINT16 attrs; /* Resource fork attribute */ + NNOffsetTo<ArrayOfM1<ResourceTypeRecord> > + typeList; /* Offset from beginning of map to + * resource type list */ + Offset16 nameList; /* Offset from beginning of map to + * resource name list */ + public: + DEFINE_SIZE_STATIC (28); +}; + +struct ResourceForkHeader +{ + unsigned int get_face_count () const + { return (this+map).get_face_count (); } + + const OpenTypeFontFace& get_face (unsigned int idx, + unsigned int *base_offset = nullptr) const + { + const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data)); + if (base_offset) + *base_offset = (const char *) &face - (const char *) this; + return face; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + data.sanitize (c, this, dataLen) && + map.sanitize (c, this, &(this+data))); + } + + protected: + LNNOffsetTo<UnsizedArrayOf<HBUINT8> > + data; /* Offset from beginning of resource fork + * to resource data */ + LNNOffsetTo<ResourceMap > + map; /* Offset from beginning of resource fork + * to resource map */ + HBUINT32 dataLen; /* Length of resource data */ + HBUINT32 mapLen; /* Length of resource map */ + public: + DEFINE_SIZE_STATIC (16); +}; /* * OpenType Font File @@ -293,19 +440,18 @@ struct TTCHeader struct OpenTypeFontFile { - static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */ - enum { CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ - TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ + TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ + DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ }; - inline hb_tag_t get_tag (void) const { return u.tag; } + hb_tag_t get_tag () const { return u.tag; } - inline unsigned int get_face_count (void) const + unsigned int get_face_count () const { switch (u.tag) { case CFFTag: /* All the non-collection tags */ @@ -313,11 +459,14 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return 1; case TTCTag: return u.ttcHeader.get_face_count (); + case DFontTag: return u.rfHeader.get_face_count (); default: return 0; } } - inline const OpenTypeFontFace& get_face (unsigned int i) const + const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const { + if (base_offset) + *base_offset = 0; switch (u.tag) { /* Note: for non-collection SFNT data we ignore index. This is because * Apple dfont container is a container of SFNT's. So each SFNT is a @@ -327,23 +476,23 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return u.fontFace; case TTCTag: return u.ttcHeader.get_face (i); + case DFontTag: return u.rfHeader.get_face (i, base_offset); default: return Null(OpenTypeFontFace); } } - inline bool serialize_single (hb_serialize_context_t *c, - hb_tag_t sfnt_tag, - Supplier<hb_tag_t> &tags, - Supplier<hb_blob_t *> &blobs, - unsigned int table_count) + template <typename item_t> + bool serialize_single (hb_serialize_context_t *c, + hb_tag_t sfnt_tag, + hb_array_t<item_t> items) { TRACE_SERIALIZE (this); assert (sfnt_tag != TTCTag); if (unlikely (!c->extend_min (*this))) return_trace (false); - return_trace (u.fontFace.serialize (c, sfnt_tag, tags, blobs, table_count)); + return_trace (u.fontFace.serialize (c, sfnt_tag, items)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!u.tag.sanitize (c))) return_trace (false); @@ -353,6 +502,7 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); case TTCTag: return_trace (u.ttcHeader.sanitize (c)); + case DFontTag: return_trace (u.rfHeader.sanitize (c)); default: return_trace (true); } } @@ -362,6 +512,7 @@ struct OpenTypeFontFile Tag tag; /* 4-byte identifier. */ OpenTypeFontFace fontFace; TTCHeader ttcHeader; + ResourceForkHeader rfHeader; } u; public: DEFINE_SIZE_UNION (4, tag); @@ -371,4 +522,4 @@ struct OpenTypeFontFile } /* namespace OT */ -#endif /* HB_OPEN_FILE_PRIVATE_HH */ +#endif /* HB_OPEN_FILE_HH */ diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh deleted file mode 100644 index 8180287..0000000 --- a/src/hb-open-type-private.hh +++ /dev/null @@ -1,1299 +0,0 @@ -/* - * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 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. - * - * Red Hat Author(s): Behdad Esfahbod - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OPEN_TYPE_PRIVATE_HH -#define HB_OPEN_TYPE_PRIVATE_HH - -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-blob-private.hh" -#include "hb-face-private.hh" - - -namespace OT { - - - -/* - * Casts - */ - -/* Cast to struct T, reference to reference */ -template<typename Type, typename TObject> -static inline const Type& CastR(const TObject &X) -{ return reinterpret_cast<const Type&> (X); } -template<typename Type, typename TObject> -static inline Type& CastR(TObject &X) -{ return reinterpret_cast<Type&> (X); } - -/* Cast to struct T, pointer to pointer */ -template<typename Type, typename TObject> -static inline const Type* CastP(const TObject *X) -{ return reinterpret_cast<const Type*> (X); } -template<typename Type, typename TObject> -static inline Type* CastP(TObject *X) -{ return reinterpret_cast<Type*> (X); } - -/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory - * location pointed to by P plus Ofs bytes. */ -template<typename Type> -static inline const Type& StructAtOffset(const void *P, unsigned int offset) -{ return * reinterpret_cast<const Type*> ((const char *) P + offset); } -template<typename Type> -static inline Type& StructAtOffset(void *P, unsigned int offset) -{ return * reinterpret_cast<Type*> ((char *) P + offset); } - -/* StructAfter<T>(X) returns the struct T& that is placed after X. - * Works with X of variable size also. X must implement get_size() */ -template<typename Type, typename TObject> -static inline const Type& StructAfter(const TObject &X) -{ return StructAtOffset<Type>(&X, X.get_size()); } -template<typename Type, typename TObject> -static inline Type& StructAfter(TObject &X) -{ return StructAtOffset<Type>(&X, X.get_size()); } - - - -/* - * Size checking - */ - -/* Check _assertion in a method environment */ -#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ - inline void _instance_assertion_on_line_##_line (void) const \ - { \ - static_assert ((_assertion), ""); \ - ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \ - } -# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) -# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) - -/* Check that _code compiles in a method environment */ -#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ - inline void _compiles_assertion_on_line_##_line (void) const \ - { _code; } -# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) -# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) - - -#define DEFINE_SIZE_STATIC(size) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \ - static const unsigned int static_size = (size); \ - static const unsigned int min_size = (size); \ - inline unsigned int get_size (void) const { return (size); } - -#define DEFINE_SIZE_UNION(size, _member) \ - DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \ - static const unsigned int min_size = (size) - -#define DEFINE_SIZE_MIN(size) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \ - static const unsigned int min_size = (size) - -#define DEFINE_SIZE_ARRAY(size, array) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \ - DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \ - static const unsigned int min_size = (size) - -#define DEFINE_SIZE_ARRAY2(size, array1, array2) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \ - DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \ - static const unsigned int min_size = (size) - - - -/* - * Dispatch - */ - -template <typename Context, typename Return, unsigned int MaxDebugDepth> -struct hb_dispatch_context_t -{ - static const unsigned int max_debug_depth = MaxDebugDepth; - typedef Return return_t; - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } - static return_t no_dispatch_return_value (void) { return Context::default_return_value (); } -}; - - -/* - * Sanitize - */ - -/* This limits sanitizing time on really broken fonts. */ -#ifndef HB_SANITIZE_MAX_EDITS -#define HB_SANITIZE_MAX_EDITS 32 -#endif -#ifndef HB_SANITIZE_MAX_OPS_FACTOR -#define HB_SANITIZE_MAX_OPS_FACTOR 8 -#endif -#ifndef HB_SANITIZE_MAX_OPS_MIN -#define HB_SANITIZE_MAX_OPS_MIN 16384 -#endif - -struct hb_sanitize_context_t : - hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE> -{ - inline hb_sanitize_context_t (void) : - debug_depth (0), - start (nullptr), end (nullptr), - writable (false), edit_count (0), max_ops (0), - blob (nullptr), - num_glyphs (0) {} - - inline const char *get_name (void) { return "SANITIZE"; } - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) - { return format->sanitize (this); } - template <typename T> - inline return_t dispatch (const T &obj) { return obj.sanitize (this); } - static return_t default_return_value (void) { return true; } - static return_t no_dispatch_return_value (void) { return false; } - bool stop_sublookup_iteration (const return_t r) const { return !r; } - - inline void init (hb_blob_t *b) - { - this->blob = hb_blob_reference (b); - this->writable = false; - } - - inline void start_processing (void) - { - this->start = hb_blob_get_data (this->blob, nullptr); - this->end = this->start + this->blob->length; - assert (this->start <= this->end); /* Must not overflow. */ - this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, - (unsigned) HB_SANITIZE_MAX_OPS_MIN); - this->edit_count = 0; - this->debug_depth = 0; - - DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, - "start [%p..%p] (%lu bytes)", - this->start, this->end, - (unsigned long) (this->end - this->start)); - } - - inline void end_processing (void) - { - DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, - "end [%p..%p] %u edit requests", - this->start, this->end, this->edit_count); - - hb_blob_destroy (this->blob); - this->blob = nullptr; - this->start = this->end = nullptr; - } - - inline bool check_range (const void *base, unsigned int len) const - { - const char *p = (const char *) base; - bool ok = this->max_ops-- > 0 && - this->start <= p && - p <= this->end && - (unsigned int) (this->end - p) >= len; - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s", - p, p + len, len, - this->start, this->end, - ok ? "OK" : "OUT-OF-RANGE"); - - return likely (ok); - } - - inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const - { - const char *p = (const char *) base; - bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); - unsigned int array_size = record_size * len; - bool ok = !overflows && this->check_range (base, array_size); - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s", - p, p + (record_size * len), record_size, len, (unsigned int) array_size, - this->start, this->end, - overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE"); - - return likely (ok); - } - - template <typename Type> - inline bool check_struct (const Type *obj) const - { - return likely (this->check_range (obj, obj->min_size)); - } - - inline bool may_edit (const void *base, unsigned int len) - { - if (this->edit_count >= HB_SANITIZE_MAX_EDITS) - return false; - - const char *p = (const char *) base; - this->edit_count++; - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", - this->edit_count, - p, p + len, len, - this->start, this->end, - this->writable ? "GRANTED" : "DENIED"); - - return this->writable; - } - - template <typename Type, typename ValueType> - inline bool try_set (const Type *obj, const ValueType &v) { - if (this->may_edit (obj, obj->static_size)) { - const_cast<Type *> (obj)->set (v); - return true; - } - return false; - } - - mutable unsigned int debug_depth; - const char *start, *end; - bool writable; - unsigned int edit_count; - mutable int max_ops; - hb_blob_t *blob; - unsigned int num_glyphs; -}; - - - -/* Template to sanitize an object. */ -template <typename Type> -struct Sanitizer -{ - inline Sanitizer (void) {} - - inline hb_blob_t *sanitize (hb_blob_t *blob) { - bool sane; - - /* TODO is_sane() stuff */ - - c->init (blob); - - retry: - DEBUG_MSG_FUNC (SANITIZE, c->start, "start"); - - c->start_processing (); - - if (unlikely (!c->start)) { - c->end_processing (); - return blob; - } - - Type *t = CastP<Type> (const_cast<char *> (c->start)); - - sane = t->sanitize (c); - if (sane) { - if (c->edit_count) { - DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count); - - /* sanitize again to ensure no toe-stepping */ - c->edit_count = 0; - sane = t->sanitize (c); - if (c->edit_count) { - DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count); - sane = false; - } - } - } else { - unsigned int edit_count = c->edit_count; - if (edit_count && !c->writable) { - c->start = hb_blob_get_data_writable (blob, nullptr); - c->end = c->start + blob->length; - - if (c->start) { - c->writable = true; - /* ok, we made it writable by relocating. try again */ - DEBUG_MSG_FUNC (SANITIZE, c->start, "retry"); - goto retry; - } - } - } - - c->end_processing (); - - DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED"); - if (sane) - { - blob->lock (); - return blob; - } - else - { - hb_blob_destroy (blob); - return hb_blob_get_empty (); - } - } - - inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; } - - private: - hb_sanitize_context_t c[1]; -}; - - - -/* - * Serialize - */ - - -struct hb_serialize_context_t -{ - inline hb_serialize_context_t (void *start_, unsigned int size) - { - this->start = (char *) start_; - this->end = this->start + size; - - this->ran_out_of_room = false; - this->head = this->start; - this->debug_depth = 0; - } - - template <typename Type> - inline Type *start_serialize (void) - { - DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, - "start [%p..%p] (%lu bytes)", - this->start, this->end, - (unsigned long) (this->end - this->start)); - - return start_embed<Type> (); - } - - inline void end_serialize (void) - { - DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, - "end [%p..%p] serialized %d bytes; %s", - this->start, this->end, - (int) (this->head - this->start), - this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room"); - - } - - template <typename Type> - inline Type *copy (void) - { - assert (!this->ran_out_of_room); - unsigned int len = this->head - this->start; - void *p = malloc (len); - if (p) - memcpy (p, this->start, len); - return reinterpret_cast<Type *> (p); - } - - template <typename Type> - inline Type *allocate_size (unsigned int size) - { - if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) { - this->ran_out_of_room = true; - return nullptr; - } - memset (this->head, 0, size); - char *ret = this->head; - this->head += size; - return reinterpret_cast<Type *> (ret); - } - - template <typename Type> - inline Type *allocate_min (void) - { - return this->allocate_size<Type> (Type::min_size); - } - - template <typename Type> - inline Type *start_embed (void) - { - Type *ret = reinterpret_cast<Type *> (this->head); - return ret; - } - - template <typename Type> - inline Type *embed (const Type &obj) - { - unsigned int size = obj.get_size (); - Type *ret = this->allocate_size<Type> (size); - if (unlikely (!ret)) return nullptr; - memcpy (ret, obj, size); - return ret; - } - - template <typename Type> - inline Type *extend_min (Type &obj) - { - unsigned int size = obj.min_size; - assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); - if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr; - return reinterpret_cast<Type *> (&obj); - } - - template <typename Type> - inline Type *extend (Type &obj) - { - unsigned int size = obj.get_size (); - assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); - if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr; - return reinterpret_cast<Type *> (&obj); - } - - inline void truncate (void *new_head) - { - assert (this->start < new_head && new_head <= this->head); - this->head = (char *) new_head; - } - - unsigned int debug_depth; - char *start, *end, *head; - bool ran_out_of_room; -}; - -template <typename Type> -struct Supplier -{ - inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type)) - { - head = array; - len = len_; - stride = stride_; - } - inline const Type operator [] (unsigned int i) const - { - if (unlikely (i >= len)) return Type (); - return * (const Type *) (const void *) ((const char *) head + stride * i); - } - - inline Supplier<Type> & operator += (unsigned int count) - { - if (unlikely (count > len)) - count = len; - len -= count; - head = (const Type *) (const void *) ((const char *) head + stride * count); - return *this; - } - - private: - inline Supplier (const Supplier<Type> &); /* Disallow copy */ - inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */ - - unsigned int len; - unsigned int stride; - const Type *head; -}; - - -/* - * - * The OpenType Font File: Data Types - */ - - -/* "The following data types are used in the OpenType font file. - * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ - -/* - * Int types - */ - - -template <typename Type, int Bytes> struct BEInt; - -template <typename Type> -struct BEInt<Type, 1> -{ - public: - inline void set (Type V) - { - v = V; - } - inline operator Type (void) const - { - return v; - } - private: uint8_t v; -}; -template <typename Type> -struct BEInt<Type, 2> -{ - public: - inline void set (Type V) - { - v[0] = (V >> 8) & 0xFF; - v[1] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[0] << 8) - + (v[1] ); - } - private: uint8_t v[2]; -}; -template <typename Type> -struct BEInt<Type, 3> -{ - public: - inline void set (Type V) - { - v[0] = (V >> 16) & 0xFF; - v[1] = (V >> 8) & 0xFF; - v[2] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[0] << 16) - + (v[1] << 8) - + (v[2] ); - } - private: uint8_t v[3]; -}; -template <typename Type> -struct BEInt<Type, 4> -{ - public: - inline void set (Type V) - { - v[0] = (V >> 24) & 0xFF; - v[1] = (V >> 16) & 0xFF; - v[2] = (V >> 8) & 0xFF; - v[3] = (V ) & 0xFF; - } - inline operator Type (void) const - { - return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); - } - private: uint8_t v[4]; -}; - -/* Integer types in big-endian order and no alignment requirement */ -template <typename Type, unsigned int Size> -struct IntType -{ - inline void set (Type i) { v.set (i); } - inline operator Type(void) const { return v; } - inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; } - inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); } - static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); } - template <typename Type2> - inline int cmp (Type2 a) const - { - Type b = v; - if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) - return (int) a - (int) b; - else - return a < b ? -1 : a == b ? 0 : +1; - } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); - } - protected: - BEInt<Type, Size> v; - public: - DEFINE_SIZE_STATIC (Size); -}; - -typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */ -typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */ -typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */ -typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */ -typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */ -typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */ -typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ - -/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ -typedef HBINT16 FWORD; - -/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ -typedef HBUINT16 UFWORD; - -/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ -struct F2DOT14 : HBINT16 -{ - // 16384 means 1<<14 - inline float to_float (void) const { return ((int32_t) v) / 16384.f; } - inline void set_float (float f) { v.set (round (f * 16384.f)); } - public: - DEFINE_SIZE_STATIC (2); -}; - -/* 32-bit signed fixed-point number (16.16). */ -struct Fixed : HBINT32 -{ - // 65536 means 1<<16 - inline float to_float (void) const { return ((int32_t) v) / 65536.f; } - inline void set_float (float f) { v.set (round (f * 65536.f)); } - public: - DEFINE_SIZE_STATIC (4); -}; - -/* Date represented in number of seconds since 12:00 midnight, January 1, - * 1904. The value is represented as a signed 64-bit integer. */ -struct LONGDATETIME -{ - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); - } - protected: - HBINT32 major; - HBUINT32 minor; - public: - DEFINE_SIZE_STATIC (8); -}; - -/* Array of four uint8s (length = 32 bits) used to identify a script, language - * system, feature, or baseline */ -struct Tag : HBUINT32 -{ - /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ - inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); } - inline operator char* (void) { return reinterpret_cast<char *> (&this->v); } - public: - DEFINE_SIZE_STATIC (4); -}; -DEFINE_NULL_DATA (OT, Tag, " "); - -/* Glyph index number, same as uint16 (length = 16 bits) */ -typedef HBUINT16 GlyphID; - -/* Name-table index, same as uint16 (length = 16 bits) */ -typedef HBUINT16 NameID; - -/* Script/language-system/feature index */ -struct Index : HBUINT16 { - static const unsigned int NOT_FOUND_INDEX = 0xFFFFu; -}; -DEFINE_NULL_DATA (OT, Index, "\xff\xff"); - -/* Offset, Null offset = 0 */ -template <typename Type> -struct Offset : Type -{ - inline bool is_null (void) const { return 0 == *this; } - - inline void *serialize (hb_serialize_context_t *c, const void *base) - { - void *t = c->start_embed<void> (); - this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ - return t; - } - - public: - DEFINE_SIZE_STATIC (sizeof(Type)); -}; - -typedef Offset<HBUINT16> Offset16; -typedef Offset<HBUINT32> Offset32; - - -/* CheckSum */ -struct CheckSum : HBUINT32 -{ - /* This is reference implementation from the spec. */ - static inline uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) - { - uint32_t Sum = 0L; - assert (0 == (Length & 3)); - const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; - - while (Table < EndPtr) - Sum += *Table++; - return Sum; - } - - /* Note: data should be 4byte aligned and have 4byte padding at the end. */ - inline void set_for_data (const void *data, unsigned int length) - { set (CalcTableChecksum ((const HBUINT32 *) data, length)); } - - public: - DEFINE_SIZE_STATIC (4); -}; - - -/* - * Version Numbers - */ - -template <typename FixedType=HBUINT16> -struct FixedVersion -{ - inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - FixedType major; - FixedType minor; - public: - DEFINE_SIZE_STATIC (2 * sizeof(FixedType)); -}; - - - -/* - * Template subclasses of Offset that do the dereferencing. - * Use: (base+offset) - */ - -template <typename Type, typename OffsetType=HBUINT16> -struct OffsetTo : Offset<OffsetType> -{ - inline const Type& operator () (const void *base) const - { - unsigned int offset = *this; - if (unlikely (!offset)) return Null(Type); - return StructAtOffset<const Type> (base, offset); - } - inline Type& operator () (void *base) const - { - unsigned int offset = *this; - if (unlikely (!offset)) return Crap(Type); - return StructAtOffset<Type> (base, offset); - } - - inline Type& serialize (hb_serialize_context_t *c, const void *base) - { - return * (Type *) Offset<OffsetType>::serialize (c, base); - } - - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return_trace (false); - unsigned int offset = *this; - if (unlikely (!offset)) return_trace (true); - if (unlikely (!c->check_range (base, offset))) return_trace (false); - const Type &obj = StructAtOffset<Type> (base, offset); - return_trace (likely (obj.sanitize (c)) || neuter (c)); - } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return_trace (false); - unsigned int offset = *this; - if (unlikely (!offset)) return_trace (true); - if (unlikely (!c->check_range (base, offset))) return_trace (false); - const Type &obj = StructAtOffset<Type> (base, offset); - return_trace (likely (obj.sanitize (c, user_data)) || neuter (c)); - } - - /* Set the offset to Null */ - inline bool neuter (hb_sanitize_context_t *c) const { - return c->try_set (this, 0); - } - DEFINE_SIZE_STATIC (sizeof(OffsetType)); -}; -template <typename Type> struct LOffsetTo : OffsetTo<Type, HBUINT32> {}; -template <typename Base, typename OffsetType, typename Type> -static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); } -template <typename Base, typename OffsetType, typename Type> -static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); } - - -/* - * Array Types - */ - - -/* TODO Use it in ArrayOf, HeadlessArrayOf, and other places around the code base?? */ -template <typename Type> -struct UnsizedArrayOf -{ - inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; } - inline Type& operator [] (unsigned int i) { return arrayZ[i]; } - - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - - return_trace (true); - } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) - return_trace (false); - return_trace (true); - } - - inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count)); - } - - public: - Type arrayZ[VAR]; - public: - DEFINE_SIZE_ARRAY (0, arrayZ); -}; - -/* Unsized array of offset's */ -template <typename Type, typename OffsetType> -struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {}; - -/* Unsized array of offsets relative to the beginning of the array itself. */ -template <typename Type, typename OffsetType> -struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType> -{ - inline const Type& operator [] (unsigned int i) const - { - return this+this->arrayZ[i]; - } - - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this))); - } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const - { - TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data))); - } -}; - - -/* An array with a number of elements. */ -template <typename Type, typename LenType=HBUINT16> -struct ArrayOf -{ - const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const - { - unsigned int count = len; - if (unlikely (start_offset > count)) - count = 0; - else - count -= start_offset; - count = MIN (count, *pcount); - *pcount = count; - return arrayZ + start_offset; - } - - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= len)) return Null(Type); - return arrayZ[i]; - } - inline Type& operator [] (unsigned int i) - { - if (unlikely (i >= len)) return Crap(Type); - return arrayZ[i]; - } - inline unsigned int get_size (void) const - { return len.static_size + len * Type::static_size; } - - inline bool serialize (hb_serialize_context_t *c, - unsigned int items_len) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - len.set (items_len); /* TODO(serialize) Overflow? */ - if (unlikely (!c->extend (*this))) return_trace (false); - return_trace (true); - } - - inline bool serialize (hb_serialize_context_t *c, - Supplier<Type> &items, - unsigned int items_len) - { - TRACE_SERIALIZE (this); - if (unlikely (!serialize (c, items_len))) return_trace (false); - for (unsigned int i = 0; i < items_len; i++) - arrayZ[i] = items[i]; - items += items_len; - return_trace (true); - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - - return_trace (true); - } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) - return_trace (false); - return_trace (true); - } - - template <typename SearchType> - inline int lsearch (const SearchType &x) const - { - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - if (!this->arrayZ[i].cmp (x)) - return i; - return -1; - } - - inline void qsort (void) - { - ::qsort (arrayZ, len, sizeof (Type), Type::cmp); - } - - private: - inline bool sanitize_shallow (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && c->check_array (arrayZ, Type::static_size, len)); - } - - public: - LenType len; - Type arrayZ[VAR]; - public: - DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); -}; -template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {}; - -/* Array of Offset's */ -template <typename Type, typename OffsetType=HBUINT16> -struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {}; - -/* Array of offsets relative to the beginning of the array itself. */ -template <typename Type> -struct OffsetListOf : OffsetArrayOf<Type> -{ - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= this->len)) return Null(Type); - return this+this->arrayZ[i]; - } - inline const Type& operator [] (unsigned int i) - { - if (unlikely (i >= this->len)) return Crap(Type); - return this+this->arrayZ[i]; - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (OffsetArrayOf<Type>::sanitize (c, this)); - } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, T user_data) const - { - TRACE_SANITIZE (this); - return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data)); - } -}; - - -/* An array starting at second element. */ -template <typename Type, typename LenType=HBUINT16> -struct HeadlessArrayOf -{ - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= len || !i)) return Null(Type); - return arrayZ[i-1]; - } - inline Type& operator [] (unsigned int i) - { - if (unlikely (i >= len || !i)) return Crap(Type); - return arrayZ[i-1]; - } - inline unsigned int get_size (void) const - { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } - - inline bool serialize (hb_serialize_context_t *c, - Supplier<Type> &items, - unsigned int items_len) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - len.set (items_len); /* TODO(serialize) Overflow? */ - if (unlikely (!items_len)) return_trace (true); - if (unlikely (!c->extend (*this))) return_trace (false); - for (unsigned int i = 0; i < items_len - 1; i++) - arrayZ[i] = items[i]; - items += items_len - 1; - return_trace (true); - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - - return_trace (true); - } - - private: - inline bool sanitize_shallow (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && - (!len || c->check_array (arrayZ, Type::static_size, len - 1))); - } - - public: - LenType len; - Type arrayZ[VAR]; - public: - DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); -}; - - -/* - * An array with sorted elements. Supports binary searching. - */ -template <typename Type, typename LenType=HBUINT16> -struct SortedArrayOf : ArrayOf<Type, LenType> -{ - template <typename SearchType> - inline int bsearch (const SearchType &x) const - { - /* Hand-coded bsearch here since this is in the hot inner loop. */ - const Type *arr = this->arrayZ; - int min = 0, max = (int) this->len - 1; - while (min <= max) - { - int mid = (min + max) / 2; - int c = arr[mid].cmp (x); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - return mid; - } - return -1; - } -}; - -/* - * Binary-search arrays - */ - -struct BinSearchHeader -{ - inline operator uint32_t (void) const { return len; } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - inline void set (unsigned int v) - { - len.set (v); - assert (len == v); - entrySelector.set (MAX (1u, _hb_bit_storage (v)) - 1); - searchRange.set (16 * (1u << entrySelector)); - rangeShift.set (v * 16 > searchRange - ? 16 * v - searchRange - : 0); - } - - protected: - HBUINT16 len; - HBUINT16 searchRange; - HBUINT16 entrySelector; - HBUINT16 rangeShift; - - public: - DEFINE_SIZE_STATIC (8); -}; - -template <typename Type> -struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {}; - - -/* Lazy struct and blob loaders. */ - -/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */ -template <typename T> -struct hb_lazy_loader_t -{ - inline void init (hb_face_t *face_) - { - face = face_; - instance = nullptr; - } - - inline void fini (void) - { - if (instance && instance != &Null(T)) - { - instance->fini(); - free (instance); - } - } - - inline const T* get (void) const - { - retry: - T *p = (T *) hb_atomic_ptr_get (&instance); - if (unlikely (!p)) - { - p = (T *) calloc (1, sizeof (T)); - if (unlikely (!p)) - p = const_cast<T *> (&Null(T)); - else - p->init (face); - if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p))) - { - if (p != &Null(T)) - p->fini (); - goto retry; - } - } - return p; - } - - inline const T* operator-> (void) const - { - return get (); - } - - private: - hb_face_t *face; - T *instance; -}; - -/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */ -template <typename T> -struct hb_table_lazy_loader_t -{ - inline void init (hb_face_t *face_) - { - face = face_; - blob = nullptr; - } - - inline void fini (void) - { - hb_blob_destroy (blob); - } - - inline const T* get (void) const - { - retry: - hb_blob_t *blob_ = (hb_blob_t *) hb_atomic_ptr_get (&blob); - if (unlikely (!blob_)) - { - blob_ = OT::Sanitizer<T>().sanitize (face->reference_table (T::tableTag)); - if (!hb_atomic_ptr_cmpexch (&blob, nullptr, blob_)) - { - hb_blob_destroy (blob_); - goto retry; - } - blob = blob_; - } - return blob_->as<T> (); - } - - inline const T* operator-> (void) const - { - return get(); - } - - private: - hb_face_t *face; - mutable hb_blob_t *blob; -}; - - -} /* namespace OT */ - - -#endif /* HB_OPEN_TYPE_PRIVATE_HH */ diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh new file mode 100644 index 0000000..6abb898 --- /dev/null +++ b/src/hb-open-type.hh @@ -0,0 +1,1008 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OPEN_TYPE_HH +#define HB_OPEN_TYPE_HH + +#include "hb.hh" +#include "hb-blob.hh" +#include "hb-face.hh" +#include "hb-machinery.hh" +#include "hb-subset.hh" + + +namespace OT { + + +/* + * + * The OpenType Font File: Data Types + */ + + +/* "The following data types are used in the OpenType font file. + * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ + +/* + * Int types + */ + +template <bool is_signed> struct hb_signedness_int; +template <> struct hb_signedness_int<false> { typedef unsigned int value; }; +template <> struct hb_signedness_int<true> { typedef signed int value; }; + +/* Integer types in big-endian order and no alignment requirement */ +template <typename Type, unsigned int Size> +struct IntType +{ + typedef Type type; + typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type; + + void set (wide_type i) { v.set (i); } + operator wide_type () const { return v; } + bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; } + bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); } + static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); } + template <typename Type2> + int cmp (Type2 a) const + { + Type b = v; + if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) + return (int) a - (int) b; + else + return a < b ? -1 : a == b ? 0 : +1; + } + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + protected: + BEInt<Type, Size> v; + public: + DEFINE_SIZE_STATIC (Size); +}; + +typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */ +typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */ +typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */ +typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */ +typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */ +typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */ +/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. + * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ +typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ + +/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ +typedef HBINT16 FWORD; + +/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ +typedef HBINT32 FWORD32; + +/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ +typedef HBUINT16 UFWORD; + +/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ +struct F2DOT14 : HBINT16 +{ + // 16384 means 1<<14 + float to_float () const { return ((int32_t) v) / 16384.f; } + void set_float (float f) { v.set (round (f * 16384.f)); } + public: + DEFINE_SIZE_STATIC (2); +}; + +/* 32-bit signed fixed-point number (16.16). */ +struct Fixed : HBINT32 +{ + // 65536 means 1<<16 + float to_float () const { return ((int32_t) v) / 65536.f; } + void set_float (float f) { v.set (round (f * 65536.f)); } + public: + DEFINE_SIZE_STATIC (4); +}; + +/* Date represented in number of seconds since 12:00 midnight, January 1, + * 1904. The value is represented as a signed 64-bit integer. */ +struct LONGDATETIME +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + protected: + HBINT32 major; + HBUINT32 minor; + public: + DEFINE_SIZE_STATIC (8); +}; + +/* Array of four uint8s (length = 32 bits) used to identify a script, language + * system, feature, or baseline */ +struct Tag : HBUINT32 +{ + /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ + operator const char* () const { return reinterpret_cast<const char *> (&this->v); } + operator char* () { return reinterpret_cast<char *> (&this->v); } + public: + DEFINE_SIZE_STATIC (4); +}; + +/* Glyph index number, same as uint16 (length = 16 bits) */ +typedef HBUINT16 GlyphID; + +/* Script/language-system/feature index */ +struct Index : HBUINT16 { + static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; +}; +DECLARE_NULL_NAMESPACE_BYTES (OT, Index); + +typedef Index NameID; + +/* Offset, Null offset = 0 */ +template <typename Type, bool has_null=true> +struct Offset : Type +{ + typedef Type type; + + bool is_null () const { return has_null && 0 == *this; } + + void *serialize (hb_serialize_context_t *c, const void *base) + { + void *t = c->start_embed<void> (); + this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ + return t; + } + + public: + DEFINE_SIZE_STATIC (sizeof (Type)); +}; + +typedef Offset<HBUINT16> Offset16; +typedef Offset<HBUINT32> Offset32; + + +/* CheckSum */ +struct CheckSum : HBUINT32 +{ + /* This is reference implementation from the spec. */ + static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) + { + uint32_t Sum = 0L; + assert (0 == (Length & 3)); + const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; + + while (Table < EndPtr) + Sum += *Table++; + return Sum; + } + + /* Note: data should be 4byte aligned and have 4byte padding at the end. */ + void set_for_data (const void *data, unsigned int length) + { set (CalcTableChecksum ((const HBUINT32 *) data, length)); } + + public: + DEFINE_SIZE_STATIC (4); +}; + + +/* + * Version Numbers + */ + +template <typename FixedType=HBUINT16> +struct FixedVersion +{ + uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + FixedType major; + FixedType minor; + public: + DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); +}; + + +/* + * Template subclasses of Offset that do the dereferencing. + * Use: (base+offset) + */ + +template <typename Type, bool has_null> +struct _hb_has_null +{ + static const Type *get_null () { return nullptr; } + static Type *get_crap () { return nullptr; } +}; +template <typename Type> +struct _hb_has_null<Type, true> +{ + static const Type *get_null () { return &Null(Type); } + static Type *get_crap () { return &Crap(Type); } +}; + +template <typename Type, typename OffsetType=HBUINT16, bool has_null=true> +struct OffsetTo : Offset<OffsetType, has_null> +{ + const Type& operator () (const void *base) const + { + if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); + return StructAtOffset<const Type> (base, *this); + } + Type& operator () (void *base) const + { + if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); + return StructAtOffset<Type> (base, *this); + } + + Type& serialize (hb_serialize_context_t *c, const void *base) + { + return * (Type *) Offset<OffsetType>::serialize (c, base); + } + + template <typename T> + void serialize_subset (hb_subset_context_t *c, const T &src, const void *base) + { + if (&src == &Null (T)) + { + this->set (0); + return; + } + serialize (c->serializer, base); + if (!src.subset (c)) + this->set (0); + } + + bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + if (unlikely (this->is_null ())) return_trace (true); + if (unlikely (!c->check_range (base, *this))) return_trace (false); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c) || + neuter (c))); + } + template <typename T1> + bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1) || + neuter (c))); + } + template <typename T1, typename T2> + bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) || + neuter (c))); + } + template <typename T1, typename T2, typename T3> + bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) || + neuter (c))); + } + + /* Set the offset to Null */ + bool neuter (hb_sanitize_context_t *c) const + { + if (!has_null) return false; + return c->try_set (this, 0); + } + DEFINE_SIZE_STATIC (sizeof (OffsetType)); +}; +/* Partial specializations. */ +template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {}; +template <typename Type, typename OffsetType=HBUINT16 > struct NNOffsetTo : OffsetTo<Type, OffsetType, false> {}; +template <typename Type > struct LNNOffsetTo : OffsetTo<Type, HBUINT32, false> {}; + +template <typename Base, typename OffsetType, bool has_null, typename Type> +static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); } +template <typename Base, typename OffsetType, bool has_null, typename Type> +static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); } + + +/* + * Array Types + */ + +template <typename Type> +struct UnsizedArrayOf +{ + typedef Type item_t; + static constexpr unsigned item_size = hb_static_size (Type); + + HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type); + + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + const Type *p = &arrayZ[i]; + if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ + return *p; + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + Type *p = &arrayZ[i]; + if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ + return *p; + } + + unsigned int get_size (unsigned int len) const + { return len * Type::static_size; } + + template <typename T> operator T * () { return arrayZ; } + template <typename T> operator const T * () const { return arrayZ; } + hb_array_t<Type> as_array (unsigned int len) + { return hb_array (arrayZ, len); } + hb_array_t<const Type> as_array (unsigned int len) const + { return hb_array (arrayZ, len); } + operator hb_array_t<Type> () { return as_array (); } + operator hb_array_t<const Type> () const { return as_array (); } + + template <typename T> + Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) + { return *as_array (len).lsearch (x, ¬_found); } + template <typename T> + const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const + { return *as_array (len).lsearch (x, ¬_found); } + + void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) + { as_array (len).qsort (start, end); } + + bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c, count))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && arrayZ[0].sanitize (c)); + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c, count))) return_trace (false); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!arrayZ[i].sanitize (c, base))) + return_trace (false); + return_trace (true); + } + template <typename T> + bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c, count))) return_trace (false); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + return_trace (false); + return_trace (true); + } + + bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const + { + TRACE_SANITIZE (this); + return_trace (c->check_array (arrayZ, count)); + } + + public: + Type arrayZ[VAR]; + public: + DEFINE_SIZE_UNBOUNDED (0); +}; + +/* Unsized array of offset's */ +template <typename Type, typename OffsetType, bool has_null=true> +struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {}; + +/* Unsized array of offsets relative to the beginning of the array itself. */ +template <typename Type, typename OffsetType, bool has_null=true> +struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> +{ + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; + if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ + return this+*p; + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; + if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ + return this+*p; + } + + + bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + { + TRACE_SANITIZE (this); + return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this))); + } + template <typename T> + bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const + { + TRACE_SANITIZE (this); + return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data))); + } +}; + +/* An array with sorted elements. Supports binary searching. */ +template <typename Type> +struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> +{ + hb_sorted_array_t<Type> as_array (unsigned int len) + { return hb_sorted_array (this->arrayZ, len); } + hb_sorted_array_t<const Type> as_array (unsigned int len) const + { return hb_sorted_array (this->arrayZ, len); } + operator hb_sorted_array_t<Type> () { return as_array (); } + operator hb_sorted_array_t<const Type> () const { return as_array (); } + + template <typename T> + Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) + { return *as_array (len).bsearch (x, ¬_found); } + template <typename T> + const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const + { return *as_array (len).bsearch (x, ¬_found); } + template <typename T> + bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_array (len).bfind (x, i, not_found, to_store); } +}; + + +/* An array with a number of elements. */ +template <typename Type, typename LenType=HBUINT16> +struct ArrayOf +{ + typedef Type item_t; + static constexpr unsigned item_size = hb_static_size (Type); + + HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType); + + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= len)) return Null (Type); + return arrayZ[i]; + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= len)) return Crap (Type); + return arrayZ[i]; + } + + unsigned int get_size () const + { return len.static_size + len * Type::static_size; } + + hb_array_t<Type> as_array () + { return hb_array (arrayZ, len); } + hb_array_t<const Type> as_array () const + { return hb_array (arrayZ, len); } + operator hb_array_t<Type> (void) { return as_array (); } + operator hb_array_t<const Type> (void) const { return as_array (); } + + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + { return as_array ().sub_array (start_offset, count);} + + bool serialize (hb_serialize_context_t *c, unsigned int items_len) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + len.set (items_len); /* TODO(serialize) Overflow? */ + if (unlikely (!c->extend (*this))) return_trace (false); + return_trace (true); + } + template <typename T> + bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items) + { + TRACE_SERIALIZE (this); + if (unlikely (!serialize (c, items.length))) return_trace (false); + for (unsigned int i = 0; i < items.length; i++) + hb_assign (arrayZ[i], items[i]); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && arrayZ[0].sanitize (c)); + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!arrayZ[i].sanitize (c, base))) + return_trace (false); + return_trace (true); + } + template <typename T> + bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + return_trace (false); + return_trace (true); + } + + template <typename T> + Type &lsearch (const T &x, Type ¬_found = Crap (Type)) + { return *as_array ().lsearch (x, ¬_found); } + template <typename T> + const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const + { return *as_array ().lsearch (x, ¬_found); } + + void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) + { as_array ().qsort (start, end); } + + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); + } + + public: + LenType len; + Type arrayZ[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); +}; +template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {}; +typedef ArrayOf<HBUINT8, HBUINT8> PString; + +/* Array of Offset's */ +template <typename Type> +struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {}; +template <typename Type> +struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {}; +template <typename Type> +struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {}; + +/* Array of offsets relative to the beginning of the array itself. */ +template <typename Type> +struct OffsetListOf : OffsetArrayOf<Type> +{ + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= this->len)) return Null (Type); + return this+this->arrayZ[i]; + } + const Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= this->len)) return Crap (Type); + return this+this->arrayZ[i]; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct OffsetListOf<Type> *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + unsigned int count = this->len; + for (unsigned int i = 0; i < count; i++) + out->arrayZ[i].serialize_subset (c, (*this)[i], out); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (OffsetArrayOf<Type>::sanitize (c, this)); + } + template <typename T> + bool sanitize (hb_sanitize_context_t *c, T user_data) const + { + TRACE_SANITIZE (this); + return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data)); + } +}; + +/* An array starting at second element. */ +template <typename Type, typename LenType=HBUINT16> +struct HeadlessArrayOf +{ + static constexpr unsigned item_size = Type::static_size; + + HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType); + + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= lenP1 || !i)) return Null (Type); + return arrayZ[i-1]; + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= lenP1 || !i)) return Crap (Type); + return arrayZ[i-1]; + } + unsigned int get_size () const + { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; } + + bool serialize (hb_serialize_context_t *c, + hb_array_t<const Type> items) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */ + if (unlikely (!c->extend (*this))) return_trace (false); + for (unsigned int i = 0; i < items.length; i++) + arrayZ[i] = items[i]; + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && arrayZ[0].sanitize (c)); + + return_trace (true); + } + + private: + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (lenP1.sanitize (c) && + (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); + } + + public: + LenType lenP1; + Type arrayZ[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); +}; + +/* An array storing length-1. */ +template <typename Type, typename LenType=HBUINT16> +struct ArrayOfM1 +{ + HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType); + + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i > lenM1)) return Null (Type); + return arrayZ[i]; + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i > lenM1)) return Crap (Type); + return arrayZ[i]; + } + unsigned int get_size () const + { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } + + template <typename T> + bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = lenM1 + 1; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + return_trace (false); + return_trace (true); + } + + private: + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (lenM1.sanitize (c) && + (c->check_array (arrayZ, lenM1 + 1))); + } + + public: + LenType lenM1; + Type arrayZ[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); +}; + +/* An array with sorted elements. Supports binary searching. */ +template <typename Type, typename LenType=HBUINT16> +struct SortedArrayOf : ArrayOf<Type, LenType> +{ + hb_sorted_array_t<Type> as_array () + { return hb_sorted_array (this->arrayZ, this->len); } + hb_sorted_array_t<const Type> as_array () const + { return hb_sorted_array (this->arrayZ, this->len); } + operator hb_sorted_array_t<Type> () { return as_array (); } + operator hb_sorted_array_t<const Type> () const { return as_array (); } + + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + { return as_array ().sub_array (start_offset, count);} + + template <typename T> + Type &bsearch (const T &x, Type ¬_found = Crap (Type)) + { return *as_array ().bsearch (x, ¬_found); } + template <typename T> + const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const + { return *as_array ().bsearch (x, ¬_found); } + template <typename T> + bool bfind (const T &x, unsigned int *i = nullptr, + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_array ().bfind (x, i, not_found, to_store); } +}; + +/* + * Binary-search arrays + */ + +template <typename LenType=HBUINT16> +struct BinSearchHeader +{ + operator uint32_t () const { return len; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void set (unsigned int v) + { + len.set (v); + assert (len == v); + entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1); + searchRange.set (16 * (1u << entrySelector)); + rangeShift.set (v * 16 > searchRange + ? 16 * v - searchRange + : 0); + } + + protected: + LenType len; + LenType searchRange; + LenType entrySelector; + LenType rangeShift; + + public: + DEFINE_SIZE_STATIC (8); +}; + +template <typename Type, typename LenType=HBUINT16> +struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {}; + + +struct VarSizedBinSearchHeader +{ + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ + HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ + HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 + * that is less than or equal to the value of nUnits. */ + HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than + * or equal to the value of nUnits. */ + HBUINT16 rangeShift; /* The value of unitSize times the difference of the + * value of nUnits minus the largest power of 2 less + * than or equal to the value of nUnits. */ + public: + DEFINE_SIZE_STATIC (10); +}; + +template <typename Type> +struct VarSizedBinSearchArrayOf +{ + static constexpr unsigned item_size = Type::static_size; + + HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type); + + bool last_is_terminator () const + { + if (unlikely (!header.nUnits)) return false; + + /* Gah. + * + * "The number of termination values that need to be included is table-specific. + * The value that indicates binary search termination is 0xFFFF." */ + const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); + unsigned int count = Type::TerminationWordCount; + for (unsigned int i = 0; i < count; i++) + if (words[i] != 0xFFFFu) + return false; + return true; + } + + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= get_length ())) return Null (Type); + return StructAtOffset<Type> (&bytesZ, i * header.unitSize); + } + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= get_length ())) return Crap (Type); + return StructAtOffset<Type> (&bytesZ, i * header.unitSize); + } + unsigned int get_length () const + { return header.nUnits - last_is_terminator (); } + unsigned int get_size () const + { return header.static_size + header.nUnits * header.unitSize; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c)); + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = get_length (); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!(*this)[i].sanitize (c, base))) + return_trace (false); + return_trace (true); + } + template <typename T> + bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = get_length (); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!(*this)[i].sanitize (c, base, user_data))) + return_trace (false); + return_trace (true); + } + + template <typename T> + const Type *bsearch (const T &key) const + { + unsigned int size = header.unitSize; + int min = 0, max = (int) get_length () - 1; + while (min <= max) + { + int mid = ((unsigned int) min + (unsigned int) max) / 2; + const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); + int c = p->cmp (key); + if (c < 0) max = mid - 1; + else if (c > 0) min = mid + 1; + else return p; + } + return nullptr; + } + + private: + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (header.sanitize (c) && + Type::static_size <= header.unitSize && + c->check_range (bytesZ.arrayZ, + header.nUnits, + header.unitSize)); + } + + protected: + VarSizedBinSearchHeader header; + UnsizedArrayOf<HBUINT8> bytesZ; + public: + DEFINE_SIZE_ARRAY (10, bytesZ); +}; + + +} /* namespace OT */ + + +#endif /* HB_OPEN_TYPE_HH */ diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh new file mode 100644 index 0000000..c645953 --- /dev/null +++ b/src/hb-ot-cff-common.hh @@ -0,0 +1,713 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_OT_CFF_COMMON_HH +#define HB_OT_CFF_COMMON_HH + +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" +#include "hb-cff-interp-dict-common.hh" +#include "hb-subset-plan.hh" + +namespace CFF { + +using namespace OT; + +#define CFF_UNDEF_CODE 0xFFFFFFFF + +/* utility macro */ +template<typename Type> +static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset) +{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); } + +inline unsigned int calcOffSize(unsigned int dataSize) +{ + unsigned int size = 1; + unsigned int offset = dataSize + 1; + while ((offset & ~0xFF) != 0) + { + size++; + offset >>= 8; + } + /* format does not support size > 4; caller should handle it as an error */ + return size; +} + +struct code_pair_t +{ + hb_codepoint_t code; + hb_codepoint_t glyph; +}; + +typedef hb_vector_t<unsigned char> str_buff_t; +struct str_buff_vec_t : hb_vector_t<str_buff_t> +{ + void fini () { SUPER::fini_deep (); } + + unsigned int total_size () const + { + unsigned int size = 0; + for (unsigned int i = 0; i < length; i++) + size += (*this)[i].length; + return size; + } + + private: + typedef hb_vector_t<str_buff_t> SUPER; +}; + +/* CFF INDEX */ +template <typename COUNT> +struct CFFIndex +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */ + (c->check_struct (this) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1) && + c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1)))); + } + + static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) + { return offSize * (count + 1); } + + unsigned int offset_array_size () const + { return calculate_offset_array_size (offSize, count); } + + static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize) + { + if (count == 0) + return COUNT::static_size; + else + return min_size + calculate_offset_array_size (offSize, count) + dataSize; + } + + bool serialize (hb_serialize_context_t *c, const CFFIndex &src) + { + TRACE_SERIALIZE (this); + unsigned int size = src.get_size (); + CFFIndex *dest = c->allocate_size<CFFIndex> (size); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, &src, size); + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const byte_str_array_t &byteArray) + { + TRACE_SERIALIZE (this); + if (byteArray.length == 0) + { + COUNT *dest = c->allocate_min<COUNT> (); + if (unlikely (dest == nullptr)) return_trace (false); + dest->set (0); + } + else + { + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count.set (byteArray.length); + this->offSize.set (offSize_); + if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (; i < byteArray.length; i++) + { + set_offset_at (i, offset); + offset += byteArray[i].get_size (); + } + set_offset_at (i, offset); + + /* serialize data */ + for (unsigned int i = 0; i < byteArray.length; i++) + { + const byte_str_t &bs = byteArray[i]; + unsigned char *dest = c->allocate_size<unsigned char> (bs.length); + if (unlikely (dest == nullptr)) + return_trace (false); + memcpy (dest, &bs[0], bs.length); + } + } + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const str_buff_vec_t &buffArray) + { + byte_str_array_t byteArray; + byteArray.init (); + byteArray.resize (buffArray.length); + for (unsigned int i = 0; i < byteArray.length; i++) + { + byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length); + } + bool result = this->serialize (c, offSize_, byteArray); + byteArray.fini (); + return result; + } + + void set_offset_at (unsigned int index, unsigned int offset) + { + HBUINT8 *p = offsets + offSize * index + offSize; + unsigned int size = offSize; + for (; size; size--) + { + --p; + p->set (offset & 0xFF); + offset >>= 8; + } + } + + unsigned int offset_at (unsigned int index) const + { + assert (index <= count); + const HBUINT8 *p = offsets + offSize * index; + unsigned int size = offSize; + unsigned int offset = 0; + for (; size; size--) + offset = (offset << 8) + *p++; + return offset; + } + + unsigned int length_at (unsigned int index) const + { + if (likely ((offset_at (index + 1) >= offset_at (index)) && + (offset_at (index + 1) <= offset_at (count)))) + return offset_at (index + 1) - offset_at (index); + else + return 0; + } + + const unsigned char *data_base () const + { return (const unsigned char *)this + min_size + offset_array_size (); } + + unsigned int data_size () const { return HBINT8::static_size; } + + byte_str_t operator [] (unsigned int index) const + { + if (likely (index < count)) + return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); + else + return Null(byte_str_t); + } + + unsigned int get_size () const + { + if (this != &Null(CFFIndex)) + { + if (count > 0) + return min_size + offset_array_size () + (offset_at (count) - 1); + else + return count.static_size; /* empty CFFIndex contains count only */ + } + else + return 0; + } + + protected: + unsigned int max_offset () const + { + unsigned int max = 0; + for (unsigned int i = 0; i < count + 1u; i++) + { + unsigned int off = offset_at (i); + if (off > max) max = off; + } + return max; + } + + public: + COUNT count; /* Number of object data. Note there are (count+1) offsets */ + HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ + HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */ + /* HBUINT8 data[VAR]; Object data */ + public: + DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); +}; + +template <typename COUNT, typename TYPE> +struct CFFIndexOf : CFFIndex<COUNT> +{ + const byte_str_t operator [] (unsigned int index) const + { + if (likely (index < CFFIndex<COUNT>::count)) + return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index)); + return Null(byte_str_t); + } + + template <typename DATA, typename PARAM1, typename PARAM2> + bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const DATA *dataArray, + unsigned int dataArrayLen, + const hb_vector_t<unsigned int> &dataSizeArray, + const PARAM1 ¶m1, + const PARAM2 ¶m2) + { + TRACE_SERIALIZE (this); + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count.set (dataArrayLen); + this->offSize.set (offSize_); + if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (; i < dataArrayLen; i++) + { + CFFIndex<COUNT>::set_offset_at (i, offset); + offset += dataSizeArray[i]; + } + CFFIndex<COUNT>::set_offset_at (i, offset); + + /* serialize data */ + for (unsigned int i = 0; i < dataArrayLen; i++) + { + TYPE *dest = c->start_embed<TYPE> (); + if (unlikely (dest == nullptr || + !dest->serialize (c, dataArray[i], param1, param2))) + return_trace (false); + } + return_trace (true); + } + + /* in parallel to above */ + template <typename DATA, typename PARAM> + static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, + const DATA *dataArray, + unsigned int dataArrayLen, + hb_vector_t<unsigned int> &dataSizeArray, /* OUT */ + const PARAM ¶m) + { + /* determine offset size */ + unsigned int totalDataSize = 0; + for (unsigned int i = 0; i < dataArrayLen; i++) + { + unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); + dataSizeArray[i] = dataSize; + totalDataSize += dataSize; + } + offSize_ = calcOffSize (totalDataSize); + + return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize); + } +}; + +/* Top Dict, Font Dict, Private Dict */ +struct Dict : UnsizedByteStr +{ + template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM> + bool serialize (hb_serialize_context_t *c, + const DICTVAL &dictval, + OP_SERIALIZER& opszr, + PARAM& param) + { + TRACE_SERIALIZE (this); + for (unsigned int i = 0; i < dictval.get_count (); i++) + { + if (unlikely (!opszr.serialize (c, dictval[i], param))) + return_trace (false); + } + return_trace (true); + } + + /* in parallel to above */ + template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM> + static unsigned int calculate_serialized_size (const DICTVAL &dictval, + OP_SERIALIZER& opszr, + PARAM& param) + { + unsigned int size = 0; + for (unsigned int i = 0; i < dictval.get_count (); i++) + size += opszr.calculate_serialized_size (dictval[i], param); + return size; + } + + template <typename DICTVAL, typename OP_SERIALIZER> + static unsigned int calculate_serialized_size (const DICTVAL &dictval, + OP_SERIALIZER& opszr) + { + unsigned int size = 0; + for (unsigned int i = 0; i < dictval.get_count (); i++) + size += opszr.calculate_serialized_size (dictval[i]); + return size; + } + + template <typename INTTYPE, int minVal, int maxVal> + static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp) + { + // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation + if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value))) + return false; + + TRACE_SERIALIZE (this); + /* serialize the opcode */ + HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op)); + if (unlikely (p == nullptr)) return_trace (false); + if (Is_OpCode_ESC (op)) + { + p->set (OpCode_escape); + op = Unmake_OpCode_ESC (op); + p++; + } + p->set (op); + return_trace (true); + } + + static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value) + { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); } + + static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value) + { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); } + + static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value) + { + return serialize_uint4_op (c, op, value); + } + + static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value) + { + return serialize_uint2_op (c, op, value); + } +}; + +struct TopDict : Dict {}; +struct FontDict : Dict {}; +struct PrivateDict : Dict {}; + +struct table_info_t +{ + void init () { offSize = offset = size = 0; } + + unsigned int offset; + unsigned int size; + unsigned int offSize; +}; + +/* used to remap font index or SID from fullset to subset. + * set to CFF_UNDEF_CODE if excluded from subset */ +struct remap_t : hb_vector_t<hb_codepoint_t> +{ + void init () { SUPER::init (); } + + void fini () { SUPER::fini (); } + + bool reset (unsigned int size) + { + if (unlikely (!SUPER::resize (size))) + return false; + for (unsigned int i = 0; i < length; i++) + (*this)[i] = CFF_UNDEF_CODE; + count = 0; + return true; + } + + bool identity (unsigned int size) + { + if (unlikely (!SUPER::resize (size))) + return false; + unsigned int i; + for (i = 0; i < length; i++) + (*this)[i] = i; + count = i; + return true; + } + + bool excludes (hb_codepoint_t id) const + { return (id < length) && ((*this)[id] == CFF_UNDEF_CODE); } + + bool includes (hb_codepoint_t id) const + { return !excludes (id); } + + unsigned int add (unsigned int i) + { + if ((*this)[i] == CFF_UNDEF_CODE) + (*this)[i] = count++; + return (*this)[i]; + } + + hb_codepoint_t get_count () const { return count; } + + protected: + hb_codepoint_t count; + + private: + typedef hb_vector_t<hb_codepoint_t> SUPER; +}; + +template <typename COUNT> +struct FDArray : CFFIndexOf<COUNT, FontDict> +{ + /* used by CFF1 */ + template <typename DICTVAL, typename OP_SERIALIZER> + bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const hb_vector_t<DICTVAL> &fontDicts, + OP_SERIALIZER& opszr) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count.set (fontDicts.length); + this->offSize.set (offSize_); + if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1)))) + return_trace (false); + + /* serialize font dict offsets */ + unsigned int offset = 1; + unsigned int fid = 0; + for (; fid < fontDicts.length; fid++) + { + CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); + offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr); + } + CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); + + /* serialize font dicts */ + for (unsigned int i = 0; i < fontDicts.length; i++) + { + FontDict *dict = c->start_embed<FontDict> (); + if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) + return_trace (false); + } + return_trace (true); + } + + /* used by CFF2 */ + template <typename DICTVAL, typename OP_SERIALIZER> + bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const hb_vector_t<DICTVAL> &fontDicts, + unsigned int fdCount, + const remap_t &fdmap, + OP_SERIALIZER& opszr, + const hb_vector_t<table_info_t> &privateInfos) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count.set (fdCount); + this->offSize.set (offSize_); + if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1)))) + return_trace (false); + + /* serialize font dict offsets */ + unsigned int offset = 1; + unsigned int fid = 0; + for (unsigned i = 0; i < fontDicts.length; i++) + if (fdmap.includes (i)) + { + CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset); + offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); + } + CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); + + /* serialize font dicts */ + for (unsigned int i = 0; i < fontDicts.length; i++) + if (fdmap.includes (i)) + { + FontDict *dict = c->start_embed<FontDict> (); + if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) + return_trace (false); + } + return_trace (true); + } + + /* in parallel to above */ + template <typename OP_SERIALIZER, typename DICTVAL> + static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, + const hb_vector_t<DICTVAL> &fontDicts, + unsigned int fdCount, + const remap_t &fdmap, + OP_SERIALIZER& opszr) + { + unsigned int dictsSize = 0; + for (unsigned int i = 0; i < fontDicts.len; i++) + if (fdmap.includes (i)) + dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); + + offSize_ = calcOffSize (dictsSize); + return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize); + } +}; + +/* FDSelect */ +struct FDSelect0 { + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + if (unlikely (!(c->check_struct (this)))) + return_trace (false); + for (unsigned int i = 0; i < c->get_num_glyphs (); i++) + if (unlikely (!fds[i].sanitize (c))) + return_trace (false); + + return_trace (true); + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + return (hb_codepoint_t)fds[glyph]; + } + + unsigned int get_size (unsigned int num_glyphs) const + { return HBUINT8::static_size * num_glyphs; } + + HBUINT8 fds[VAR]; + + DEFINE_SIZE_MIN (1); +}; + +template <typename GID_TYPE, typename FD_TYPE> +struct FDSelect3_4_Range { + bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + return_trace (first < c->get_num_glyphs () && (fd < fdcount)); + } + + GID_TYPE first; + FD_TYPE fd; + + DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size); +}; + +template <typename GID_TYPE, typename FD_TYPE> +struct FDSelect3_4 { + unsigned int get_size () const + { return GID_TYPE::static_size * 2 + ranges.get_size (); } + + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) || + (nRanges () == 0) || ranges[0].first != 0)) + return_trace (false); + + for (unsigned int i = 1; i < nRanges (); i++) + { + if (unlikely (ranges[i - 1].first >= ranges[i].first)) + return_trace (false); + } + + if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) + return_trace (false); + + return_trace (true); + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + unsigned int i; + for (i = 1; i < nRanges (); i++) + if (glyph < ranges[i].first) + break; + + return (hb_codepoint_t)ranges[i - 1].fd; + } + + GID_TYPE &nRanges () { return ranges.len; } + GID_TYPE nRanges () const { return ranges.len; } + GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } + const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } + + ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges; + /* GID_TYPE sentinel */ + + DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges); +}; + +typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3; +typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range; + +struct FDSelect { + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + + return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) && + (format == 0)? + u.format0.sanitize (c, fdcount): + u.format3.sanitize (c, fdcount))); + } + + bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs) + { + TRACE_SERIALIZE (this); + unsigned int size = src.get_size (num_glyphs); + FDSelect *dest = c->allocate_size<FDSelect> (size); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, &src, size); + return_trace (true); + } + + unsigned int calculate_serialized_size (unsigned int num_glyphs) const + { return get_size (num_glyphs); } + + unsigned int get_size (unsigned int num_glyphs) const + { + unsigned int size = format.static_size; + if (format == 0) + size += u.format0.get_size (num_glyphs); + else + size += u.format3.get_size (); + return size; + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + if (this == &Null(FDSelect)) + return 0; + if (format == 0) + return u.format0.get_fd (glyph); + else + return u.format3.get_fd (glyph); + } + + HBUINT8 format; + union { + FDSelect0 format0; + FDSelect3 format3; + } u; + + DEFINE_SIZE_MIN (1); +}; + +template <typename COUNT> +struct Subrs : CFFIndex<COUNT> +{ + typedef COUNT count_type; + typedef CFFIndex<COUNT> SUPER; +}; + +} /* namespace CFF */ + +#endif /* HB_OT_CFF_COMMON_HH */ diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc new file mode 100644 index 0000000..8773c05 --- /dev/null +++ b/src/hb-ot-cff1-table.cc @@ -0,0 +1,385 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-ot-cff1-table.hh" +#include "hb-cff1-interp-cs.hh" + +using namespace CFF; + +/* SID to code */ +static const uint8_t standard_encoding_to_code [] = +{ + 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, + 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 193, 194, 195, 196, + 197, 198, 199, 200, 202, 203, 205, 206, 207, 208, 225, 227, 232, 233, 234, 235, + 241, 245, 248, 249, 250, 251 +}; + +/* SID to code */ +static const uint8_t expert_encoding_to_code [] = +{ + 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 189, 0, 0, 188, 0, + 0, 0, 0, 190, 202, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63, 65, 66, 67, + 68, 69, 73, 76, 77, 78, 79, 82, 83, 84, 86, 89, 90, 91, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 161, 162, 163, 166, 167, 168, 169, 170, 172, 175, 178, 179, 182, 183, 184, 191, + 192, 193, 194, 195, 196, 197, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + +/* glyph ID to SID */ +static const uint16_t expert_charset_to_sid [] = +{ + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +/* glyph ID to SID */ +static const uint16_t expert_subset_charset_to_sid [] = +{ + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; + +/* code to SID */ +static const uint8_t standard_encoding_to_sid [] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0 +}; + +hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid) +{ + if (sid < ARRAY_LENGTH (standard_encoding_to_code)) + return (hb_codepoint_t)standard_encoding_to_code[sid]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid) +{ + if (sid < ARRAY_LENGTH (expert_encoding_to_code)) + return (hb_codepoint_t)expert_encoding_to_code[sid]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph) +{ + if (glyph < ARRAY_LENGTH (expert_charset_to_sid)) + return (hb_codepoint_t)expert_charset_to_sid[glyph]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph) +{ + if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid)) + return (hb_codepoint_t)expert_subset_charset_to_sid[glyph]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code) +{ + if (code < ARRAY_LENGTH (standard_encoding_to_sid)) + return (hb_codepoint_t)standard_encoding_to_sid[code]; + else + return CFF_UNDEF_SID; +} + +struct bounds_t +{ + void init () + { + min.set_int (0x7FFFFFFF, 0x7FFFFFFF); + max.set_int (-0x80000000, -0x80000000); + } + + void update (const point_t &pt) + { + if (pt.x < min.x) min.x = pt.x; + if (pt.x > max.x) max.x = pt.x; + if (pt.y < min.y) min.y = pt.y; + if (pt.y > max.y) max.y = pt.y; + } + + void merge (const bounds_t &b) + { + if (empty ()) + *this = b; + else if (!b.empty ()) + { + if (b.min.x < min.x) min.x = b.min.x; + if (b.max.x > max.x) max.x = b.max.x; + if (b.min.y < min.y) min.y = b.min.y; + if (b.max.y > max.y) max.y = b.max.y; + } + } + + void offset (const point_t &delta) + { + if (!empty ()) + { + min.move (delta); + max.move (delta); + } + } + + bool empty () const + { return (min.x >= max.x) || (min.y >= max.y); } + + point_t min; + point_t max; +}; + +struct extents_param_t +{ + void init (const OT::cff1::accelerator_t *_cff) + { + path_open = false; + cff = _cff; + bounds.init (); + } + + void start_path () { path_open = true; } + void end_path () { path_open = false; } + bool is_path_open () const { return path_open; } + + bool path_open; + bounds_t bounds; + + const OT::cff1::accelerator_t *cff; +}; + +struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, extents_param_t> +{ + static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + { + param.end_path (); + env.moveto (pt); + } + + static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + { + if (!param.is_path_open ()) + { + param.start_path (); + param.bounds.update (env.get_pt ()); + } + env.moveto (pt1); + param.bounds.update (env.get_pt ()); + } + + static void curve (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + if (!param.is_path_open ()) + { + param.start_path (); + param.bounds.update (env.get_pt ()); + } + /* include control points */ + param.bounds.update (pt1); + param.bounds.update (pt2); + env.moveto (pt3); + param.bounds.update (env.get_pt ()); + } +}; + +static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false); + +struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, extents_param_t, cff1_path_procs_extents_t> +{ + static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param) + { + unsigned int n = env.argStack.get_count (); + point_t delta; + delta.x = env.argStack[n-4]; + delta.y = env.argStack[n-3]; + hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ()); + hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); + + bounds_t base_bounds, accent_bounds; + if (likely (!env.in_seac && base && accent + && _get_bounds (param.cff, base, base_bounds, true) + && _get_bounds (param.cff, accent, accent_bounds, true))) + { + param.bounds.merge (base_bounds); + accent_bounds.offset (delta); + param.bounds.merge (accent_bounds); + } + else + env.set_error (); + } +}; + +bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac) +{ + bounds.init (); + if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; + + unsigned int fd = cff->fdSelect->get_fd (glyph); + cff1_cs_interpreter_t<cff1_cs_opset_extents_t, extents_param_t> interp; + const byte_str_t str = (*cff->charStrings)[glyph]; + interp.env.init (str, *cff, fd); + interp.env.set_in_seac (in_seac); + extents_param_t param; + param.init (cff); + if (unlikely (!interp.interpret (param))) return false; + bounds = param.bounds; + return true; +} + +bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +{ + bounds_t bounds; + + if (!_get_bounds (this, glyph, bounds)) + return false; + + if (bounds.min.x >= bounds.max.x) + { + extents->width = 0; + extents->x_bearing = 0; + } + else + { + extents->x_bearing = (int32_t)bounds.min.x.floor (); + extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; + } + if (bounds.min.y >= bounds.max.y) + { + extents->height = 0; + extents->y_bearing = 0; + } + else + { + extents->y_bearing = (int32_t)bounds.max.y.ceil (); + extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; + } + + return true; +} + +struct get_seac_param_t +{ + void init (const OT::cff1::accelerator_t *_cff) + { + cff = _cff; + base = 0; + accent = 0; + } + + bool has_seac () const { return base && accent; } + + const OT::cff1::accelerator_t *cff; + hb_codepoint_t base; + hb_codepoint_t accent; +}; + +struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t> +{ + static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param) + { + unsigned int n = env.argStack.get_count (); + hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int (); + hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int (); + + param.base = param.cff->std_code_to_glyph (base_char); + param.accent = param.cff->std_code_to_glyph (accent_char); + } +}; + +bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const +{ + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + + unsigned int fd = fdSelect->get_fd (glyph); + cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp; + const byte_str_t str = (*charStrings)[glyph]; + interp.env.init (str, *this, fd); + get_seac_param_t param; + param.init (this); + if (unlikely (!interp.interpret (param))) return false; + + if (param.has_seac ()) + { + *base = param.base; + *accent = param.accent; + return true; + } + return false; +} diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh new file mode 100644 index 0000000..1effdf0 --- /dev/null +++ b/src/hb-ot-cff1-table.hh @@ -0,0 +1,1299 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_CFF1_TABLE_HH +#define HB_OT_CFF1_TABLE_HH + +#include "hb-ot-head-table.hh" +#include "hb-ot-cff-common.hh" +#include "hb-subset-cff1.hh" + +namespace CFF { + +/* + * CFF -- Compact Font Format (CFF) + * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf + */ +#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') + +#define CFF_UNDEF_SID CFF_UNDEF_CODE + +enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; +enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; + +typedef CFFIndex<HBUINT16> CFF1Index; +template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {}; + +typedef CFFIndex<HBUINT16> CFF1Index; +typedef CFF1Index CFF1CharStrings; +typedef FDArray<HBUINT16> CFF1FDArray; +typedef Subrs<HBUINT16> CFF1Subrs; + +struct CFF1FDSelect : FDSelect {}; + +/* Encoding */ +struct Encoding0 { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c)); + } + + hb_codepoint_t get_code (hb_codepoint_t glyph) const + { + assert (glyph > 0); + glyph--; + if (glyph < nCodes) + { + return (hb_codepoint_t)codes[glyph]; + } + else + return CFF_UNDEF_CODE; + } + + unsigned int get_size () const + { return HBUINT8::static_size * (nCodes + 1); } + + HBUINT8 nCodes; + HBUINT8 codes[VAR]; + + DEFINE_SIZE_ARRAY(1, codes); +}; + +struct Encoding1_Range { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT8 first; + HBUINT8 nLeft; + + DEFINE_SIZE_STATIC (2); +}; + +struct Encoding1 { + unsigned int get_size () const + { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); + } + + hb_codepoint_t get_code (hb_codepoint_t glyph) const + { + assert (glyph > 0); + glyph--; + for (unsigned int i = 0; i < nRanges; i++) + { + if (glyph <= ranges[i].nLeft) + { + return (hb_codepoint_t)ranges[i].first + glyph; + } + glyph -= (ranges[i].nLeft + 1); + } + return CFF_UNDEF_CODE; + } + + HBUINT8 nRanges; + Encoding1_Range ranges[VAR]; + + DEFINE_SIZE_ARRAY (1, ranges); +}; + +struct SuppEncoding { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT8 code; + HBUINT16 glyph; + + DEFINE_SIZE_STATIC (3); +}; + +struct CFF1SuppEncData { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c))); + } + + void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const + { + for (unsigned int i = 0; i < nSups; i++) + if (sid == supps[i].glyph) + codes.push (supps[i].code); + } + + unsigned int get_size () const + { return HBUINT8::static_size + SuppEncoding::static_size * nSups; } + + HBUINT8 nSups; + SuppEncoding supps[VAR]; + + DEFINE_SIZE_ARRAY (1, supps); +}; + +struct Encoding { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_struct (this))) + return_trace (false); + unsigned int fmt = format & 0x7F; + if (unlikely (fmt > 1)) + return_trace (false); + if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c)))) + return_trace (false); + return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c)); + } + + /* serialize a fullset Encoding */ + bool serialize (hb_serialize_context_t *c, const Encoding &src) + { + TRACE_SERIALIZE (this); + unsigned int size = src.get_size (); + Encoding *dest = c->allocate_size<Encoding> (size); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, &src, size); + return_trace (true); + } + + /* serialize a subset Encoding */ + bool serialize (hb_serialize_context_t *c, + uint8_t format, + unsigned int enc_count, + const hb_vector_t<code_pair_t>& code_ranges, + const hb_vector_t<code_pair_t>& supp_codes) + { + TRACE_SERIALIZE (this); + Encoding *dest = c->extend_min (*this); + if (unlikely (dest == nullptr)) return_trace (false); + dest->format.set (format | ((supp_codes.length > 0)? 0x80: 0)); + if (format == 0) + { + Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count); + if (unlikely (fmt0 == nullptr)) return_trace (false); + fmt0->nCodes.set (enc_count); + unsigned int glyph = 0; + for (unsigned int i = 0; i < code_ranges.length; i++) + { + hb_codepoint_t code = code_ranges[i].code; + for (int left = (int)code_ranges[i].glyph; left >= 0; left--) + fmt0->codes[glyph++].set (code++); + if (unlikely (!((glyph <= 0x100) && (code <= 0x100)))) + return_trace (false); + } + } + else + { + Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); + if (unlikely (fmt1 == nullptr)) return_trace (false); + fmt1->nRanges.set (code_ranges.length); + for (unsigned int i = 0; i < code_ranges.length; i++) + { + if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)))) + return_trace (false); + fmt1->ranges[i].first.set (code_ranges[i].code); + fmt1->ranges[i].nLeft.set (code_ranges[i].glyph); + } + } + if (supp_codes.length > 0) + { + CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); + if (unlikely (suppData == nullptr)) return_trace (false); + suppData->nSups.set (supp_codes.length); + for (unsigned int i = 0; i < supp_codes.length; i++) + { + suppData->supps[i].code.set (supp_codes[i].code); + suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */ + } + } + return_trace (true); + } + + /* parallel to above: calculate the size of a subset Encoding */ + static unsigned int calculate_serialized_size (uint8_t format, + unsigned int enc_count, + unsigned int supp_count) + { + unsigned int size = min_size; + if (format == 0) + size += Encoding0::min_size + HBUINT8::static_size * enc_count; + else + size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; + if (supp_count > 0) + size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; + return size; + } + + unsigned int get_size () const + { + unsigned int size = min_size; + if (table_format () == 0) + size += u.format0.get_size (); + else + size += u.format1.get_size (); + if (has_supplement ()) + size += suppEncData ().get_size (); + return size; + } + + hb_codepoint_t get_code (hb_codepoint_t glyph) const + { + if (table_format () == 0) + return u.format0.get_code (glyph); + else + return u.format1.get_code (glyph); + } + + uint8_t table_format () const { return (format & 0x7F); } + bool has_supplement () const { return (format & 0x80) != 0; } + + void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const + { + codes.resize (0); + if (has_supplement ()) + suppEncData().get_codes (sid, codes); + } + + protected: + const CFF1SuppEncData &suppEncData () const + { + if ((format & 0x7F) == 0) + return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]); + else + return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]); + } + + public: + HBUINT8 format; + + union { + Encoding0 format0; + Encoding1 format1; + } u; + /* CFF1SuppEncData suppEncData; */ + + DEFINE_SIZE_MIN (1); +}; + +/* Charset */ +struct Charset0 { + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); + } + + hb_codepoint_t get_sid (hb_codepoint_t glyph) const + { + if (glyph == 0) + return 0; + else + return sids[glyph - 1]; + } + + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + { + if (sid == 0) + return 0; + + for (unsigned int glyph = 1; glyph < num_glyphs; glyph++) + { + if (sids[glyph-1] == sid) + return glyph; + } + return 0; + } + + unsigned int get_size (unsigned int num_glyphs) const + { + assert (num_glyphs > 0); + return HBUINT16::static_size * (num_glyphs - 1); + } + + HBUINT16 sids[VAR]; + + DEFINE_SIZE_ARRAY(0, sids); +}; + +template <typename TYPE> +struct Charset_Range { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT16 first; + TYPE nLeft; + + DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size); +}; + +template <typename TYPE> +struct Charset1_2 { + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + num_glyphs--; + for (unsigned int i = 0; num_glyphs > 0; i++) + { + if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) + return_trace (false); + num_glyphs -= (ranges[i].nLeft + 1); + } + return_trace (true); + } + + hb_codepoint_t get_sid (hb_codepoint_t glyph) const + { + if (glyph == 0) return 0; + glyph--; + for (unsigned int i = 0;; i++) + { + if (glyph <= ranges[i].nLeft) + return (hb_codepoint_t)ranges[i].first + glyph; + glyph -= (ranges[i].nLeft + 1); + } + + return 0; + } + + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + { + if (sid == 0) return 0; + hb_codepoint_t glyph = 1; + for (unsigned int i = 0;; i++) + { + if (glyph >= num_glyphs) + return 0; + if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft)) + return glyph + (sid - ranges[i].first); + glyph += (ranges[i].nLeft + 1); + } + + return 0; + } + + unsigned int get_size (unsigned int num_glyphs) const + { + unsigned int size = HBUINT8::static_size; + int glyph = (int)num_glyphs; + + assert (glyph > 0); + glyph--; + for (unsigned int i = 0; glyph > 0; i++) + { + glyph -= (ranges[i].nLeft + 1); + size += Charset_Range<TYPE>::static_size; + } + + return size; + } + + Charset_Range<TYPE> ranges[VAR]; + + DEFINE_SIZE_ARRAY (0, ranges); +}; + +typedef Charset1_2<HBUINT8> Charset1; +typedef Charset1_2<HBUINT16> Charset2; +typedef Charset_Range<HBUINT8> Charset1_Range; +typedef Charset_Range<HBUINT16> Charset2_Range; + +struct Charset { + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_struct (this))) + return_trace (false); + if (format == 0) + return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); + else if (format == 1) + return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); + else if (likely (format == 2)) + return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); + else + return_trace (false); + } + + /* serialize a fullset Charset */ + bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) + { + TRACE_SERIALIZE (this); + unsigned int size = src.get_size (num_glyphs); + Charset *dest = c->allocate_size<Charset> (size); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, &src, size); + return_trace (true); + } + + /* serialize a subset Charset */ + bool serialize (hb_serialize_context_t *c, + uint8_t format, + unsigned int num_glyphs, + const hb_vector_t<code_pair_t>& sid_ranges) + { + TRACE_SERIALIZE (this); + Charset *dest = c->extend_min (*this); + if (unlikely (dest == nullptr)) return_trace (false); + dest->format.set (format); + if (format == 0) + { + Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); + if (unlikely (fmt0 == nullptr)) return_trace (false); + unsigned int glyph = 0; + for (unsigned int i = 0; i < sid_ranges.length; i++) + { + hb_codepoint_t sid = sid_ranges[i].code; + for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) + fmt0->sids[glyph++].set (sid++); + } + } + else if (format == 1) + { + Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); + if (unlikely (fmt1 == nullptr)) return_trace (false); + for (unsigned int i = 0; i < sid_ranges.length; i++) + { + if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) + return_trace (false); + fmt1->ranges[i].first.set (sid_ranges[i].code); + fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph); + } + } + else /* format 2 */ + { + Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); + if (unlikely (fmt2 == nullptr)) return_trace (false); + for (unsigned int i = 0; i < sid_ranges.length; i++) + { + if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) + return_trace (false); + fmt2->ranges[i].first.set (sid_ranges[i].code); + fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph); + } + } + return_trace (true); + } + + /* parallel to above: calculate the size of a subset Charset */ + static unsigned int calculate_serialized_size ( + uint8_t format, + unsigned int count) + { + unsigned int size = min_size; + if (format == 0) + size += Charset0::min_size + HBUINT16::static_size * (count - 1); + else if (format == 1) + size += Charset1::min_size + Charset1_Range::static_size * count; + else + size += Charset2::min_size + Charset2_Range::static_size * count; + + return size; + } + + unsigned int get_size (unsigned int num_glyphs) const + { + unsigned int size = min_size; + if (format == 0) + size += u.format0.get_size (num_glyphs); + else if (format == 1) + size += u.format1.get_size (num_glyphs); + else + size += u.format2.get_size (num_glyphs); + return size; + } + + hb_codepoint_t get_sid (hb_codepoint_t glyph) const + { + if (format == 0) + return u.format0.get_sid (glyph); + else if (format == 1) + return u.format1.get_sid (glyph); + else + return u.format2.get_sid (glyph); + } + + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + { + if (format == 0) + return u.format0.get_glyph (sid, num_glyphs); + else if (format == 1) + return u.format1.get_glyph (sid, num_glyphs); + else + return u.format2.get_glyph (sid, num_glyphs); + } + + HBUINT8 format; + union { + Charset0 format0; + Charset1 format1; + Charset2 format2; + } u; + + DEFINE_SIZE_MIN (1); +}; + +struct CFF1StringIndex : CFF1Index +{ + bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, + unsigned int offSize_, const remap_t &sidmap) + { + TRACE_SERIALIZE (this); + if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) + { + if (!unlikely (c->extend_min (this->count))) + return_trace (false); + count.set (0); + return_trace (true); + } + + byte_str_array_t bytesArray; + bytesArray.init (); + if (!bytesArray.resize (sidmap.get_count ())) + return_trace (false); + for (unsigned int i = 0; i < strings.count; i++) + { + hb_codepoint_t j = sidmap[i]; + if (j != CFF_UNDEF_CODE) + bytesArray[j] = strings[i]; + } + + bool result = CFF1Index::serialize (c, offSize_, bytesArray); + bytesArray.fini (); + return_trace (result); + } + + /* in parallel to above */ + unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const remap_t &sidmap) const + { + offSize = 0; + if ((count == 0) || (sidmap.get_count () == 0)) + return count.static_size; + + unsigned int dataSize = 0; + for (unsigned int i = 0; i < count; i++) + if (sidmap[i] != CFF_UNDEF_CODE) + dataSize += length_at (i); + + offSize = calcOffSize(dataSize); + return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize); + } +}; + +struct cff1_top_dict_interp_env_t : num_interp_env_t +{ + cff1_top_dict_interp_env_t () + : num_interp_env_t(), prev_offset(0), last_offset(0) {} + + unsigned int prev_offset; + unsigned int last_offset; +}; + +struct name_dict_values_t +{ + enum name_dict_val_index_t + { + version, + notice, + copyright, + fullName, + familyName, + weight, + postscript, + fontName, + baseFontName, + registry, + ordering, + + ValCount + }; + + void init () + { + for (unsigned int i = 0; i < ValCount; i++) + values[i] = CFF_UNDEF_SID; + } + + unsigned int& operator[] (unsigned int i) + { assert (i < ValCount); return values[i]; } + + unsigned int operator[] (unsigned int i) const + { assert (i < ValCount); return values[i]; } + + static enum name_dict_val_index_t name_op_to_index (op_code_t op) + { + switch (op) { + default: // can't happen - just make some compiler happy + case OpCode_version: + return version; + case OpCode_Notice: + return notice; + case OpCode_Copyright: + return copyright; + case OpCode_FullName: + return fullName; + case OpCode_FamilyName: + return familyName; + case OpCode_Weight: + return weight; + case OpCode_PostScript: + return postscript; + case OpCode_FontName: + return fontName; + case OpCode_BaseFontName: + return baseFontName; + } + } + + unsigned int values[ValCount]; +}; + +struct cff1_top_dict_val_t : op_str_t +{ + unsigned int last_arg_offset; +}; + +struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t> +{ + void init () + { + top_dict_values_t<cff1_top_dict_val_t>::init (); + + nameSIDs.init (); + ros_supplement = 0; + cidCount = 8720; + EncodingOffset = 0; + CharsetOffset = 0; + FDSelectOffset = 0; + privateDictInfo.init (); + } + void fini () { top_dict_values_t<cff1_top_dict_val_t>::fini (); } + + bool is_CID () const + { return nameSIDs[name_dict_values_t::registry] != CFF_UNDEF_SID; } + + name_dict_values_t nameSIDs; + unsigned int ros_supplement_offset; + unsigned int ros_supplement; + unsigned int cidCount; + + unsigned int EncodingOffset; + unsigned int CharsetOffset; + unsigned int FDSelectOffset; + table_info_t privateDictInfo; +}; + +struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t> +{ + static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval) + { + cff1_top_dict_val_t val; + val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ + + switch (op) { + case OpCode_version: + case OpCode_Notice: + case OpCode_Copyright: + case OpCode_FullName: + case OpCode_FamilyName: + case OpCode_Weight: + case OpCode_PostScript: + case OpCode_BaseFontName: + dictval.nameSIDs[name_dict_values_t::name_op_to_index (op)] = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_isFixedPitch: + case OpCode_ItalicAngle: + case OpCode_UnderlinePosition: + case OpCode_UnderlineThickness: + case OpCode_PaintType: + case OpCode_CharstringType: + case OpCode_UniqueID: + case OpCode_StrokeWidth: + case OpCode_SyntheticBase: + case OpCode_CIDFontVersion: + case OpCode_CIDFontRevision: + case OpCode_CIDFontType: + case OpCode_UIDBase: + case OpCode_FontBBox: + case OpCode_XUID: + case OpCode_BaseFontBlend: + env.clear_args (); + break; + + case OpCode_CIDCount: + dictval.cidCount = env.argStack.pop_uint (); + env.clear_args (); + break; + + case OpCode_ROS: + dictval.ros_supplement = env.argStack.pop_uint (); + dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint (); + dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint (); + env.clear_args (); + break; + + case OpCode_Encoding: + dictval.EncodingOffset = env.argStack.pop_uint (); + env.clear_args (); + if (unlikely (dictval.EncodingOffset == 0)) return; + break; + + case OpCode_charset: + dictval.CharsetOffset = env.argStack.pop_uint (); + env.clear_args (); + if (unlikely (dictval.CharsetOffset == 0)) return; + break; + + case OpCode_FDSelect: + dictval.FDSelectOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + + case OpCode_Private: + dictval.privateDictInfo.offset = env.argStack.pop_uint (); + dictval.privateDictInfo.size = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + env.last_offset = env.str_ref.offset; + top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval); + /* Record this operand below if stack is empty, otherwise done */ + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref, val); + } +}; + +struct cff1_font_dict_values_t : dict_values_t<op_str_t> +{ + void init () + { + dict_values_t<op_str_t>::init (); + privateDictInfo.init (); + fontName = CFF_UNDEF_SID; + } + void fini () { dict_values_t<op_str_t>::fini (); } + + table_info_t privateDictInfo; + unsigned int fontName; +}; + +struct cff1_font_dict_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, num_interp_env_t& env, cff1_font_dict_values_t& dictval) + { + switch (op) { + case OpCode_FontName: + dictval.fontName = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_FontMatrix: + case OpCode_PaintType: + env.clear_args (); + break; + case OpCode_Private: + dictval.privateDictInfo.offset = env.argStack.pop_uint (); + dictval.privateDictInfo.size = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + dict_opset_t::process_op (op, env); + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref); + } +}; + +template <typename VAL> +struct cff1_private_dict_values_base_t : dict_values_t<VAL> +{ + void init () + { + dict_values_t<VAL>::init (); + subrsOffset = 0; + localSubrs = &Null(CFF1Subrs); + } + void fini () { dict_values_t<VAL>::fini (); } + + unsigned int calculate_serialized_size () const + { + unsigned int size = 0; + for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++) + if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs) + size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); + else + size += dict_values_t<VAL>::get_value (i).str.length; + return size; + } + + unsigned int subrsOffset; + const CFF1Subrs *localSubrs; +}; + +typedef cff1_private_dict_values_base_t<op_str_t> cff1_private_dict_values_subset_t; +typedef cff1_private_dict_values_base_t<num_dict_val_t> cff1_private_dict_values_t; + +struct cff1_private_dict_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_t& dictval) + { + num_dict_val_t val; + val.init (); + + switch (op) { + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + env.clear_args (); + break; + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_ForceBold: + case OpCode_LanguageGroup: + case OpCode_ExpansionFactor: + case OpCode_initialRandomSeed: + case OpCode_defaultWidthX: + case OpCode_nominalWidthX: + val.single_val = env.argStack.pop_num (); + env.clear_args (); + break; + case OpCode_Subrs: + dictval.subrsOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + dict_opset_t::process_op (op, env); + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref, val); + } +}; + +struct cff1_private_dict_opset_subset : dict_opset_t +{ + static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval) + { + switch (op) { + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_ForceBold: + case OpCode_LanguageGroup: + case OpCode_ExpansionFactor: + case OpCode_initialRandomSeed: + case OpCode_defaultWidthX: + case OpCode_nominalWidthX: + env.clear_args (); + break; + + case OpCode_Subrs: + dictval.subrsOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + dict_opset_t::process_op (op, env); + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref); + } +}; + +typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_top_dict_interp_env_t> cff1_top_dict_interpreter_t; +typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t; + +typedef CFF1Index CFF1NameIndex; +typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; + +} /* namespace CFF */ + +namespace OT { + +using namespace CFF; + +struct cff1 +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version.major == 1)); + } + + template <typename PRIVOPSET, typename PRIVDICTVAL> + struct accelerator_templ_t + { + void init (hb_face_t *face) + { + topDict.init (); + fontDicts.init (); + privateDicts.init (); + + this->blob = sc.reference_table<cff1> (face); + + /* setup for run-time santization */ + sc.init (this->blob); + sc.start_processing (); + + const OT::cff1 *cff = this->blob->template as<OT::cff1> (); + + if (cff == &Null(OT::cff1)) + { fini (); return; } + + nameIndex = &cff->nameIndex (cff); + if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) + { fini (); return; } + + topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); + if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) + { fini (); return; } + + { /* parse top dict */ + const byte_str_t topDictStr = (*topDictIndex)[0]; + if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } + cff1_top_dict_interpreter_t top_interp; + top_interp.env.init (topDictStr); + topDict.init (); + if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + } + + if (is_predef_charset ()) + charset = &Null(Charset); + else + { + charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); + if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } + } + + fdCount = 1; + if (is_CID ()) + { + fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset); + fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); + if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || + (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) + { fini (); return; } + + fdCount = fdArray->count; + } + else + { + fdArray = &Null(CFF1FDArray); + fdSelect = &Null(CFF1FDSelect); + } + + stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); + if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) + { fini (); return; } + + globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); + if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) + { fini (); return; } + + charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset); + + if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) + { fini (); return; } + + num_glyphs = charStrings->count; + if (num_glyphs != sc.get_num_glyphs ()) + { fini (); return; } + + privateDicts.resize (fdCount); + for (unsigned int i = 0; i < fdCount; i++) + privateDicts[i].init (); + + // parse CID font dicts and gather private dicts + if (is_CID ()) + { + for (unsigned int i = 0; i < fdCount; i++) + { + byte_str_t fontDictStr = (*fdArray)[i]; + if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + cff1_font_dict_values_t *font; + cff1_font_dict_interpreter_t font_interp; + font_interp.env.init (fontDictStr); + font = fontDicts.push (); + if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; } + font->init (); + if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + PRIVDICTVAL *priv = &privateDicts[i]; + const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; + priv_interp.env.init (privDictStr); + priv->init (); + if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + + priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); + if (priv->localSubrs != &Null(CFF1Subrs) && + unlikely (!priv->localSubrs->sanitize (&sc))) + { fini (); return; } + } + } + else /* non-CID */ + { + cff1_top_dict_values_t *font = &topDict; + PRIVDICTVAL *priv = &privateDicts[0]; + + const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; + priv_interp.env.init (privDictStr); + priv->init (); + if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + + priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); + if (priv->localSubrs != &Null(CFF1Subrs) && + unlikely (!priv->localSubrs->sanitize (&sc))) + { fini (); return; } + } + } + + void fini () + { + sc.end_processing (); + topDict.fini (); + fontDicts.fini_deep (); + privateDicts.fini_deep (); + hb_blob_destroy (blob); + blob = nullptr; + } + + bool is_valid () const { return blob != nullptr; } + bool is_CID () const { return topDict.is_CID (); } + + bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } + + unsigned int std_code_to_glyph (hb_codepoint_t code) const + { + hb_codepoint_t sid = lookup_standard_encoding_for_sid (code); + if (unlikely (sid == CFF_UNDEF_SID)) + return 0; + + if (charset != &Null(Charset)) + return charset->get_glyph (sid, num_glyphs); + else if ((topDict.CharsetOffset == ISOAdobeCharset) + && (code <= 228 /*zcaron*/)) return sid; + return 0; + } + + protected: + hb_blob_t *blob; + hb_sanitize_context_t sc; + + public: + const Charset *charset; + const CFF1NameIndex *nameIndex; + const CFF1TopDictIndex *topDictIndex; + const CFF1StringIndex *stringIndex; + const CFF1Subrs *globalSubrs; + const CFF1CharStrings *charStrings; + const CFF1FDArray *fdArray; + const CFF1FDSelect *fdSelect; + unsigned int fdCount; + + cff1_top_dict_values_t topDict; + hb_vector_t<cff1_font_dict_values_t> fontDicts; + hb_vector_t<PRIVDICTVAL> privateDicts; + + unsigned int num_glyphs; + }; + + struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> + { + HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; + }; + + struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> + { + void init (hb_face_t *face) + { + SUPER::init (face); + if (blob == nullptr) return; + + const OT::cff1 *cff = this->blob->as<OT::cff1> (); + encoding = &Null(Encoding); + if (is_CID ()) + { + if (unlikely (charset == &Null(Charset))) { fini (); return; } + } + else + { + if (!is_predef_encoding ()) + { + encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); + if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + } + } + } + + bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } + + hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + { + if (encoding != &Null(Encoding)) + return encoding->get_code (glyph); + else + { + hb_codepoint_t sid = glyph_to_sid (glyph); + if (sid == 0) return 0; + hb_codepoint_t code = 0; + switch (topDict.EncodingOffset) + { + case StandardEncoding: + code = lookup_standard_encoding_for_code (sid); + break; + case ExpertEncoding: + code = lookup_expert_encoding_for_code (sid); + break; + default: + break; + } + return code; + } + } + + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + { + if (charset != &Null(Charset)) + return charset->get_sid (glyph); + else + { + hb_codepoint_t sid = 0; + switch (topDict.CharsetOffset) + { + case ISOAdobeCharset: + if (glyph <= 228 /*zcaron*/) sid = glyph; + break; + case ExpertCharset: + sid = lookup_expert_charset_for_sid (glyph); + break; + case ExpertSubsetCharset: + sid = lookup_expert_subset_charset_for_sid (glyph); + break; + default: + break; + } + return sid; + } + } + + const Encoding *encoding; + + private: + typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER; + }; + + bool subset (hb_subset_plan_t *plan) const + { + hb_blob_t *cff_prime = nullptr; + + bool success = true; + if (hb_subset_cff1 (plan, &cff_prime)) { + success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime); + hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); + success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); + hb_blob_destroy (head_blob); + } else { + success = false; + } + hb_blob_destroy (cff_prime); + + return success; + } + + protected: + HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); + + public: + FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */ + OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */ + HBUINT8 offSize; /* offset size (unused?) */ + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct cff1_accelerator_t : cff1::accelerator_t {}; +} /* namespace OT */ + +#endif /* HB_OT_CFF1_TABLE_HH */ diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc new file mode 100644 index 0000000..7daa536 --- /dev/null +++ b/src/hb-ot-cff2-table.cc @@ -0,0 +1,136 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-ot-cff2-table.hh" +#include "hb-cff2-interp-cs.hh" + +using namespace CFF; + +struct extents_param_t +{ + void init () + { + path_open = false; + min_x.set_int (0x7FFFFFFF); + min_y.set_int (0x7FFFFFFF); + max_x.set_int (-0x80000000); + max_y.set_int (-0x80000000); + } + + void start_path () { path_open = true; } + void end_path () { path_open = false; } + bool is_path_open () const { return path_open; } + + void update_bounds (const point_t &pt) + { + if (pt.x < min_x) min_x = pt.x; + if (pt.x > max_x) max_x = pt.x; + if (pt.y < min_y) min_y = pt.y; + if (pt.y > max_y) max_y = pt.y; + } + + bool path_open; + number_t min_x; + number_t min_y; + number_t max_x; + number_t max_y; +}; + +struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, extents_param_t> +{ + static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + { + param.end_path (); + env.moveto (pt); + } + + static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + { + if (!param.is_path_open ()) + { + param.start_path (); + param.update_bounds (env.get_pt ()); + } + env.moveto (pt1); + param.update_bounds (env.get_pt ()); + } + + static void curve (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + if (!param.is_path_open ()) + { + param.start_path (); + param.update_bounds (env.get_pt ()); + } + /* include control points */ + param.update_bounds (pt1); + param.update_bounds (pt2); + env.moveto (pt3); + param.update_bounds (env.get_pt ()); + } +}; + +struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, extents_param_t, cff2_path_procs_extents_t> {}; + +bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const +{ + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + + unsigned int num_coords; + const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); + unsigned int fd = fdSelect->get_fd (glyph); + cff2_cs_interpreter_t<cff2_cs_opset_extents_t, extents_param_t> interp; + const byte_str_t str = (*charStrings)[glyph]; + interp.env.init (str, *this, fd, coords, num_coords); + extents_param_t param; + param.init (); + if (unlikely (!interp.interpret (param))) return false; + + if (param.min_x >= param.max_x) + { + extents->width = 0; + extents->x_bearing = 0; + } + else + { + extents->x_bearing = (int32_t)param.min_x.floor (); + extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + } + if (param.min_y >= param.max_y) + { + extents->height = 0; + extents->y_bearing = 0; + } + else + { + extents->y_bearing = (int32_t)param.max_y.ceil (); + extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + } + + return true; +} diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh new file mode 100644 index 0000000..a7b0ba9 --- /dev/null +++ b/src/hb-ot-cff2-table.hh @@ -0,0 +1,566 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_CFF2_TABLE_HH +#define HB_OT_CFF2_TABLE_HH + +#include "hb-ot-head-table.hh" +#include "hb-ot-cff-common.hh" +#include "hb-subset-cff2.hh" + +namespace CFF { + +/* + * CFF2 -- Compact Font Format (CFF) Version 2 + * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2 + */ +#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') + +typedef CFFIndex<HBUINT32> CFF2Index; +template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {}; + +typedef CFF2Index CFF2CharStrings; +typedef FDArray<HBUINT32> CFF2FDArray; +typedef Subrs<HBUINT32> CFF2Subrs; + +typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4; +typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range; + +struct CFF2FDSelect +{ + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + + return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) && + (format == 0)? + u.format0.sanitize (c, fdcount): + ((format == 3)? + u.format3.sanitize (c, fdcount): + u.format4.sanitize (c, fdcount)))); + } + + bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs) + { + TRACE_SERIALIZE (this); + unsigned int size = src.get_size (num_glyphs); + CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, &src, size); + return_trace (true); + } + + unsigned int calculate_serialized_size (unsigned int num_glyphs) const + { return get_size (num_glyphs); } + + unsigned int get_size (unsigned int num_glyphs) const + { + unsigned int size = format.static_size; + if (format == 0) + size += u.format0.get_size (num_glyphs); + else if (format == 3) + size += u.format3.get_size (); + else + size += u.format4.get_size (); + return size; + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + if (this == &Null(CFF2FDSelect)) + return 0; + if (format == 0) + return u.format0.get_fd (glyph); + else if (format == 3) + return u.format3.get_fd (glyph); + else + return u.format4.get_fd (glyph); + } + + HBUINT8 format; + union { + FDSelect0 format0; + FDSelect3 format3; + FDSelect4 format4; + } u; + + DEFINE_SIZE_MIN (2); +}; + +struct CFF2VariationStore +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c)); + } + + bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore) + { + TRACE_SERIALIZE (this); + unsigned int size_ = varStore->get_size (); + CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_); + if (unlikely (dest == nullptr)) return_trace (false); + memcpy (dest, varStore, size_); + return_trace (true); + } + + unsigned int get_size () const { return HBUINT16::static_size + size; } + + HBUINT16 size; + VariationStore varStore; + + DEFINE_SIZE_MIN (2 + VariationStore::min_size); +}; + +struct cff2_top_dict_values_t : top_dict_values_t<> +{ + void init () + { + top_dict_values_t<>::init (); + vstoreOffset = 0; + FDSelectOffset = 0; + } + void fini () { top_dict_values_t<>::fini (); } + + unsigned int calculate_serialized_size () const + { + unsigned int size = 0; + for (unsigned int i = 0; i < get_count (); i++) + { + op_code_t op = get_value (i).op; + switch (op) + { + case OpCode_vstore: + case OpCode_FDSelect: + size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); + break; + default: + size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i)); + break; + } + } + return size; + } + + unsigned int vstoreOffset; + unsigned int FDSelectOffset; +}; + +struct cff2_top_dict_opset_t : top_dict_opset_t<> +{ + static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval) + { + switch (op) { + case OpCode_FontMatrix: + { + dict_val_t val; + val.init (); + dictval.add_op (op, env.str_ref); + env.clear_args (); + } + break; + + case OpCode_vstore: + dictval.vstoreOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_FDSelect: + dictval.FDSelectOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + SUPER::process_op (op, env, dictval); + /* Record this operand below if stack is empty, otherwise done */ + if (!env.argStack.is_empty ()) return; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref); + } + + typedef top_dict_opset_t<> SUPER; +}; + +struct cff2_font_dict_values_t : dict_values_t<op_str_t> +{ + void init () + { + dict_values_t<op_str_t>::init (); + privateDictInfo.init (); + } + void fini () { dict_values_t<op_str_t>::fini (); } + + table_info_t privateDictInfo; +}; + +struct cff2_font_dict_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval) + { + switch (op) { + case OpCode_Private: + dictval.privateDictInfo.offset = env.argStack.pop_uint (); + dictval.privateDictInfo.size = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + SUPER::process_op (op, env); + if (!env.argStack.is_empty ()) + return; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref); + } + + private: + typedef dict_opset_t SUPER; +}; + +template <typename VAL> +struct cff2_private_dict_values_base_t : dict_values_t<VAL> +{ + void init () + { + dict_values_t<VAL>::init (); + subrsOffset = 0; + localSubrs = &Null(CFF2Subrs); + ivs = 0; + } + void fini () { dict_values_t<VAL>::fini (); } + + unsigned int calculate_serialized_size () const + { + unsigned int size = 0; + for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++) + if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs) + size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); + else + size += dict_values_t<VAL>::get_value (i).str.length; + return size; + } + + unsigned int subrsOffset; + const CFF2Subrs *localSubrs; + unsigned int ivs; +}; + +typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t; +typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t; + +struct cff2_priv_dict_interp_env_t : num_interp_env_t +{ + void init (const byte_str_t &str) + { + num_interp_env_t::init (str); + ivs = 0; + seen_vsindex = false; + } + + void process_vsindex () + { + if (likely (!seen_vsindex)) + { + set_ivs (argStack.pop_uint ()); + } + seen_vsindex = true; + } + + unsigned int get_ivs () const { return ivs; } + void set_ivs (unsigned int ivs_) { ivs = ivs_; } + + protected: + unsigned int ivs; + bool seen_vsindex; +}; + +struct cff2_private_dict_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval) + { + num_dict_val_t val; + val.init (); + + switch (op) { + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_ExpansionFactor: + case OpCode_LanguageGroup: + val.single_val = env.argStack.pop_num (); + env.clear_args (); + break; + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + env.clear_args (); + break; + case OpCode_Subrs: + dictval.subrsOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + case OpCode_vsindexdict: + env.process_vsindex (); + dictval.ivs = env.get_ivs (); + env.clear_args (); + break; + case OpCode_blenddict: + break; + + default: + dict_opset_t::process_op (op, env); + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref, val); + } +}; + +struct cff2_private_dict_opset_subset_t : dict_opset_t +{ + static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval) + { + switch (op) { + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + case OpCode_LanguageGroup: + case OpCode_ExpansionFactor: + env.clear_args (); + break; + + case OpCode_blenddict: + env.clear_args (); + return; + + case OpCode_Subrs: + dictval.subrsOffset = env.argStack.pop_uint (); + env.clear_args (); + break; + + default: + SUPER::process_op (op, env); + if (!env.argStack.is_empty ()) return; + break; + } + + if (unlikely (env.in_error ())) return; + + dictval.add_op (op, env.str_ref); + } + + private: + typedef dict_opset_t SUPER; +}; + +typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t; +typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t; + +} /* namespace CFF */ + +namespace OT { + +using namespace CFF; + +struct cff2 +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version.major == 2)); + } + + template <typename PRIVOPSET, typename PRIVDICTVAL> + struct accelerator_templ_t + { + void init (hb_face_t *face) + { + topDict.init (); + fontDicts.init (); + privateDicts.init (); + + this->blob = sc.reference_table<cff2> (face); + + /* setup for run-time santization */ + sc.init (this->blob); + sc.start_processing (); + + const OT::cff2 *cff2 = this->blob->template as<OT::cff2> (); + + if (cff2 == &Null(OT::cff2)) + { fini (); return; } + + { /* parse top dict */ + byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); + if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } + cff2_top_dict_interpreter_t top_interp; + top_interp.env.init (topDictStr); + topDict.init (); + if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + } + + globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize); + varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset); + charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset); + fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset); + fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset); + + if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || + (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || + (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || + (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || + (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) + { fini (); return; } + + num_glyphs = charStrings->count; + if (num_glyphs != sc.get_num_glyphs ()) + { fini (); return; } + + fdCount = fdArray->count; + privateDicts.resize (fdCount); + + /* parse font dicts and gather private dicts */ + for (unsigned int i = 0; i < fdCount; i++) + { + const byte_str_t fontDictStr = (*fdArray)[i]; + if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + cff2_font_dict_values_t *font; + cff2_font_dict_interpreter_t font_interp; + font_interp.env.init (fontDictStr); + font = fontDicts.push (); + if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; } + font->init (); + if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + + const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); + if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp; + priv_interp.env.init(privDictStr); + privateDicts[i].init (); + if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } + + privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset); + if (privateDicts[i].localSubrs != &Null(CFF2Subrs) && + unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) + { fini (); return; } + } + } + + void fini () + { + sc.end_processing (); + topDict.fini (); + fontDicts.fini_deep (); + privateDicts.fini_deep (); + hb_blob_destroy (blob); + blob = nullptr; + } + + bool is_valid () const { return blob != nullptr; } + + protected: + hb_blob_t *blob; + hb_sanitize_context_t sc; + + public: + cff2_top_dict_values_t topDict; + const CFF2Subrs *globalSubrs; + const CFF2VariationStore *varStore; + const CFF2CharStrings *charStrings; + const CFF2FDArray *fdArray; + const CFF2FDSelect *fdSelect; + unsigned int fdCount; + + hb_vector_t<cff2_font_dict_values_t> fontDicts; + hb_vector_t<PRIVDICTVAL> privateDicts; + + unsigned int num_glyphs; + }; + + struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> + { + HB_INTERNAL bool get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const; + }; + + typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; + + bool subset (hb_subset_plan_t *plan) const + { + hb_blob_t *cff2_prime = nullptr; + + bool success = true; + if (hb_subset_cff2 (plan, &cff2_prime)) { + success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime); + hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); + success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); + hb_blob_destroy (head_blob); + } else { + success = false; + } + hb_blob_destroy (cff2_prime); + + return success; + } + + public: + FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */ + NNOffsetTo<TopDict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */ + HBUINT16 topDictSize; /* Top DICT size */ + + public: + DEFINE_SIZE_STATIC (5); +}; + +struct cff2_accelerator_t : cff2::accelerator_t {}; +} /* namespace OT */ + +#endif /* HB_OT_CFF2_TABLE_HH */ diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index c1903f6..0526c35 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -27,9 +27,8 @@ #ifndef HB_OT_CMAP_TABLE_HH #define HB_OT_CMAP_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-set-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" +#include "hb-set.hh" /* * cmap -- Character to Glyph Index Mapping @@ -37,13 +36,12 @@ */ #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') - namespace OT { struct CmapSubtableFormat0 { - inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; if (!gid) @@ -51,8 +49,14 @@ struct CmapSubtableFormat0 *glyph = gid; return true; } + void collect_unicodes (hb_set_t *out) const + { + for (unsigned int i = 0; i < 256; i++) + if (glyphIdArray[i]) + out->add (i); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -78,8 +82,8 @@ struct CmapSubtableFormat4 }; bool serialize (hb_serialize_context_t *c, - const hb_subset_plan_t *plan, - const hb_vector_t<segment_plan> &segments) + const hb_subset_plan_t *plan, + const hb_vector_t<segment_plan> &segments) { TRACE_SERIALIZE (this); @@ -88,92 +92,92 @@ struct CmapSubtableFormat4 this->format.set (4); this->length.set (get_sub_table_size (segments)); - this->segCountX2.set (segments.len * 2); - this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1); + this->segCountX2.set (segments.length * 2); + this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1); this->searchRange.set (2 * (1u << this->entrySelector)); - this->rangeShift.set (segments.len * 2 > this->searchRange - ? 2 * segments.len - this->searchRange - : 0); + this->rangeShift.set (segments.length * 2 > this->searchRange + ? 2 * segments.length - this->searchRange + : 0); - HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); + HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding. - HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); - HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len); - HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); + HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); + HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length); + HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); if (id_range_offset == nullptr) return_trace (false); - for (unsigned int i = 0; i < segments.len; i++) + for (unsigned int i = 0; i < segments.length; i++) { end_count[i].set (segments[i].end_code); start_count[i].set (segments[i].start_code); if (segments[i].use_delta) { - hb_codepoint_t cp = segments[i].start_code; - hb_codepoint_t start_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) - return_trace (false); - id_delta[i].set (start_gid - segments[i].start_code); + hb_codepoint_t cp = segments[i].start_code; + hb_codepoint_t start_gid = 0; + if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) + return_trace (false); + id_delta[i].set (start_gid - segments[i].start_code); } else { - id_delta[i].set (0); - unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; - HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints); - if (glyph_id_array == nullptr) - return_trace (false); - // From the cmap spec: - // - // id_range_offset[i]/2 - // + (cp - segments[i].start_code) - // + (id_range_offset + i) - // = - // glyph_id_array + (cp - segments[i].start_code) - // - // So, solve for id_range_offset[i]: - // - // id_range_offset[i] - // = - // 2 * (glyph_id_array - id_range_offset - i) - id_range_offset[i].set (2 * ( - glyph_id_array - id_range_offset - i)); - for (unsigned int j = 0; j < num_codepoints; j++) - { - hb_codepoint_t cp = segments[i].start_code + j; - hb_codepoint_t new_gid; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) - return_trace (false); - glyph_id_array[j].set (new_gid); - } + id_delta[i].set (0); + unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; + HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints); + if (glyph_id_array == nullptr) + return_trace (false); + // From the cmap spec: + // + // id_range_offset[i]/2 + // + (cp - segments[i].start_code) + // + (id_range_offset + i) + // = + // glyph_id_array + (cp - segments[i].start_code) + // + // So, solve for id_range_offset[i]: + // + // id_range_offset[i] + // = + // 2 * (glyph_id_array - id_range_offset - i) + id_range_offset[i].set (2 * ( + glyph_id_array - id_range_offset - i)); + for (unsigned int j = 0; j < num_codepoints; j++) + { + hb_codepoint_t cp = segments[i].start_code + j; + hb_codepoint_t new_gid; + if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) + return_trace (false); + glyph_id_array[j].set (new_gid); + } } } return_trace (true); } - static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments) + static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments) { size_t segment_size = 0; - for (unsigned int i = 0; i < segments.len; i++) + for (unsigned int i = 0; i < segments.length; i++) { // Parallel array entries segment_size += - 2 // end count - + 2 // start count - + 2 // delta - + 2; // range offset + 2 // end count + + 2 // start count + + 2 // delta + + 2; // range offset if (!segments[i].use_delta) - // Add bytes for the glyph index array entries for this segment. - segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; + // Add bytes for the glyph index array entries for this segment. + segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; } return min_size - + 2 // Padding - + segment_size; + + 2 // Padding + + segment_size; } - static inline bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_vector_t<segment_plan> *segments) + static bool create_sub_table_plan (const hb_subset_plan_t *plan, + hb_vector_t<segment_plan> *segments) { segment_plan *segment = nullptr; hb_codepoint_t last_gid = 0; @@ -187,24 +191,22 @@ struct CmapSubtableFormat4 return false; } - if (cp > 0xFFFF) { - // We are now outside of unicode BMP, stop adding to this cmap. - break; - } + /* Stop adding to cmap if we are now outside of unicode BMP. */ + if (cp > 0xFFFF) break; - if (!segment - || cp != segment->end_code + 1u) + if (!segment || + cp != segment->end_code + 1u) { - segment = segments->push (); - segment->start_code.set (cp); - segment->end_code.set (cp); - segment->use_delta = true; + segment = segments->push (); + segment->start_code.set (cp); + segment->end_code.set (cp); + segment->use_delta = true; } else { - segment->end_code.set (cp); - if (last_gid + 1u != new_gid) - // gid's are not consecutive in this segment so delta - // cannot be used. - segment->use_delta = false; + segment->end_code.set (cp); + if (last_gid + 1u != new_gid) + // gid's are not consecutive in this segment so delta + // cannot be used. + segment->use_delta = false; } last_gid = new_gid; @@ -224,29 +226,32 @@ struct CmapSubtableFormat4 struct accelerator_t { - inline void init (const CmapSubtableFormat4 *subtable) + accelerator_t () {} + accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } + ~accelerator_t () { fini (); } + + void init (const CmapSubtableFormat4 *subtable) { segCount = subtable->segCountX2 / 2; - endCount = subtable->values; + endCount = subtable->values.arrayZ; startCount = endCount + segCount + 1; idDelta = startCount + segCount; idRangeOffset = idDelta + segCount; glyphIdArray = idRangeOffset + segCount; glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; } + void fini () {} - static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - const accelerator_t *thiz = (const accelerator_t *) obj; - /* Custom two-array bsearch. */ - int min = 0, max = (int) thiz->segCount - 1; - const HBUINT16 *startCount = thiz->startCount; - const HBUINT16 *endCount = thiz->endCount; + int min = 0, max = (int) this->segCount - 1; + const HBUINT16 *startCount = this->startCount; + const HBUINT16 *endCount = this->endCount; unsigned int i; while (min <= max) { - int mid = (min + max) / 2; + int mid = ((unsigned int) min + (unsigned int) max) / 2; if (codepoint < startCount[mid]) max = mid - 1; else if (codepoint > endCount[mid]) @@ -261,33 +266,55 @@ struct CmapSubtableFormat4 found: hb_codepoint_t gid; - unsigned int rangeOffset = thiz->idRangeOffset[i]; + unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) - gid = codepoint + thiz->idDelta[i]; + gid = codepoint + this->idDelta[i]; else { /* Somebody has been smoking... */ - unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount; - if (unlikely (index >= thiz->glyphIdArrayLength)) + unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) return false; - gid = thiz->glyphIdArray[index]; + gid = this->glyphIdArray[index]; if (unlikely (!gid)) return false; - gid += thiz->idDelta[i]; + gid += this->idDelta[i]; } - - *glyph = gid & 0xFFFFu; + gid &= 0xFFFFu; + if (!gid) + return false; + *glyph = gid; return true; } - - static inline void get_all_codepoints_func (const void *obj, hb_set_t *out) + static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) { - const accelerator_t *thiz = (const accelerator_t *) obj; - for (unsigned int i = 0; i < thiz->segCount; i++) + return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); + } + void collect_unicodes (hb_set_t *out) const + { + unsigned int count = this->segCount; + if (count && this->startCount[count - 1] == 0xFFFFu) + count--; /* Skip sentinel segment. */ + for (unsigned int i = 0; i < count; i++) { - if (thiz->startCount[i] != 0xFFFFu - || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF) - hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]); + unsigned int rangeOffset = this->idRangeOffset[i]; + if (rangeOffset == 0) + out->add_range (this->startCount[i], this->endCount[i]); + else + { + for (hb_codepoint_t codepoint = this->startCount[i]; + codepoint <= this->endCount[i]; + codepoint++) + { + unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) + break; + hb_codepoint_t gid = this->glyphIdArray[index]; + if (unlikely (!gid)) + continue; + out->add (codepoint); + } + } } } @@ -300,14 +327,18 @@ struct CmapSubtableFormat4 unsigned int glyphIdArrayLength; }; - inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - accelerator_t accel; - accel.init (this); + accelerator_t accel (this); return accel.get_glyph_func (&accel, codepoint, glyph); } + void collect_unicodes (hb_set_t *out) const + { + accelerator_t accel (this); + accel.collect_unicodes (out); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) @@ -340,7 +371,8 @@ struct CmapSubtableFormat4 HBUINT16 entrySelector; /* log2(searchRange/2) */ HBUINT16 rangeShift; /* 2 x segCount - searchRange */ - HBUINT16 values[VAR]; + UnsizedArrayOf<HBUINT16> + values; #if 0 HBUINT16 endCount[segCount]; /* End characterCode for each segment, * last=0xFFFFu. */ @@ -348,7 +380,8 @@ struct CmapSubtableFormat4 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ - HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ + UnsizedArrayOf<HBUINT16> + glyphIdArray; /* Glyph index array (arbitrary length) */ #endif public: @@ -370,7 +403,7 @@ struct CmapSubtableLongGroup return 0; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -380,15 +413,16 @@ struct CmapSubtableLongGroup HBUINT32 startCharCode; /* First character code in this group. */ HBUINT32 endCharCode; /* Last character code in this group. */ HBUINT32 glyphID; /* Glyph index; interpretation depends on - * subtable format. */ + * subtable format. */ public: DEFINE_SIZE_STATIC (12); }; +DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup); template <typename UINT> struct CmapSubtableTrimmed { - inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { /* Rely on our implicit array bound-checking. */ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; @@ -397,8 +431,16 @@ struct CmapSubtableTrimmed *glyph = gid; return true; } + void collect_unicodes (hb_set_t *out) const + { + hb_codepoint_t start = startCharCode; + unsigned int count = glyphIdArray.len; + for (unsigned int i = 0; i < count; i++) + if (glyphIdArray[i]) + out->add (start + i); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); @@ -424,37 +466,36 @@ struct CmapSubtableLongSegmented { friend struct cmap; - inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - int i = groups.bsearch (codepoint); - if (i == -1) + hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); + if (!gid) return false; - *glyph = T::group_get_glyph (groups[i], codepoint); + *glyph = gid; return true; } - inline void get_all_codepoints (hb_set_t *out) const + void collect_unicodes (hb_set_t *out) const { for (unsigned int i = 0; i < this->groups.len; i++) { - hb_set_add_range (out, - this->groups[i].startCharCode, - this->groups[i].endCharCode); + out->add_range (this->groups[i].startCharCode, + MIN ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX)); } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && groups.sanitize (c)); } - inline bool serialize (hb_serialize_context_t *c, - const hb_vector_t<CmapSubtableLongGroup> &group_data) + bool serialize (hb_serialize_context_t *c, + const hb_vector_t<CmapSubtableLongGroup> &group_data) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len); - if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false); + if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false); return true; } @@ -471,13 +512,14 @@ struct CmapSubtableLongSegmented struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> { - static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, - hb_codepoint_t u) - { return group.glyphID + (u - group.startCharCode); } + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, + hb_codepoint_t u) + { return likely (group.startCharCode <= group.endCharCode) ? + group.glyphID + (u - group.startCharCode) : 0; } bool serialize (hb_serialize_context_t *c, - const hb_vector_t<CmapSubtableLongGroup> &groups) + const hb_vector_t<CmapSubtableLongGroup> &groups) { if (unlikely (!c->extend_min (*this))) return false; @@ -488,13 +530,13 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups); } - static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups) + static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups) { - return 16 + 12 * groups.len; + return 16 + 12 * groups.length; } - static inline bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_vector_t<CmapSubtableLongGroup> *groups) + static bool create_sub_table_plan (const hb_subset_plan_t *plan, + hb_vector_t<CmapSubtableLongGroup> *groups) { CmapSubtableLongGroup *group = nullptr; @@ -509,18 +551,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> if (!group || !_is_gid_consecutive (group, cp, new_gid)) { - group = groups->push (); - group->startCharCode.set (cp); - group->endCharCode.set (cp); - group->glyphID.set (new_gid); - } else - { - group->endCharCode.set (cp); + group = groups->push (); + group->startCharCode.set (cp); + group->endCharCode.set (cp); + group->glyphID.set (new_gid); } + else group->endCharCode.set (cp); } DEBUG_MSG(SUBSET, nullptr, "cmap"); - for (unsigned int i = 0; i < groups->len; i++) { + for (unsigned int i = 0; i < groups->length; i++) { CmapSubtableLongGroup& group = (*groups)[i]; DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode)); } @@ -529,9 +569,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> } private: - static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group, - hb_codepoint_t cp, - hb_codepoint_t new_gid) + static bool _is_gid_consecutive (CmapSubtableLongGroup *group, + hb_codepoint_t cp, + hb_codepoint_t new_gid) { return (cp - 1 == group->endCharCode) && new_gid == group->glyphID + (cp - group->startCharCode); @@ -541,8 +581,8 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> { - static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, - hb_codepoint_t u HB_UNUSED) + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, + hb_codepoint_t u HB_UNUSED) { return group.glyphID; } }; @@ -555,36 +595,52 @@ typedef enum struct UnicodeValueRange { - inline int cmp (const hb_codepoint_t &codepoint) const + int cmp (const hb_codepoint_t &codepoint) const { if (codepoint < startUnicodeValue) return -1; if (codepoint > startUnicodeValue + additionalCount) return +1; return 0; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } HBUINT24 startUnicodeValue; /* First value in this range. */ - HBUINT8 additionalCount; /* Number of additional values in this + HBUINT8 additionalCount; /* Number of additional values in this * range. */ public: DEFINE_SIZE_STATIC (4); }; -typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS; +struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32> +{ + void collect_unicodes (hb_set_t *out) const + { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + hb_codepoint_t first = arrayZ[i].startUnicodeValue; + hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount), + (hb_codepoint_t) HB_UNICODE_MAX); + out->add_range (first, last); + } + } + + public: + DEFINE_SIZE_ARRAY (4, *this); +}; struct UVSMapping { - inline int cmp (const hb_codepoint_t &codepoint) const + int cmp (const hb_codepoint_t &codepoint) const { return unicodeValue.cmp (codepoint); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -596,35 +652,48 @@ struct UVSMapping DEFINE_SIZE_STATIC (5); }; -typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS; +struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32> +{ + void collect_unicodes (hb_set_t *out) const + { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + out->add (arrayZ[i].glyphID); + } + + public: + DEFINE_SIZE_ARRAY (4, *this); +}; struct VariationSelectorRecord { - inline glyph_variant_t get_glyph (hb_codepoint_t codepoint, - hb_codepoint_t *glyph, - const void *base) const + glyph_variant_t get_glyph (hb_codepoint_t codepoint, + hb_codepoint_t *glyph, + const void *base) const { - int i; - const DefaultUVS &defaults = base+defaultUVS; - i = defaults.bsearch (codepoint); - if (i != -1) + if ((base+defaultUVS).bfind (codepoint)) return GLYPH_VARIANT_USE_DEFAULT; - const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; - i = nonDefaults.bsearch (codepoint); - if (i != -1) + const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); + if (nonDefault.glyphID) { - *glyph = nonDefaults[i].glyphID; + *glyph = nonDefault.glyphID; return GLYPH_VARIANT_FOUND; } return GLYPH_VARIANT_NOT_FOUND; } - inline int cmp (const hb_codepoint_t &variation_selector) const + void collect_unicodes (hb_set_t *out, const void *base) const + { + (base+defaultUVS).collect_unicodes (out); + (base+nonDefaultUVS).collect_unicodes (out); + } + + int cmp (const hb_codepoint_t &variation_selector) const { return varSelector.cmp (variation_selector); } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -634,23 +703,35 @@ struct VariationSelectorRecord HBUINT24 varSelector; /* Variation selector. */ LOffsetTo<DefaultUVS> - defaultUVS; /* Offset to Default UVS Table. May be 0. */ + defaultUVS; /* Offset to Default UVS Table. May be 0. */ LOffsetTo<NonDefaultUVS> - nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ + nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ public: DEFINE_SIZE_STATIC (11); }; struct CmapSubtableFormat14 { - inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, - hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) const + glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const { - return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); + return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); } - inline bool sanitize (hb_sanitize_context_t *c) const + void collect_variation_selectors (hb_set_t *out) const + { + unsigned int count = record.len; + for (unsigned int i = 0; i < count; i++) + out->add (record.arrayZ[i].varSelector); + } + void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const + { + record.bsearch (variation_selector).collect_unicodes (out, this); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -671,8 +752,8 @@ struct CmapSubtable { /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ - inline bool get_glyph (hb_codepoint_t codepoint, - hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, + hb_codepoint_t *glyph) const { switch (u.format) { case 0: return u.format0 .get_glyph (codepoint, glyph); @@ -685,8 +766,21 @@ struct CmapSubtable default: return false; } } + void collect_unicodes (hb_set_t *out) const + { + switch (u.format) { + case 0: u.format0 .collect_unicodes (out); return; + case 4: u.format4 .collect_unicodes (out); return; + case 6: u.format6 .collect_unicodes (out); return; + case 10: u.format10.collect_unicodes (out); return; + case 12: u.format12.collect_unicodes (out); return; + case 13: u.format13.collect_unicodes (out); return; + case 14: + default: return; + } + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -720,7 +814,7 @@ struct CmapSubtable struct EncodingRecord { - inline int cmp (const EncodingRecord &other) const + int cmp (const EncodingRecord &other) const { int ret; ret = platformID.cmp (other.platformID); @@ -730,7 +824,7 @@ struct EncodingRecord return 0; } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -747,106 +841,85 @@ struct EncodingRecord struct cmap { - static const hb_tag_t tableTag = HB_OT_TAG_cmap; + static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; - struct subset_plan { - subset_plan(void) - { - format4_segments.init(); - format12_groups.init(); - } - - ~subset_plan(void) - { - format4_segments.fini(); - format12_groups.fini(); - } - - inline size_t final_size() const + struct subset_plan + { + size_t final_size () const { return 4 // header - + 8 * 3 // 3 EncodingRecord - + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) - + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); + + 8 * 3 // 3 EncodingRecord + + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) + + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); } - // Format 4 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments; - // Format 12 hb_vector_t<CmapSubtableLongGroup> format12_groups; }; - inline bool sanitize (hb_sanitize_context_t *c) const + bool _create_plan (const hb_subset_plan_t *plan, + subset_plan *cmap_plan) const { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - likely (version == 0) && - encodingRecord.sanitize (c, this)); - } - - inline bool _create_plan (const hb_subset_plan_t *plan, - subset_plan *cmap_plan) const - { - if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) + if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) return false; return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); } - inline bool _subset (const hb_subset_plan_t *plan, - const subset_plan &cmap_subset_plan, - size_t dest_sz, - void *dest) const + bool _subset (const hb_subset_plan_t *plan, + const subset_plan &cmap_subset_plan, + size_t dest_sz, + void *dest) const { hb_serialize_context_t c (dest, dest_sz); - OT::cmap *cmap = c.start_serialize<OT::cmap> (); - if (unlikely (!c.extend_min (*cmap))) + cmap *table = c.start_serialize<cmap> (); + if (unlikely (!c.extend_min (*table))) { return false; } - cmap->version.set (0); + table->version.set (0); - if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3))) + if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3))) return false; // TODO(grieger): Convert the below to a for loop // Format 4, Plat 0 Encoding Record - EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0]; + EncodingRecord &format4_plat0_rec = table->encodingRecord[0]; format4_plat0_rec.platformID.set (0); // Unicode format4_plat0_rec.encodingID.set (3); // Format 4, Plat 3 Encoding Record - EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1]; + EncodingRecord &format4_plat3_rec = table->encodingRecord[1]; format4_plat3_rec.platformID.set (3); // Windows format4_plat3_rec.encodingID.set (1); // Unicode BMP // Format 12 Encoding Record - EncodingRecord &format12_rec = cmap->encodingRecord[2]; + EncodingRecord &format12_rec = table->encodingRecord[2]; format12_rec.platformID.set (3); // Windows format12_rec.encodingID.set (10); // Unicode UCS-4 // Write out format 4 sub table { - CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap); + CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table); format4_plat3_rec.subtable.set (format4_plat0_rec.subtable); subtable.u.format.set (4); CmapSubtableFormat4 &format4 = subtable.u.format4; if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) - return false; + return false; } // Write out format 12 sub table. { - CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap); + CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table); subtable.u.format.set (12); CmapSubtableFormat12 &format12 = subtable.u.format12; if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) - return false; + return false; } c.end_serialize (); @@ -854,7 +927,7 @@ struct cmap return true; } - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { subset_plan cmap_subset_plan; @@ -865,7 +938,7 @@ struct cmap } // We now know how big our blob needs to be - size_t dest_sz = cmap_subset_plan.final_size(); + size_t dest_sz = cmap_subset_plan.final_size (); void *dest = malloc (dest_sz); if (unlikely (!dest)) { DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); @@ -880,147 +953,159 @@ struct cmap } // all done, write the blob into dest - hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest, - dest_sz, - HB_MEMORY_MODE_READONLY, - dest, - free); + hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest, + dest_sz, + HB_MEMORY_MODE_READONLY, + dest, + free); bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime); hb_blob_destroy (cmap_prime); return result; } - struct accelerator_t + const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const { - inline void init (hb_face_t *face) + if (symbol) *symbol = false; + + const CmapSubtable *subtable; + + /* 32-bit subtables. */ + if ((subtable = this->find_subtable (3, 10))) return subtable; + if ((subtable = this->find_subtable (0, 6))) return subtable; + if ((subtable = this->find_subtable (0, 4))) return subtable; + + /* 16-bit subtables. */ + if ((subtable = this->find_subtable (3, 1))) return subtable; + if ((subtable = this->find_subtable (0, 3))) return subtable; + if ((subtable = this->find_subtable (0, 2))) return subtable; + if ((subtable = this->find_subtable (0, 1))) return subtable; + if ((subtable = this->find_subtable (0, 0))) return subtable; + + /* Symbol subtable. */ + if ((subtable = this->find_subtable (3, 0))) { - this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap)); - const OT::cmap *cmap = this->blob->as<OT::cmap> (); - const OT::CmapSubtable *subtable = nullptr; - const OT::CmapSubtableFormat14 *subtable_uvs = nullptr; - - bool symbol = false; - /* 32-bit subtables. */ - if (!subtable) subtable = cmap->find_subtable (3, 10); - if (!subtable) subtable = cmap->find_subtable (0, 6); - if (!subtable) subtable = cmap->find_subtable (0, 4); - /* 16-bit subtables. */ - if (!subtable) subtable = cmap->find_subtable (3, 1); - if (!subtable) subtable = cmap->find_subtable (0, 3); - if (!subtable) subtable = cmap->find_subtable (0, 2); - if (!subtable) subtable = cmap->find_subtable (0, 1); - if (!subtable) subtable = cmap->find_subtable (0, 0); - if (!subtable) - { - subtable = cmap->find_subtable (3, 0); - if (subtable) symbol = true; - } - /* Meh. */ - if (!subtable) subtable = &Null(OT::CmapSubtable); + if (symbol) *symbol = true; + return subtable; + } + + /* Meh. */ + return &Null (CmapSubtable); + } - /* UVS subtable. */ - if (!subtable_uvs) + struct accelerator_t + { + void init (hb_face_t *face) + { + this->table = hb_sanitize_context_t ().reference_table<cmap> (face); + bool symbol; + this->subtable = table->find_best_subtable (&symbol); + this->subtable_uvs = &Null (CmapSubtableFormat14); { - const OT::CmapSubtable *st = cmap->find_subtable (0, 5); + const CmapSubtable *st = table->find_subtable (0, 5); if (st && st->u.format == 14) subtable_uvs = &st->u.format14; } - /* Meh. */ - if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14); - - this->uvs_table = subtable_uvs; this->get_glyph_data = subtable; if (unlikely (symbol)) { - this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>; - this->get_all_codepoints_func = null_get_all_codepoints_func; + this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>; } else { switch (subtable->u.format) { /* Accelerate format 4 and format 12. */ default: - this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; - this->get_all_codepoints_func = null_get_all_codepoints_func; + this->get_glyph_funcZ = get_glyph_from<CmapSubtable>; break; case 12: - this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; - this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>; + this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>; break; case 4: { this->format4_accel.init (&subtable->u.format4); this->get_glyph_data = &this->format4_accel; - this->get_glyph_func = this->format4_accel.get_glyph_func; - this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func; + this->get_glyph_funcZ = this->format4_accel.get_glyph_func; } break; } } } - inline void fini (void) - { - hb_blob_destroy (this->blob); - } + void fini () { this->table.destroy (); } - inline bool get_nominal_glyph (hb_codepoint_t unicode, + bool get_nominal_glyph (hb_codepoint_t unicode, hb_codepoint_t *glyph) const { - return this->get_glyph_func (this->get_glyph_data, unicode, glyph); + if (unlikely (!this->get_glyph_funcZ)) return false; + return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); } + unsigned int get_nominal_glyphs (unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) const + { + if (unlikely (!this->get_glyph_funcZ)) return 0; - inline bool get_variation_glyph (hb_codepoint_t unicode, - hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) const + hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; + const void *get_glyph_data = this->get_glyph_data; + + unsigned int done; + for (done = 0; + done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); + done++) + { + first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + } + return done; + } + + bool get_variation_glyph (hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const { - switch (this->uvs_table->get_glyph_variant (unicode, - variation_selector, - glyph)) + switch (this->subtable_uvs->get_glyph_variant (unicode, + variation_selector, + glyph)) { - case OT::GLYPH_VARIANT_NOT_FOUND: return false; - case OT::GLYPH_VARIANT_FOUND: return true; - case OT::GLYPH_VARIANT_USE_DEFAULT: break; + case GLYPH_VARIANT_NOT_FOUND: return false; + case GLYPH_VARIANT_FOUND: return true; + case GLYPH_VARIANT_USE_DEFAULT: break; } return get_nominal_glyph (unicode, glyph); } - inline void get_all_codepoints (hb_set_t *out) const + void collect_unicodes (hb_set_t *out) const + { + subtable->collect_unicodes (out); + } + void collect_variation_selectors (hb_set_t *out) const + { + subtable_uvs->collect_variation_selectors (out); + } + void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const { - this->get_all_codepoints_func (get_glyph_data, out); + subtable_uvs->collect_variation_unicodes (variation_selector, out); } protected: typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph); - typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj, - hb_set_t *out); - - static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out) - { - // NOOP - } template <typename Type> - static inline bool get_glyph_from (const void *obj, - hb_codepoint_t codepoint, - hb_codepoint_t *glyph) + static bool get_glyph_from (const void *obj, + hb_codepoint_t codepoint, + hb_codepoint_t *glyph) { const Type *typed_obj = (const Type *) obj; return typed_obj->get_glyph (codepoint, glyph); } template <typename Type> - static inline void get_all_codepoints_from (const void *obj, - hb_set_t *out) - { - const Type *typed_obj = (const Type *) obj; - typed_obj->get_all_codepoints (out); - } - - template <typename Type> - static inline bool get_glyph_from_symbol (const void *obj, + static bool get_glyph_from_symbol (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) { @@ -1042,33 +1127,41 @@ struct cmap } private: - hb_cmap_get_glyph_func_t get_glyph_func; + hb_nonnull_ptr_t<const CmapSubtable> subtable; + hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs; + + hb_cmap_get_glyph_func_t get_glyph_funcZ; const void *get_glyph_data; - hb_cmap_get_all_codepoints_func_t get_all_codepoints_func; - OT::CmapSubtableFormat4::accelerator_t format4_accel; + CmapSubtableFormat4::accelerator_t format4_accel; - const OT::CmapSubtableFormat14 *uvs_table; - hb_blob_t *blob; + hb_blob_ptr_t<cmap> table; }; protected: - inline const CmapSubtable *find_subtable (unsigned int platform_id, - unsigned int encoding_id) const + const CmapSubtable *find_subtable (unsigned int platform_id, + unsigned int encoding_id) const { EncodingRecord key; key.platformID.set (platform_id); key.encodingID.set (encoding_id); - /* Note: We can use bsearch, but since it has no performance - * implications, we use lsearch and as such accept fonts with - * unsorted subtable list. */ - int result = encodingRecord./*bsearch*/lsearch (key); - if (result == -1 || !encodingRecord[result].subtable) + const EncodingRecord &result = encodingRecord.bsearch (key); + if (!result.subtable) return nullptr; - return &(this+encodingRecord[result].subtable); + return &(this+result.subtable); + } + + public: + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version == 0) && + encodingRecord.sanitize (c, this)); } protected: @@ -1079,6 +1172,7 @@ struct cmap DEFINE_SIZE_ARRAY (4, encodingRecord); }; +struct cmap_accelerator_t : cmap::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index d1dd9de..333ceaa 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_COLOR_CBDT_TABLE_HH #define HB_OT_COLOR_CBDT_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * CBLC -- Color Bitmap Location @@ -45,18 +45,18 @@ namespace OT { struct SmallGlyphMetrics { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - inline void get_extents (hb_glyph_extents_t *extents) const + void get_extents (hb_glyph_extents_t *extents) const { extents->x_bearing = bearingX; extents->y_bearing = bearingY; extents->width = width; - extents->height = -height; + extents->height = - (hb_position_t) height; } HBUINT8 height; @@ -79,7 +79,7 @@ struct BigGlyphMetrics : SmallGlyphMetrics struct SBitLineMetrics { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -108,7 +108,7 @@ struct SBitLineMetrics struct IndexSubtableHeader { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -124,11 +124,11 @@ struct IndexSubtableHeader template <typename OffsetType> struct IndexSubtableFormat1Or3 { - inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const + bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1)); + offsetArrayZ.sanitize (c, glyph_count + 1)); } bool get_image_data (unsigned int idx, @@ -144,7 +144,8 @@ struct IndexSubtableFormat1Or3 } IndexSubtableHeader header; - Offset<OffsetType> offsetArrayZ[VAR]; + UnsizedArrayOf<Offset<OffsetType> > + offsetArrayZ; public: DEFINE_SIZE_ARRAY(8, offsetArrayZ); }; @@ -154,7 +155,7 @@ struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {}; struct IndexSubtable { - inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const + bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const { TRACE_SANITIZE (this); if (!u.header.sanitize (c)) return_trace (false); @@ -165,7 +166,7 @@ struct IndexSubtable } } - inline bool get_extents (hb_glyph_extents_t *extents) const + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const { switch (u.header.indexFormat) { case 2: case 5: /* TODO */ @@ -200,29 +201,28 @@ struct IndexSubtable struct IndexSubtableRecord { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && firstGlyphIndex <= lastGlyphIndex && - offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1)); + offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } - inline bool get_extents (hb_glyph_extents_t *extents) const + bool get_extents (hb_glyph_extents_t *extents, + const void *base) const { - return (this+offsetToSubtable).get_extents (extents); + return (base+offsetToSubtable).get_extents (extents); } - bool get_image_data (unsigned int gid, + bool get_image_data (unsigned int gid, + const void *base, unsigned int *offset, unsigned int *length, unsigned int *format) const { - if (gid < firstGlyphIndex || gid > lastGlyphIndex) - { - return false; - } - return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex, + if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false; + return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex, offset, length, format); } @@ -237,15 +237,10 @@ struct IndexSubtableArray { friend struct CBDT; - inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + bool sanitize (hb_sanitize_context_t *c, unsigned int count) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count))) - return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!indexSubtablesZ[i].sanitize (c, this))) - return_trace (false); - return_trace (true); + return_trace (indexSubtablesZ.sanitize (c, count, this)); } public: @@ -255,17 +250,14 @@ struct IndexSubtableArray { unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex; unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex; - if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) { + if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) return &indexSubtablesZ[i]; - } } return nullptr; } protected: - IndexSubtableRecord indexSubtablesZ[VAR]; - public: - DEFINE_SIZE_ARRAY(0, indexSubtablesZ); + UnsizedArrayOf<IndexSubtableRecord> indexSubtablesZ; }; struct BitmapSizeTable @@ -273,23 +265,25 @@ struct BitmapSizeTable friend struct CBLC; friend struct CBDT; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && - c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) && horizontal.sanitize (c) && vertical.sanitize (c)); } - const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const + const IndexSubtableRecord *find_table (hb_codepoint_t glyph, + const void *base, + const void **out_base) const { + *out_base = &(base+indexSubtableArrayOffset); return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables); } protected: - LOffsetTo<IndexSubtableArray> + LNNOffsetTo<IndexSubtableArray> indexSubtableArrayOffset; HBUINT32 indexTablesSize; HBUINT32 numberOfIndexSubtables; @@ -338,9 +332,9 @@ struct CBLC { friend struct CBDT; - static const hb_tag_t tableTag = HB_OT_TAG_CBLC; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -349,25 +343,30 @@ struct CBLC } protected: - const IndexSubtableRecord *find_table (hb_codepoint_t glyph, - unsigned int *x_ppem, unsigned int *y_ppem) const + const BitmapSizeTable &choose_strike (hb_font_t *font) const { - /* TODO: Make it possible to select strike. */ + unsigned count = sizeTables.len; + if (unlikely (!count)) + return Null(BitmapSizeTable); + + unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem); + if (!requested_ppem) + requested_ppem = 1<<30; /* Choose largest strike. */ + unsigned int best_i = 0; + unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY); - unsigned int count = sizeTables.len; - for (uint32_t i = 0; i < count; ++i) + for (unsigned int i = 1; i < count; i++) { - unsigned int startGlyphIndex = sizeTables.arrayZ[i].startGlyphIndex; - unsigned int endGlyphIndex = sizeTables.arrayZ[i].endGlyphIndex; - if (startGlyphIndex <= glyph && glyph <= endGlyphIndex) + unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY); + if ((requested_ppem <= ppem && ppem < best_ppem) || + (requested_ppem > best_ppem && ppem > best_ppem)) { - *x_ppem = sizeTables[i].ppemX; - *y_ppem = sizeTables[i].ppemY; - return sizeTables[i].find_table (glyph, this); + best_i = i; + best_ppem = ppem; } } - return nullptr; + return sizeTables[best_i]; } protected: @@ -379,60 +378,42 @@ struct CBLC struct CBDT { - static const hb_tag_t tableTag = HB_OT_TAG_CBDT; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - likely (version.major == 2 || version.major == 3)); - } + static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT; struct accelerator_t { - inline void init (hb_face_t *face) + void init (hb_face_t *face) { - upem = hb_face_get_upem (face); - - cblc_blob = Sanitizer<CBLC>().sanitize (face->reference_table (HB_OT_TAG_CBLC)); - cbdt_blob = Sanitizer<CBDT>().sanitize (face->reference_table (HB_OT_TAG_CBDT)); - cbdt_len = hb_blob_get_length (cbdt_blob); - - if (hb_blob_get_length (cblc_blob) == 0) { - cblc = nullptr; - cbdt = nullptr; - return; /* Not a bitmap font. */ - } - cblc = cblc_blob->as<CBLC> (); - cbdt = cbdt_blob->as<CBDT> (); + cblc = hb_sanitize_context_t().reference_table<CBLC> (face); + cbdt = hb_sanitize_context_t().reference_table<CBDT> (face); + upem = hb_face_get_upem (face); } - inline void fini (void) + void fini () { - hb_blob_destroy (this->cblc_blob); - hb_blob_destroy (this->cbdt_blob); + this->cblc.destroy (); + this->cbdt.destroy (); } - inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + bool get_extents (hb_font_t *font, hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const { - unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */ - - if (!cblc) - return false; // Not a color bitmap font. - - const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem); - if (!subtable_record || !x_ppem || !y_ppem) + const void *base; + const BitmapSizeTable &strike = this->cblc->choose_strike (font); + const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base); + if (!subtable_record || !strike.ppemX || !strike.ppemY) return false; - if (subtable_record->get_extents (extents)) + if (subtable_record->get_extents (extents, base)) return true; unsigned int image_offset = 0, image_length = 0, image_format = 0; - if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format)) + if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return false; { + unsigned int cbdt_len = cbdt.get_length (); if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) return false; @@ -441,98 +422,114 @@ struct CBDT case 17: { if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; - const GlyphBitmapDataFormat17& glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset); glyphFormat17.glyphMetrics.get_extents (extents); + break; + } + case 18: { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return false; + const GlyphBitmapDataFormat18& glyphFormat18 = + StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset); + glyphFormat18.glyphMetrics.get_extents (extents); + break; } - break; default: // TODO: Support other image formats. return false; } } - /* Convert to the font units. */ - extents->x_bearing *= upem / (float) x_ppem; - extents->y_bearing *= upem / (float) y_ppem; - extents->width *= upem / (float) x_ppem; - extents->height *= upem / (float) y_ppem; + /* Convert to font units. */ + double x_scale = upem / (double) strike.ppemX; + double y_scale = upem / (double) strike.ppemY; + extents->x_bearing = round (extents->x_bearing * x_scale); + extents->y_bearing = round (extents->y_bearing * y_scale); + extents->width = round (extents->width * x_scale); + extents->height = round (extents->height * y_scale); return true; } - inline void dump (void (*callback) (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid)) const + hb_blob_t* reference_png (hb_font_t *font, + hb_codepoint_t glyph) const { - if (!cblc) - return; // Not a color bitmap font. + const void *base; + const BitmapSizeTable &strike = this->cblc->choose_strike (font); + const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base); + if (!subtable_record || !strike.ppemX || !strike.ppemY) + return hb_blob_get_empty (); + + unsigned int image_offset = 0, image_length = 0, image_format = 0; + if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) + return hb_blob_get_empty (); - for (unsigned int i = 0; i < cblc->sizeTables.len; ++i) { - const BitmapSizeTable &sizeTable = cblc->sizeTables[i]; - const IndexSubtableArray &subtable_array = cblc+sizeTable.indexSubtableArrayOffset; - for (unsigned int j = 0; j < sizeTable.numberOfIndexSubtables; ++j) - { - const IndexSubtableRecord &subtable_record = subtable_array.indexSubtablesZ[j]; - for (unsigned int gid = subtable_record.firstGlyphIndex; - gid <= subtable_record.lastGlyphIndex; ++gid) - { - unsigned int image_offset = 0, image_length = 0, image_format = 0; - - if (!subtable_record.get_image_data (gid, - &image_offset, &image_length, &image_format)) - continue; - - switch (image_format) - { - case 17: { - const GlyphBitmapDataFormat17& glyphFormat17 = - StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset); - callback ((const uint8_t *) &glyphFormat17.data.arrayZ, - glyphFormat17.data.len, i, gid); - } - break; - case 18: { - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset); - callback ((const uint8_t *) &glyphFormat18.data.arrayZ, - glyphFormat18.data.len, i, gid); - } - break; - case 19: { - const GlyphBitmapDataFormat19& glyphFormat19 = - StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset); - callback ((const uint8_t *) &glyphFormat19.data.arrayZ, - glyphFormat19.data.len, i, gid); - } - break; - default: - continue; - } - } - } + unsigned int cbdt_len = cbdt.get_length (); + if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + return hb_blob_get_empty (); + + switch (image_format) + { + case 17: { + if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) + return hb_blob_get_empty (); + const GlyphBitmapDataFormat17& glyphFormat17 = + StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat17::min_size, + glyphFormat17.data.len); + } + case 18: { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return hb_blob_get_empty (); + const GlyphBitmapDataFormat18& glyphFormat18 = + StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat18::min_size, + glyphFormat18.data.len); + } + case 19: { + if (unlikely (image_length < GlyphBitmapDataFormat19::min_size)) + return hb_blob_get_empty (); + const GlyphBitmapDataFormat19& glyphFormat19 = + StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat19::min_size, + glyphFormat19.data.len); + } + } } + + return hb_blob_get_empty (); } + bool has_data () const { return cbdt.get_length (); } + private: - hb_blob_t *cblc_blob; - hb_blob_t *cbdt_blob; - const CBLC *cblc; - const CBDT *cbdt; + hb_blob_ptr_t<CBLC> cblc; + hb_blob_ptr_t<CBDT> cbdt; - unsigned int cbdt_len; unsigned int upem; }; + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version.major == 2 || version.major == 3)); + } protected: - FixedVersion<> version; - HBUINT8 dataZ[VAR]; + FixedVersion<> version; + UnsizedArrayOf<HBUINT8> dataZ; public: DEFINE_SIZE_ARRAY(4, dataZ); }; +struct CBDT_accelerator_t : CBDT::accelerator_t {}; + } /* namespace OT */ #endif /* HB_OT_COLOR_CBDT_TABLE_HH */ diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh index ce6702d..a57911a 100644 --- a/src/hb-ot-color-colr-table.hh +++ b/src/hb-ot-color-colr-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_COLR_TABLE_HH #define HB_OT_COLOR_COLR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * COLR -- Color @@ -39,101 +39,97 @@ namespace OT { struct LayerRecord { - friend struct COLR; - - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - protected: - GlyphID glyphid; /* Glyph ID of layer glyph */ - HBUINT16 colorIdx; /* Index value to use with a selected color palette */ + public: + GlyphID glyphId; /* Glyph ID of layer glyph */ + Index colorIdx; /* Index value to use with a + * selected color palette. + * An index value of 0xFFFF + * is a special case indicating + * that the text foreground + * color (defined by a + * higher-level client) should + * be used and shall not be + * treated as actual index + * into CPAL ColorRecord array. */ public: DEFINE_SIZE_STATIC (4); }; struct BaseGlyphRecord { - friend struct COLR; + int cmp (hb_codepoint_t g) const + { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this))); } - inline int cmp (hb_codepoint_t g) const { - return g < glyphid ? -1 : g > glyphid ? 1 : 0; - } - - protected: - GlyphID glyphid; /* Glyph ID of reference glyph */ - HBUINT16 firstLayerIdx; /* Index to the layer record */ - HBUINT16 numLayers; /* Number of color layers associated with this glyph */ + public: + GlyphID glyphId; /* Glyph ID of reference glyph */ + HBUINT16 firstLayerIdx; /* Index (from beginning of + * the Layer Records) to the + * layer record. There will be + * numLayers consecutive entries + * for this base glyph. */ + HBUINT16 numLayers; /* Number of color layers + * associated with this glyph */ public: DEFINE_SIZE_STATIC (6); }; -static int compare_bgr (const void *pa, const void *pb) -{ - const hb_codepoint_t *a = (const hb_codepoint_t *) pa; - const BaseGlyphRecord *b = (const BaseGlyphRecord *) pb; - return b->cmp (*a); -} - struct COLR { - static const hb_tag_t tableTag = HB_OT_TAG_COLR; + static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && - (this+layersZ).sanitize (c, numLayers))); - } + bool has_data () const { return numBaseGlyphs; } - inline bool get_base_glyph_record (hb_codepoint_t glyph_id, - unsigned int *first_layer /* OUT */, - unsigned int *num_layers /* OUT */) const + unsigned int get_glyph_layers (hb_codepoint_t glyph, + unsigned int start_offset, + unsigned int *count, /* IN/OUT. May be NULL. */ + hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const { - const BaseGlyphRecord* record; - record = (BaseGlyphRecord *) bsearch (&glyph_id, &(this+baseGlyphsZ), numBaseGlyphs, - sizeof (BaseGlyphRecord), compare_bgr); - if (unlikely (!record)) - return false; - - *first_layer = record->firstLayerIdx; - *num_layers = record->numLayers; - return true; - } + const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); - inline bool get_layer_record (unsigned int record, - hb_codepoint_t *glyph_id /* OUT */, - unsigned int *palette_index /* OUT */) const - { - if (unlikely (record >= numLayers)) + hb_array_t<const LayerRecord> all_layers ((this+layersZ).arrayZ, numLayers); + hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, + record.numLayers); + if (count) { - *glyph_id = 0; - *palette_index = 0xFFFF; - return false; + hb_array_t<const LayerRecord> segment_layers = glyph_layers.sub_array (start_offset, *count); + *count = segment_layers.length; + for (unsigned int i = 0; i < segment_layers.length; i++) + { + layers[i].glyph = segment_layers.arrayZ[i].glyphId; + layers[i].color_index = segment_layers.arrayZ[i].colorIdx; + } } - const LayerRecord &layer = (this+layersZ)[record]; - *glyph_id = layer.glyphid; - *palette_index = layer.colorIdx; - return true; + return glyph_layers.length; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && + (this+layersZ).sanitize (c, numLayers))); } protected: - HBUINT16 version; /* Table version number */ - HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records */ - LOffsetTo<UnsizedArrayOf<BaseGlyphRecord> > + HBUINT16 version; /* Table version number (starts at 0). */ + HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ + LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> > baseGlyphsZ; /* Offset to Base Glyph records. */ - LOffsetTo<UnsizedArrayOf<LayerRecord> > - layersZ; /* Offset to Layer Records */ - HBUINT16 numLayers; /* Number of Layer Records */ + LNNOffsetTo<UnsizedArrayOf<LayerRecord> > + layersZ; /* Offset to Layer Records. */ + HBUINT16 numLayers; /* Number of Layer Records. */ public: DEFINE_SIZE_STATIC (14); }; diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh index 2c31274..4070493 100644 --- a/src/hb-ot-color-cpal-table.hh +++ b/src/hb-ot-color-cpal-table.hh @@ -28,54 +28,9 @@ #ifndef HB_OT_COLOR_CPAL_TABLE_HH #define HB_OT_COLOR_CPAL_TABLE_HH -#include "hb-open-type-private.hh" - - -/* - * Following parts to be moved to a public header. - */ - -/** - * hb_ot_color_t: - * ARGB data type for holding color values. - * - * Since: REPLACEME - */ -typedef uint32_t hb_ot_color_t; - - -/** - * hb_ot_color_palette_flags_t: - * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special to note about a color palette. - * @HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND: flag indicating that the color palette is suitable for rendering text on light background. - * @HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND: flag indicating that the color palette is suitable for rendering text on dark background. - * - * Since: REPLACEME - */ -typedef enum { /*< flags >*/ - HB_OT_COLOR_PALETTE_FLAG_DEFAULT = 0x00000000u, - HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND = 0x00000001u, - HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND = 0x00000002u, -} hb_ot_color_palette_flags_t; - -// HB_EXTERN unsigned int -// hb_ot_color_get_palette_count (hb_face_t *face); - -// HB_EXTERN unsigned int -// hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette); - -// HB_EXTERN hb_ot_color_palette_flags_t -// hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette); - -// HB_EXTERN unsigned int -// hb_ot_color_get_palette_colors (hb_face_t *face, -// unsigned int palette, /* default=0 */ -// unsigned int start_offset, -// unsigned int *color_count /* IN/OUT */, -// hb_ot_color_t *colors /* OUT */); - - - +#include "hb-open-type.hh" +#include "hb-ot-color.h" +#include "hb-ot-name.h" /* @@ -92,43 +47,57 @@ struct CPALV1Tail { friend struct CPAL; - inline bool - sanitize (hb_sanitize_context_t *c, const void *base, unsigned int palettes) const + private: + hb_ot_color_palette_flags_t get_palette_flags (const void *base, + unsigned int palette_index, + unsigned int palette_count) const { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - (base+paletteFlagsZ).sanitize (c, palettes) && - (base+paletteLabelZ).sanitize (c, palettes) && - (base+paletteEntryLabelZ).sanitize (c, palettes)); + if (!paletteFlagsZ) return HB_OT_COLOR_PALETTE_FLAG_DEFAULT; + return (hb_ot_color_palette_flags_t) (uint32_t) + (base+paletteFlagsZ).as_array (palette_count)[palette_index]; } - private: - inline hb_ot_color_palette_flags_t - get_palette_flags (const void *base, unsigned int palette) const + hb_ot_name_id_t get_palette_name_id (const void *base, + unsigned int palette_index, + unsigned int palette_count) const { - // range checked at the CPAL caller - return (hb_ot_color_palette_flags_t) (uint32_t) (base+paletteFlagsZ)[palette]; + if (!paletteLabelsZ) return HB_OT_NAME_ID_INVALID; + return (base+paletteLabelsZ).as_array (palette_count)[palette_index]; } - inline unsigned int - get_palette_name_id (const void *base, unsigned int palette) const + hb_ot_name_id_t get_color_name_id (const void *base, + unsigned int color_index, + unsigned int color_count) const { - // range checked at the CPAL caller - return (base+paletteLabelZ)[palette]; + if (!colorLabelsZ) return HB_OT_NAME_ID_INVALID; + return (base+colorLabelsZ).as_array (color_count)[color_index]; + } + + public: + bool sanitize (hb_sanitize_context_t *c, + const void *base, + unsigned int palette_count, + unsigned int color_count) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + (!paletteFlagsZ || (base+paletteFlagsZ).sanitize (c, palette_count)) && + (!paletteLabelsZ || (base+paletteLabelsZ).sanitize (c, palette_count)) && + (!colorLabelsZ || (base+colorLabelsZ).sanitize (c, color_count))); } protected: - LOffsetTo<UnsizedArrayOf<HBUINT32> > + LNNOffsetTo<UnsizedArrayOf<HBUINT32> > paletteFlagsZ; /* Offset from the beginning of CPAL table to * the Palette Type Array. Set to 0 if no array * is provided. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > - paletteLabelZ; /* Offset from the beginning of CPAL table to - * the Palette Labels Array. Set to 0 if no + LNNOffsetTo<UnsizedArrayOf<NameID> > + paletteLabelsZ; /* Offset from the beginning of CPAL table to + * the palette labels array. Set to 0 if no * array is provided. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > - paletteEntryLabelZ; /* Offset from the beginning of CPAL table to - * the Palette Entry Label Array. Set to 0 + LNNOffsetTo<UnsizedArrayOf<NameID> > + colorLabelsZ; /* Offset from the beginning of CPAL table to + * the color labels array. Set to 0 * if no array is provided. */ public: DEFINE_SIZE_STATIC (12); @@ -138,76 +107,76 @@ typedef HBUINT32 BGRAColor; struct CPAL { - static const hb_tag_t tableTag = HB_OT_TAG_CPAL; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!(c->check_struct (this) && // it checks colorRecordIndices also - // see #get_size - (this+colorRecordsZ).sanitize (c, numColorRecords)))) - return_trace (false); - - // Check for indices sanity so no need for doing it runtime - for (unsigned int i = 0; i < numPalettes; ++i) - if (unlikely (colorRecordIndicesZ[i] + numPaletteEntries > numColorRecords)) - return_trace (false); - - // If version is zero, we are done here; otherwise we need to check tail also - if (version == 0) - return_trace (true); - - const CPALV1Tail &v1 = StructAfter<CPALV1Tail> (*this); - return_trace (likely (v1.sanitize (c, this, numPalettes))); - } + bool has_data () const { return numPalettes; } - inline unsigned int get_size (void) const - { - return min_size + numPalettes * sizeof (HBUINT16); - } + unsigned int get_size () const + { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); } - inline hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette) const - { - if (unlikely (version == 0 || palette >= numPalettes)) - return HB_OT_COLOR_PALETTE_FLAG_DEFAULT; + unsigned int get_palette_count () const { return numPalettes; } + unsigned int get_color_count () const { return numColors; } - const CPALV1Tail& cpal1 = StructAfter<CPALV1Tail> (*this); - return cpal1.get_palette_flags (this, palette); - } + hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const + { return v1 ().get_palette_flags (this, palette_index, numPalettes); } - inline unsigned int get_palette_name_id (unsigned int palette) const - { - if (unlikely (version == 0 || palette >= numPalettes)) - return 0xFFFF; + hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const + { return v1 ().get_palette_name_id (this, palette_index, numPalettes); } - const CPALV1Tail& cpal1 = StructAfter<CPALV1Tail> (*this); - return cpal1.get_palette_name_id (this, palette); - } + hb_ot_name_id_t get_color_name_id (unsigned int color_index) const + { return v1 ().get_color_name_id (this, color_index, numColors); } - inline unsigned int get_palette_count () const + unsigned int get_palette_colors (unsigned int palette_index, + unsigned int start_offset, + unsigned int *color_count, /* IN/OUT. May be NULL. */ + hb_color_t *colors /* OUT. May be NULL. */) const { - return numPalettes; + if (unlikely (palette_index >= numPalettes)) + { + if (color_count) *color_count = 0; + return 0; + } + unsigned int start_index = colorRecordIndicesZ[palette_index]; + hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords); + hb_array_t<const BGRAColor> palette_colors = all_colors.sub_array (start_index, + numColors); + if (color_count) + { + hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count); + /* Always return numColors colors per palette even if it has out-of-bounds start index. */ + unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count); + *color_count = count; + for (unsigned int i = 0; i < count; i++) + colors[i] = segment_colors[i]; /* Bound-checked read. */ + } + return numColors; } - inline hb_ot_color_t - get_color_record_argb (unsigned int color_index, unsigned int palette) const + private: + const CPALV1Tail& v1 () const { - if (unlikely (color_index >= numPaletteEntries || palette >= numPalettes)) - return 0; + if (version == 0) return Null(CPALV1Tail); + return StructAfter<CPALV1Tail> (*this); + } - // No need for more range check as it is already done on #sanitize - const UnsizedArrayOf<BGRAColor>& color_records = this+colorRecordsZ; - return color_records[colorRecordIndicesZ[palette] + color_index]; + public: + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + (this+colorRecordsZ).sanitize (c, numColorRecords) && + colorRecordIndicesZ.sanitize (c, numPalettes) && + (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors))); } protected: HBUINT16 version; /* Table version number */ /* Version 0 */ - HBUINT16 numPaletteEntries; /* Number of palette entries in each palette. */ + HBUINT16 numColors; /* Number of colors in each palette. */ HBUINT16 numPalettes; /* Number of palettes in the table. */ HBUINT16 numColorRecords; /* Total number of color records, combined for * all palettes. */ - LOffsetTo<UnsizedArrayOf<BGRAColor> > + LNNOffsetTo<UnsizedArrayOf<BGRAColor> > colorRecordsZ; /* Offset from the beginning of CPAL table to * the first ColorRecord. */ UnsizedArrayOf<HBUINT16> diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 09a9517..f6bdbb3 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_SBIX_TABLE_HH #define HB_OT_COLOR_SBIX_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * sbix -- Standard Bitmap Graphics @@ -62,19 +62,65 @@ struct SBIXGlyph struct SBIXStrike { - friend struct sbix; - - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - imageOffsetsZ.sanitize_shallow (c, c->num_glyphs + 1)); + imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1)); } - protected: + hb_blob_t *get_glyph_blob (unsigned int glyph_id, + hb_blob_t *sbix_blob, + hb_tag_t file_type, + int *x_offset, + int *y_offset, + unsigned int num_glyphs, + unsigned int *strike_ppem) const + { + if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */ + + unsigned int retry_count = 8; + unsigned int sbix_len = sbix_blob->length; + unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data; + assert (strike_offset < sbix_len); + + retry: + if (unlikely (glyph_id >= num_glyphs || + imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] || + imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size || + (unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset)) + return hb_blob_get_empty (); + + unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size; + unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size; + + const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]); + + if (glyph->graphicType == HB_TAG ('d','u','p','e')) + { + if (glyph_length >= 2) + { + glyph_id = *((HBUINT16 *) &glyph->data); + if (retry_count--) + goto retry; + } + return hb_blob_get_empty (); + } + + if (unlikely (file_type != glyph->graphicType)) + return hb_blob_get_empty (); + + if (strike_ppem) *strike_ppem = ppem; + if (x_offset) *x_offset = glyph->xOffset; + if (y_offset) *y_offset = glyph->yOffset; + return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length); + } + + public: HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ HBUINT16 resolution; /* The device pixel density (in PPI) for which this * strike was designed. (E.g., 96 PPI, 192 PPI.) */ + protected: UnsizedArrayOf<LOffsetTo<SBIXGlyph> > imageOffsetsZ; /* Offset from the beginning of the strike data header * to bitmap data for an individual glyph ID. */ @@ -84,70 +130,157 @@ struct SBIXStrike struct sbix { - static const hb_tag_t tableTag = HB_OT_TAG_sbix; + static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && strikes.sanitize (c, this))); - } + bool has_data () const { return version; } + + const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; } struct accelerator_t { - inline void init (hb_face_t *face) + void init (hb_face_t *face) { - num_glyphs = hb_face_get_glyph_count (face); + table = hb_sanitize_context_t().reference_table<sbix> (face); + num_glyphs = face->get_num_glyphs (); + } + void fini () { table.destroy (); } + + bool has_data () const { return table->has_data (); } - OT::Sanitizer<OT::sbix> sanitizer; - sanitizer.set_num_glyphs (num_glyphs); - sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix)); - sbix_len = hb_blob_get_length (sbix_blob); - sbix_table = sbix_blob->as<OT::sbix> (); + bool get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const + { + /* We only support PNG right now, and following function checks type. */ + return get_png_extents (font, glyph, extents); + } + hb_blob_t *reference_png (hb_font_t *font, + hb_codepoint_t glyph_id, + int *x_offset, + int *y_offset, + unsigned int *available_ppem) const + { + return choose_strike (font).get_glyph_blob (glyph_id, table.get_blob (), + HB_TAG ('p','n','g',' '), + x_offset, y_offset, + num_glyphs, available_ppem); } - inline void fini (void) + private: + + const SBIXStrike &choose_strike (hb_font_t *font) const { - hb_blob_destroy (sbix_blob); + unsigned count = table->strikes.len; + if (unlikely (!count)) + return Null(SBIXStrike); + + unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem); + if (!requested_ppem) + requested_ppem = 1<<30; /* Choose largest strike. */ + /* TODO Add DPI sensitivity as well? */ + unsigned int best_i = 0; + unsigned int best_ppem = table->get_strike (0).ppem; + + for (unsigned int i = 1; i < count; i++) + { + unsigned int ppem = (table->get_strike (i)).ppem; + if ((requested_ppem <= ppem && ppem < best_ppem) || + (requested_ppem > best_ppem && ppem > best_ppem)) + { + best_i = i; + best_ppem = ppem; + } + } + + return table->get_strike (best_i); } - inline void dump (void (*callback) (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid)) const + struct PNGHeader { - for (unsigned group = 0; group < sbix_table->strikes.len; ++group) + HBUINT8 signature[8]; + struct { - const SBIXStrike &strike = sbix_table->strikes[group](sbix_table); - for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph) - if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0) - { - const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike); - callback ((const uint8_t*) &sbixGlyph.data, - strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8, - group, glyph); - } + struct + { + HBUINT32 length; + Tag type; + } header; + HBUINT32 width; + HBUINT32 height; + HBUINT8 bitDepth; + HBUINT8 colorType; + HBUINT8 compressionMethod; + HBUINT8 filterMethod; + HBUINT8 interlaceMethod; + } IHDR; + + public: + DEFINE_SIZE_STATIC (29); + }; + + bool get_png_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const + { + /* Following code is safe to call even without data. + * But faster to short-circuit. */ + if (!has_data ()) + return false; + + int x_offset = 0, y_offset = 0; + unsigned int strike_ppem = 0; + hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); + + const PNGHeader &png = *blob->as<PNGHeader>(); + + extents->x_bearing = x_offset; + extents->y_bearing = y_offset; + extents->width = png.IHDR.width; + extents->height = png.IHDR.height; + + /* Convert to font units. */ + if (strike_ppem) + { + double scale = font->face->get_upem () / (double) strike_ppem; + extents->x_bearing = round (extents->x_bearing * scale); + extents->y_bearing = round (extents->y_bearing * scale); + extents->width = round (extents->width * scale); + extents->height = round (extents->height * scale); } + + hb_blob_destroy (blob); + + return strike_ppem; } private: - hb_blob_t *sbix_blob; - const sbix *sbix_table; + hb_blob_ptr_t<sbix> table; - unsigned int sbix_len; unsigned int num_glyphs; - }; + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + version >= 1 && + strikes.sanitize (c, this))); + } + protected: HBUINT16 version; /* Table version number — set to 1 */ HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines. * Bits 2 to 15: reserved (set to 0). */ - LArrayOf<LOffsetTo<SBIXStrike> > + LOffsetLArrayOf<SBIXStrike> strikes; /* Offsets from the beginning of the 'sbix' * table to data for each individual bitmap strike. */ public: DEFINE_SIZE_ARRAY (8, strikes); }; +struct sbix_accelerator_t : sbix::accelerator_t {}; + } /* namespace OT */ #endif /* HB_OT_COLOR_SBIX_TABLE_HH */ diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh index ed6cf97..6e8eddf 100644 --- a/src/hb-ot-color-svg-table.hh +++ b/src/hb-ot-color-svg-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_SVG_TABLE_HH #define HB_OT_COLOR_SVG_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * SVG -- SVG (Scalable Vector Graphics) @@ -40,13 +40,21 @@ namespace OT { struct SVGDocumentIndexEntry { - friend struct SVG; + int cmp (hb_codepoint_t g) const + { return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; } - inline bool sanitize (hb_sanitize_context_t *c, const void* base) const + hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const + { + return hb_blob_create_sub_blob (svg_blob, + index_offset + (unsigned int) svgDoc, + svgDocLength); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - (base+svgDoc).sanitize (c, svgDocLength)); + svgDoc.sanitize (c, base, svgDocLength)); } protected: @@ -54,91 +62,62 @@ struct SVGDocumentIndexEntry * this index entry. */ HBUINT16 endGlyphID; /* The last glyph ID in the range described by * this index entry. Must be >= startGlyphID. */ - LOffsetTo<UnsizedArrayOf<HBUINT8> > + LNNOffsetTo<UnsizedArrayOf<HBUINT8> > svgDoc; /* Offset from the beginning of the SVG Document Index * to an SVG document. Must be non-zero. */ - HBUINT32 svgDocLength; /* Length of the SVG document. + HBUINT32 svgDocLength; /* Length of the SVG document. * Must be non-zero. */ public: DEFINE_SIZE_STATIC (12); }; -struct SVGDocumentIndex -{ - friend struct SVG; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - entries.sanitize (c, this)); - } - - protected: - ArrayOf<SVGDocumentIndexEntry> - entries; /* Array of SVG Document Index Entries. */ - public: - DEFINE_SIZE_ARRAY (2, entries); -}; - struct SVG { - static const hb_tag_t tableTag = HB_OT_TAG_SVG; + static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (this+svgDocIndex).sanitize (c))); - } + bool has_data () const { return svgDocEntries; } struct accelerator_t { - inline void init (hb_face_t *face) - { - OT::Sanitizer<OT::SVG> sanitizer; - svg_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SVG)); - svg_len = hb_blob_get_length (svg_blob); - svg = svg_blob->as<OT::SVG> (); - - } + void init (hb_face_t *face) + { table = hb_sanitize_context_t().reference_table<SVG> (face); } + void fini () { table.destroy (); } - inline void fini (void) + hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const { - hb_blob_destroy (svg_blob); + return table->get_glyph_entry (glyph_id).reference_blob (table.get_blob (), + table->svgDocEntries); } - inline void - dump (void (*callback) (const uint8_t* data, unsigned int length, - unsigned int start_glyph, unsigned int end_glyph)) const - { - const SVGDocumentIndex &index = svg+svg->svgDocIndex; - const ArrayOf<SVGDocumentIndexEntry> &entries = index.entries; - for (unsigned int i = 0; i < entries.len; ++i) - { - const SVGDocumentIndexEntry &entry = entries[i]; - callback ((const uint8_t*) &entry.svgDoc (&index), entry.svgDocLength, - entry.startGlyphID, entry.endGlyphID); - } - } + bool has_data () const { return table->has_data (); } private: - hb_blob_t *svg_blob; - const SVG *svg; - - unsigned int svg_len; + hb_blob_ptr_t<SVG> table; }; + const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const + { return (this+svgDocEntries).bsearch (glyph_id); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (this+svgDocEntries).sanitize_shallow (c))); + } + protected: HBUINT16 version; /* Table version (starting at 0). */ - LOffsetTo<SVGDocumentIndex> - svgDocIndex; /* Offset (relative to the start of the SVG table) to the + LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> > + svgDocEntries; /* Offset (relative to the start of the SVG table) to the * SVG Documents Index. Must be non-zero. */ + /* Array of SVG Document Index Entries. */ HBUINT32 reserved; /* Set to 0. */ public: DEFINE_SIZE_STATIC (10); }; +struct SVG_accelerator_t : SVG::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 86171c6..791135b 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -22,162 +22,278 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Sascha Brawer + * Google Author(s): Sascha Brawer, Behdad Esfahbod */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-colr-table.hh" #include "hb-ot-color-cpal-table.hh" +#include "hb-ot-color-sbix-table.hh" +#include "hb-ot-color-svg-table.hh" +#include "hb-ot-face.hh" #include "hb-ot.h" #include <stdlib.h> #include <string.h> -#include "hb-ot-layout-private.hh" -#include "hb-shaper-private.hh" +#include "hb-ot-layout.hh" -#if 0 -HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t) -//HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) Hmm? +/** + * SECTION:hb-ot-color + * @title: hb-ot-color + * @short_description: OpenType Color Fonts + * @include: hb-ot.h + * + * Functions for fetching color-font information from OpenType font faces. + **/ + + +/* + * CPAL + */ -static inline const OT::COLR& -_get_colr (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->colr.get ()); -} -static inline const OT::CPAL& -_get_cpal (hb_face_t *face) +/** + * hb_ot_color_has_palettes: + * @face: a font face. + * + * Returns: whether CPAL table is available. + * + * Since: 2.1.0 + */ +hb_bool_t +hb_ot_color_has_palettes (hb_face_t *face) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->cpal.get ()); + return face->table.CPAL->has_data (); } - /** - * hb_ot_color_get_palette_count: + * hb_ot_color_palette_get_count: * @face: a font face. * * Returns: the number of color palettes in @face, or zero if @face has * no colors. * - * Since: REPLACEME + * Since: 2.1.0 */ unsigned int -hb_ot_color_get_palette_count (hb_face_t *face) +hb_ot_color_palette_get_count (hb_face_t *face) { - const OT::CPAL& cpal = _get_cpal (face); - return cpal.get_palette_count (); + return face->table.CPAL->get_palette_count (); } - /** - * hb_ot_color_get_palette_name_id: - * @face: a font face. - * @palette: the index of the color palette whose name is being requested. + * hb_ot_color_palette_get_name_id: + * @face: a font face. + * @palette_index: the index of the color palette whose name is being requested. * * Retrieves the name id of a color palette. For example, a color font can * have themed palettes like "Spring", "Summer", "Fall", and "Winter". * * Returns: an identifier within @face's `name` table. - * If the requested palette has no name, or if @face has no colors, - * or if @palette is not between 0 and hb_ot_color_get_palette_count(), - * the result is 0xFFFF. The implementation does not check whether - * the returned palette name id is actually in @face's `name` table. + * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID. * - * Since: REPLACEME + * Since: 2.1.0 */ -unsigned int -hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette) +hb_ot_name_id_t +hb_ot_color_palette_get_name_id (hb_face_t *face, + unsigned int palette_index) { - const OT::CPAL& cpal = _get_cpal (face); - return cpal.get_palette_name_id (palette); + return face->table.CPAL->get_palette_name_id (palette_index); } +/** + * hb_ot_color_palette_color_get_name_id: + * @face: a font face. + * @color_index: palette entry index. + * + * Returns: Name ID associated with a palette entry, e.g. eye color + * + * Since: 2.1.0 + */ +hb_ot_name_id_t +hb_ot_color_palette_color_get_name_id (hb_face_t *face, + unsigned int color_index) +{ + return face->table.CPAL->get_color_name_id (color_index); +} /** - * hb_ot_color_get_palette_flags: - * @face: a font face - * @palette: the index of the color palette whose flags are being requested + * hb_ot_color_palette_get_flags: + * @face: a font face + * @palette_index: the index of the color palette whose flags are being requested * - * Returns: the flags for the requested color palette. If @face has no colors, - * or if @palette is not between 0 and hb_ot_color_get_palette_count(), - * the result is #HB_OT_COLOR_PALETTE_FLAG_DEFAULT. + * Returns: the flags for the requested color palette. * - * Since: REPLACEME + * Since: 2.1.0 */ hb_ot_color_palette_flags_t -hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette) +hb_ot_color_palette_get_flags (hb_face_t *face, + unsigned int palette_index) { - const OT::CPAL& cpal = _get_cpal(face); - return cpal.get_palette_flags (palette); + return face->table.CPAL->get_palette_flags (palette_index); } - /** - * hb_ot_color_get_palette_colors: + * hb_ot_color_palette_get_colors: * @face: a font face. - * @palette: the index of the color palette whose colors + * @palette_index:the index of the color palette whose colors * are being requested. * @start_offset: the index of the first color being requested. * @color_count: (inout) (optional): on input, how many colors * can be maximally stored into the @colors array; * on output, how many colors were actually stored. - * @colors: (array length=color_count) (optional): - * an array of #hb_ot_color_t records. After calling + * @colors: (array length=color_count) (out) (optional): + * an array of #hb_color_t records. After calling * this function, @colors will be filled with * the palette colors. If @colors is NULL, the function * will just return the number of total colors * without storing any actual colors; this can be used * for allocating a buffer of suitable size before calling - * hb_ot_color_get_palette_colors() a second time. + * hb_ot_color_palette_get_colors() a second time. * * Retrieves the colors in a color palette. * - * Returns: the total number of colors in the palette. All palettes in - * a font have the same number of colors. If @face has no colors, or if - * @palette is not between 0 and hb_ot_color_get_palette_count(), - * the result is zero. + * Returns: the total number of colors in the palette. + * + * Since: 2.1.0 + */ +unsigned int +hb_ot_color_palette_get_colors (hb_face_t *face, + unsigned int palette_index, + unsigned int start_offset, + unsigned int *colors_count /* IN/OUT. May be NULL. */, + hb_color_t *colors /* OUT. May be NULL. */) +{ + return face->table.CPAL->get_palette_colors (palette_index, start_offset, colors_count, colors); +} + + +/* + * COLR + */ + +/** + * hb_ot_color_has_layers: + * @face: a font face. + * + * Returns: whether COLR table is available. + * + * Since: 2.1.0 + */ +hb_bool_t +hb_ot_color_has_layers (hb_face_t *face) +{ + return face->table.COLR->has_data (); +} + +/** + * hb_ot_color_glyph_get_layers: + * @face: a font face. + * @glyph: a layered color glyph id. + * @start_offset: starting offset of layers. + * @count: (inout) (optional): gets number of layers available to be written on buffer + * and returns number of written layers. + * @layers: (array length=count) (out) (optional): layers buffer to buffer. + * + * Returns: Total number of layers a layered color glyph have. * - * Since: REPLACEME + * Since: 2.1.0 */ unsigned int -hb_ot_color_get_palette_colors (hb_face_t *face, - unsigned int palette, /* default=0 */ - unsigned int start_offset, - unsigned int *color_count /* IN/OUT */, - hb_ot_color_t *colors /* OUT */) +hb_ot_color_glyph_get_layers (hb_face_t *face, + hb_codepoint_t glyph, + unsigned int start_offset, + unsigned int *count, /* IN/OUT. May be NULL. */ + hb_ot_color_layer_t *layers /* OUT. May be NULL. */) { - const OT::CPAL& cpal = _get_cpal(face); - if (unlikely (palette >= cpal.numPalettes)) - { - if (color_count) *color_count = 0; - return 0; - } - - const OT::ColorRecord* crec = &cpal.offsetFirstColorRecord (&cpal); - crec += cpal.colorRecordIndices[palette]; - - unsigned int num_results = 0; - if (likely (color_count && colors)) - { - for (unsigned int i = start_offset; - i < cpal.numPaletteEntries && num_results < *color_count; ++i) - { - hb_ot_color_t* result = &colors[num_results]; - result->red = crec[i].red; - result->green = crec[i].green; - result->blue = crec[i].blue; - result->alpha = crec[i].alpha; - ++num_results; - } - } - - if (likely (color_count)) *color_count = num_results; - return cpal.numPaletteEntries; + return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers); +} + + +/* + * SVG + */ + +/** + * hb_ot_color_has_svg: + * @face: a font face. + * + * Check whether @face has SVG glyph images. + * + * Returns true if available, false otherwise. + * + * Since: 2.1.0 + */ +hb_bool_t +hb_ot_color_has_svg (hb_face_t *face) +{ + return face->table.SVG->has_data (); +} + +/** + * hb_ot_color_glyph_reference_svg: + * @face: a font face. + * @glyph: a svg glyph index. + * + * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded. + * + * Returns: (transfer full): respective svg blob of the glyph, if available. + * + * Since: 2.1.0 + */ +hb_blob_t * +hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) +{ + return face->table.SVG->reference_blob_for_glyph (glyph); +} + + +/* + * PNG: CBDT or sbix + */ + +/** + * hb_ot_color_has_png: + * @face: a font face. + * + * Check whether @face has PNG glyph images (either CBDT or sbix tables). + * + * Returns true if available, false otherwise. + * + * Since: 2.1.0 + */ +hb_bool_t +hb_ot_color_has_png (hb_face_t *face) +{ + return face->table.CBDT->has_data () || face->table.sbix->has_data (); +} + +/** + * hb_ot_color_glyph_reference_png: + * @font: a font object, not face. upem should be set on + * that font object if one wants to get optimal png blob, otherwise + * return the biggest one + * @glyph: a glyph index. + * + * Get PNG image for a glyph. + * + * Returns: (transfer full): respective PNG blob of the glyph, if available. + * + * Since: 2.1.0 + */ +hb_blob_t * +hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph) +{ + hb_blob_t *blob = hb_blob_get_empty (); + + if (font->face->table.sbix->has_data ()) + blob = font->face->table.sbix->reference_png (font, glyph, nullptr, nullptr, nullptr); + + if (!blob->length && font->face->table.CBDT->has_data ()) + blob = font->face->table.CBDT->reference_png (font, glyph); + + return blob; } -#endif diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h new file mode 100644 index 0000000..49646bf --- /dev/null +++ b/src/hb-ot-color.h @@ -0,0 +1,139 @@ +/* + * Copyright © 2016 Google, Inc. + * Copyright © 2018 Khaled Hosny + * Copyright © 2018 Ebrahim Byagowi + * + * 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): Sascha Brawer, Behdad Esfahbod + */ + +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + +#ifndef HB_OT_COLOR_H +#define HB_OT_COLOR_H + +#include "hb.h" +#include "hb-ot-name.h" + +HB_BEGIN_DECLS + + +/* + * Color palettes. + */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_palettes (hb_face_t *face); + +HB_EXTERN unsigned int +hb_ot_color_palette_get_count (hb_face_t *face); + +HB_EXTERN hb_ot_name_id_t +hb_ot_color_palette_get_name_id (hb_face_t *face, + unsigned int palette_index); + +HB_EXTERN hb_ot_name_id_t +hb_ot_color_palette_color_get_name_id (hb_face_t *face, + unsigned int color_index); + +/** + * hb_ot_color_palette_flags_t: + * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special + * to note about a color palette. + * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color + * palette is appropriate to use when displaying the font on a light background such as white. + * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color + * palette is appropriate to use when displaying the font on a dark background such as black. + * + * Since: 2.1.0 + */ +typedef enum { /*< flags >*/ + HB_OT_COLOR_PALETTE_FLAG_DEFAULT = 0x00000000u, + HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND = 0x00000001u, + HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND = 0x00000002u +} hb_ot_color_palette_flags_t; + +HB_EXTERN hb_ot_color_palette_flags_t +hb_ot_color_palette_get_flags (hb_face_t *face, + unsigned int palette_index); + +HB_EXTERN unsigned int +hb_ot_color_palette_get_colors (hb_face_t *face, + unsigned int palette_index, + unsigned int start_offset, + unsigned int *color_count, /* IN/OUT. May be NULL. */ + hb_color_t *colors /* OUT. May be NULL. */); + + +/* + * Color layers. + */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_layers (hb_face_t *face); + +/** + * hb_ot_color_layer_t: + * + * Pairs of glyph and color index. + * + * Since: 2.1.0 + **/ +typedef struct hb_ot_color_layer_t +{ + hb_codepoint_t glyph; + unsigned int color_index; +} hb_ot_color_layer_t; + +HB_EXTERN unsigned int +hb_ot_color_glyph_get_layers (hb_face_t *face, + hb_codepoint_t glyph, + unsigned int start_offset, + unsigned int *count, /* IN/OUT. May be NULL. */ + hb_ot_color_layer_t *layers /* OUT. May be NULL. */); + +/* + * SVG + */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_svg (hb_face_t *face); + +HB_EXTERN hb_blob_t * +hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph); + +/* + * PNG: CBDT or sbix + */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_png (hb_face_t *face); + +HB_EXTERN hb_blob_t * +hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph); + + +HB_END_DECLS + +#endif /* HB_OT_COLOR_H */ diff --git a/src/hb-ot-deprecated.h b/src/hb-ot-deprecated.h new file mode 100644 index 0000000..bce51b7 --- /dev/null +++ b/src/hb-ot-deprecated.h @@ -0,0 +1,107 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + +#ifndef HB_OT_DEPRECATED_H +#define HB_OT_DEPRECATED_H + +#include "hb.h" +#include "hb-ot-name.h" + + +HB_BEGIN_DECLS + +#ifndef HB_DISABLE_DEPRECATED + + +/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t +hb_ot_layout_table_choose_script (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *script_tags, + unsigned int *script_index, + hb_tag_t *chosen_script); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t +hb_ot_layout_script_find_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + hb_tag_t language_tag, + unsigned int *language_index); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t +hb_ot_tag_from_language (hb_language_t language); + + +/** + * HB_OT_VAR_NO_AXIS_INDEX: + * + * Since: 1.4.2 + * Deprecated: 2.2.0 + */ +#define HB_OT_VAR_NO_AXIS_INDEX 0xFFFFFFFFu + +/** + * hb_ot_var_axis_t: + * + * Since: 1.4.2 + * Deprecated: 2.2.0 + */ +typedef struct hb_ot_var_axis_t +{ + hb_tag_t tag; + hb_ot_name_id_t name_id; + float min_value; + float default_value; + float max_value; +} hb_ot_var_axis_t; + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int +hb_ot_var_get_axes (hb_face_t *face, + unsigned int start_offset, + unsigned int *axes_count /* IN/OUT */, + hb_ot_var_axis_t *axes_array /* OUT */); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t +hb_ot_var_find_axis (hb_face_t *face, + hb_tag_t axis_tag, + unsigned int *axis_index, + hb_ot_var_axis_t *axis_info); + + +#endif + +HB_END_DECLS + +#endif /* HB_OT_DEPRECATED_H */ diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc new file mode 100644 index 0000000..9b17526 --- /dev/null +++ b/src/hb-ot-face.cc @@ -0,0 +1,61 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#include "hb-ot-face.hh" + +#include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-kern-table.hh" +#include "hb-ot-name-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-color-cbdt-table.hh" +#include "hb-ot-color-sbix-table.hh" +#include "hb-ot-color-svg-table.hh" +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" + + +void hb_ot_face_t::init0 (hb_face_t *face) +{ + this->face = face; +#define HB_OT_TABLE(Namespace, Type) Type.init0 (); +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +} +void hb_ot_face_t::fini () +{ +#define HB_OT_TABLE(Namespace, Type) Type.fini (); +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +} diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh new file mode 100644 index 0000000..7f47ba6 --- /dev/null +++ b/src/hb-ot-face.hh @@ -0,0 +1,120 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2012,2013 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_FACE_HH +#define HB_OT_FACE_HH + +#include "hb.hh" + +#include "hb-machinery.hh" + + +/* + * hb_ot_face_t + */ + +#define HB_OT_TABLES \ + /* OpenType fundamentals. */ \ + HB_OT_TABLE(OT, head) \ + HB_OT_ACCELERATOR(OT, cmap) \ + HB_OT_ACCELERATOR(OT, hmtx) \ + HB_OT_ACCELERATOR(OT, vmtx) \ + HB_OT_ACCELERATOR(OT, post) \ + HB_OT_TABLE(OT, kern) \ + HB_OT_ACCELERATOR(OT, glyf) \ + HB_OT_ACCELERATOR(OT, cff1) \ + HB_OT_ACCELERATOR(OT, cff2) \ + HB_OT_TABLE(OT, VORG) \ + HB_OT_ACCELERATOR(OT, name) \ + HB_OT_TABLE(OT, OS2) \ + HB_OT_TABLE(OT, STAT) \ + /* OpenType shaping. */ \ + HB_OT_ACCELERATOR(OT, GDEF) \ + HB_OT_ACCELERATOR(OT, GSUB) \ + HB_OT_ACCELERATOR(OT, GPOS) \ + HB_OT_TABLE(OT, BASE) \ + HB_OT_TABLE(OT, JSTF) \ + /* AAT shaping. */ \ + HB_OT_TABLE(AAT, mort) \ + HB_OT_TABLE(AAT, morx) \ + HB_OT_TABLE(AAT, kerx) \ + HB_OT_TABLE(AAT, ankr) \ + HB_OT_TABLE(AAT, trak) \ + HB_OT_TABLE(AAT, lcar) \ + HB_OT_TABLE(AAT, ltag) \ + HB_OT_TABLE(AAT, feat) \ + /* OpenType variations. */ \ + HB_OT_TABLE(OT, fvar) \ + HB_OT_TABLE(OT, avar) \ + HB_OT_TABLE(OT, MVAR) \ + /* OpenType math. */ \ + HB_OT_TABLE(OT, MATH) \ + /* OpenType color fonts. */ \ + HB_OT_TABLE(OT, COLR) \ + HB_OT_TABLE(OT, CPAL) \ + HB_OT_ACCELERATOR(OT, CBDT) \ + HB_OT_ACCELERATOR(OT, sbix) \ + HB_OT_ACCELERATOR(OT, SVG) \ + /* */ + +/* Declare tables. */ +#define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; } +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t) +HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE + +struct hb_ot_face_t +{ + HB_INTERNAL void init0 (hb_face_t *face); + HB_INTERNAL void fini (); + +#define HB_OT_TABLE_ORDER(Namespace, Type) \ + HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type))) + enum order_t + { + ORDER_ZERO, +#define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type), +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE + }; + + hb_face_t *face; /* MUST be JUST before the lazy loaders. */ +#define HB_OT_TABLE(Namespace, Type) \ + hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type; +#define HB_OT_ACCELERATOR(Namespace, Type) \ + hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type; + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +}; + + +#endif /* HB_OT_FACE_HH */ diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 8310230..20b09df 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -24,67 +24,38 @@ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-ot.h" -#include "hb-font-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" +#include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-kern-table.hh" +#include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" - +#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-vorg-table.hh" #include "hb-ot-color-cbdt-table.hh" +#include "hb-ot-color-sbix-table.hh" -struct hb_ot_font_t -{ - OT::cmap::accelerator_t cmap; - OT::hmtx::accelerator_t h_metrics; - OT::vmtx::accelerator_t v_metrics; - OT::hb_lazy_loader_t<OT::glyf::accelerator_t> glyf; - OT::hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt; - OT::hb_lazy_loader_t<OT::post::accelerator_t> post; - OT::hb_lazy_loader_t<OT::kern::accelerator_t> kern; -}; - - -static hb_ot_font_t * -_hb_ot_font_create (hb_face_t *face) -{ - hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); - - if (unlikely (!ot_font)) - return nullptr; - - ot_font->cmap.init (face); - ot_font->h_metrics.init (face); - ot_font->v_metrics.init (face, ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */ - ot_font->glyf.init (face); - ot_font->cbdt.init (face); - ot_font->post.init (face); - ot_font->kern.init (face); - - return ot_font; -} - -static void -_hb_ot_font_destroy (void *data) -{ - hb_ot_font_t *ot_font = (hb_ot_font_t *) data; - - ot_font->cmap.fini (); - ot_font->h_metrics.fini (); - ot_font->v_metrics.fini (); - ot_font->glyf.fini (); - ot_font->cbdt.fini (); - ot_font->post.fini (); - ot_font->kern.fini (); - - free (ot_font); -} +/** + * SECTION:hb-ot-font + * @title: hb-ot-font + * @short_description: OpenType font implementation + * @include: hb-ot.h + * + * Functions for using OpenType fonts with hb_shape(). Not that fonts returned + * by hb_font_create() default to using these functions, so most clients would + * never need to call these functions directly. + **/ static hb_bool_t @@ -93,10 +64,25 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data HB_UNUSED) +{ + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + return ot_face->cmap->get_nominal_glyph (unicode, glyph); +} +static unsigned int +hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, + void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->cmap.get_nominal_glyph (unicode, glyph); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + return ot_face->cmap->get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); } static hb_bool_t @@ -107,39 +93,83 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph); } -static hb_position_t -hb_ot_get_glyph_h_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font)); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; + + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font)); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } } -static hb_position_t -hb_ot_get_glyph_v_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font)); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } } -static hb_position_t -hb_ot_get_glyph_h_kerning (hb_font_t *font, - void *font_data, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, - void *user_data HB_UNUSED) +static hb_bool_t +hb_ot_get_glyph_v_origin (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph)); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + + *x = font->get_glyph_h_advance (glyph) / 2; + + const OT::VORG &VORG = *ot_face->VORG; + if (VORG.has_data ()) + { + *y = font->em_scale_y (VORG.get_y_origin (glyph)); + return true; + } + + hb_glyph_extents_t extents = {0}; + if (ot_face->glyf->get_extents (glyph, &extents)) + { + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + hb_position_t tsb = vmtx.get_side_bearing (glyph); + *y = font->em_scale_y (extents.y_bearing + tsb); + return true; + } + + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + *y = font_extents.ascender; + + return true; } static hb_bool_t @@ -149,10 +179,16 @@ hb_ot_get_glyph_extents (hb_font_t *font, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - bool ret = ot_font->glyf->get_extents (glyph, extents); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + bool ret = ot_face->sbix->get_extents (font, glyph, extents); + if (!ret) + ret = ot_face->glyf->get_extents (glyph, extents); + if (!ret) + ret = ot_face->cff1->get_extents (glyph, extents); + if (!ret) + ret = ot_face->cff2->get_extents (font, glyph, extents); if (!ret) - ret = ot_font->cbdt->get_extents (glyph, extents); + ret = ot_face->CBDT->get_extents (font, glyph, extents); // TODO Hook up side-bearings variations. extents->x_bearing = font->em_scale_x (extents->x_bearing); extents->y_bearing = font->em_scale_y (extents->y_bearing); @@ -168,8 +204,8 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, char *name, unsigned int size, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->post->get_glyph_name (glyph, name, size); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + return ot_face->post->get_glyph_name (glyph, name, size); } static hb_bool_t @@ -179,8 +215,8 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->post->get_glyph_from_name (name, len, glyph); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + return ot_face->post->get_glyph_from_name (name, len, glyph); } static hb_bool_t @@ -189,12 +225,13 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); - metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); - metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; + metrics->ascender = font->em_scale_y (hmtx.ascender); + metrics->descender = font->em_scale_y (hmtx.descender); + metrics->line_gap = font->em_scale_y (hmtx.line_gap); // TODO Hook up variations. - return ot_font->h_metrics.has_font_extents; + return hmtx.has_font_extents; } static hb_bool_t @@ -203,49 +240,34 @@ hb_ot_get_font_v_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); - metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); - metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); + const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + metrics->ascender = font->em_scale_x (vmtx.ascender); + metrics->descender = font->em_scale_x (vmtx.descender); + metrics->line_gap = font->em_scale_x (vmtx.line_gap); // TODO Hook up variations. - return ot_font->v_metrics.has_font_extents; + return vmtx.has_font_extents; } -static hb_font_funcs_t *static_ot_funcs = nullptr; - -#ifdef HB_USE_ATEXIT -static -void free_static_ot_funcs (void) -{ -retry: - hb_font_funcs_t *ot_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, ot_funcs, nullptr)) - goto retry; - - hb_font_funcs_destroy (ot_funcs); -} +#if HB_USE_ATEXIT +static void free_static_ot_funcs (); #endif -static hb_font_funcs_t * -_hb_ot_get_font_funcs (void) +static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t> { -retry: - hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); - - if (unlikely (!funcs)) + static hb_font_funcs_t *create () { - funcs = hb_font_funcs_create (); + hb_font_funcs_t *funcs = hb_font_funcs_create (); hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr); - //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr); - //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr); + hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); @@ -253,17 +275,26 @@ retry: hb_font_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) { - hb_font_funcs_destroy (funcs); - goto retry; - } +#if HB_USE_ATEXIT + atexit (free_static_ot_funcs); +#endif -#ifdef HB_USE_ATEXIT - atexit (free_static_ot_funcs); /* First person registers atexit() callback. */ + return funcs; + } +} static_ot_funcs; + +#if HB_USE_ATEXIT +static +void free_static_ot_funcs () +{ + static_ot_funcs.free_instance (); +} #endif - }; - return funcs; +static hb_font_funcs_t * +_hb_ot_get_font_funcs () +{ + return static_ot_funcs.get_unconst (); } @@ -275,12 +306,8 @@ retry: void hb_ot_font_set_funcs (hb_font_t *font) { - hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); - if (unlikely (!ot_font)) - return; - hb_font_set_funcs (font, _hb_ot_get_font_funcs (), - ot_font, - _hb_ot_font_destroy); + &font->face->table, + nullptr); } diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh new file mode 100644 index 0000000..94fff58 --- /dev/null +++ b/src/hb-ot-gasp-table.hh @@ -0,0 +1,84 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#ifndef HB_OT_GASP_TABLE_HH +#define HB_OT_GASP_TABLE_HH + +#include "hb-open-type.hh" +#include "hb-ot-hhea-table.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-var-hvar-table.hh" + +/* + * gasp -- Grid-fitting and Scan-conversion Procedure + * https://docs.microsoft.com/en-us/typography/opentype/spec/gasp + */ +#define HB_OT_TAG_gasp HB_TAG('g','a','s','p') + + +namespace OT { + +struct GaspRange +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT16 rangeMaxPPEM; /* Upper limit of range, in PPEM */ + HBUINT16 rangeGaspBehavior; + /* Flags describing desired rasterizer behavior. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct gasp +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_gasp; + + const GaspRange &get_gasp_range (unsigned int i) const + { return gaspRanges[i]; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + gaspRanges.sanitize (c)); + } + + protected: + HBUINT16 version; /* Version number (set to 1) */ + ArrayOf<GaspRange> + gaspRanges; /* Number of records to follow + * Sorted by ppem */ + public: + DEFINE_SIZE_ARRAY (4, gaspRanges); +}; + +} /* namespace OT */ + + +#endif /* HB_OT_GASP_TABLE_HH */ diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 89c867d..c2b38b0 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -27,11 +27,9 @@ #ifndef HB_OT_GLYF_TABLE_HH #define HB_OT_GLYF_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-head-table.hh" #include "hb-subset-glyf.hh" -#include "hb-subset-plan.hh" -#include "hb-subset-private.hh" namespace OT { @@ -47,17 +45,20 @@ struct loca { friend struct glyf; - static const hb_tag_t tableTag = HB_OT_TAG_loca; + static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); return_trace (true); } protected: - HBUINT8 dataZ[VAR]; /* Location data. */ - DEFINE_SIZE_ARRAY (0, dataZ); + UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */ + public: + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it MIN() instead. */ }; @@ -70,9 +71,9 @@ struct loca struct glyf { - static const hb_tag_t tableTag = HB_OT_TAG_glyf; + static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); /* We don't check for anything specific here. The users of the @@ -80,7 +81,7 @@ struct glyf return_trace (true); } - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { hb_blob_t *glyf_prime = nullptr; hb_blob_t *loca_prime = nullptr; @@ -103,14 +104,14 @@ struct glyf static bool _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) { - hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_head)); + hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); hb_blob_destroy (head_blob); if (unlikely (!head_prime_blob)) return false; - OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr); + head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1); bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); @@ -121,9 +122,9 @@ struct glyf struct GlyphHeader { HBINT16 numberOfContours; /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ FWORD xMin; /* Minimum x for coordinate data. */ FWORD yMin; /* Minimum y for coordinate data. */ FWORD xMax; /* Maximum x for coordinate data. */ @@ -150,28 +151,23 @@ struct glyf }; HBUINT16 flags; - HBUINT16 glyphIndex; + GlyphID glyphIndex; - inline unsigned int get_size (void) const + unsigned int get_size () const { unsigned int size = min_size; - if (flags & ARG_1_AND_2_ARE_WORDS) { - // arg1 and 2 are int16 - size += 4; - } else { - // arg1 and 2 are int8 - size += 2; - } - if (flags & WE_HAVE_A_SCALE) { - // One x 16 bit (scale) - size += 2; - } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { - // Two x 16 bit (xscale, yscale) - size += 4; - } else if (flags & WE_HAVE_A_TWO_BY_TWO) { - // Four x 16 bit (xscale, scale01, scale10, yscale) - size += 8; - } + // arg1 and 2 are int16 + if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; + // arg1 and 2 are int8 + else size += 2; + + // One x 16 bit (scale) + if (flags & WE_HAVE_A_SCALE) size += 2; + // Two x 16 bit (xscale, yscale) + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; + // Four x 16 bit (xscale, scale01, scale10, yscale) + else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; + return size; } @@ -181,7 +177,7 @@ struct glyf const char *glyph_end; const CompositeGlyphHeader *current; - inline bool move_to_next () + bool move_to_next () { if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) { @@ -195,17 +191,17 @@ struct glyf return false; } - inline bool in_range (const CompositeGlyphHeader *composite) const + bool in_range (const CompositeGlyphHeader *composite) const { return (const char *) composite >= glyph_start && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end - && ((const char *) composite + composite->get_size()) <= glyph_end; + && ((const char *) composite + composite->get_size ()) <= glyph_end; } }; - static inline bool get_iterator (const char * glyph_data, - unsigned int length, - CompositeGlyphHeader::Iterator *iterator /* OUT */) + static bool get_iterator (const char * glyph_data, + unsigned int length, + CompositeGlyphHeader::Iterator *iterator /* OUT */) { if (length < GlyphHeader::static_size) return false; /* Empty glyph; zero extents. */ @@ -213,15 +209,15 @@ struct glyf const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0); if (glyph_header.numberOfContours < 0) { - const CompositeGlyphHeader *possible = + const CompositeGlyphHeader *possible = &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); iterator->glyph_start = glyph_data; iterator->glyph_end = (const char *) glyph_data + length; if (!iterator->in_range (possible)) - return false; - iterator->current = possible; - return true; + return false; + iterator->current = possible; + return true; } return false; @@ -232,34 +228,26 @@ struct glyf struct accelerator_t { - inline void init (hb_face_t *face) + void init (hb_face_t *face) { memset (this, 0, sizeof (accelerator_t)); - hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head)); - const head *head_table = head_blob->as<head> (); - if (head_table == &Null(head) || (unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0) - { - /* head table is not present, or in an unknown format. Leave num_glyphs=0, that takes care of disabling us. */ - hb_blob_destroy (head_blob); + const OT::head &head = *face->table.head; + if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) + /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; - } - short_offset = 0 == head_table->indexToLocFormat; - hb_blob_destroy (head_blob); + short_offset = 0 == head.indexToLocFormat; - loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca)); - loca_table = loca_blob->as<loca> (); - glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf)); - glyf_table = glyf_blob->as<glyf> (); + loca_table = hb_sanitize_context_t ().reference_table<loca> (face); + glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); - num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1; - glyf_len = hb_blob_get_length (glyf_blob); + num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; } - inline void fini (void) + void fini () { - hb_blob_destroy (loca_blob); - hb_blob_destroy (glyf_blob); + loca_table.destroy (); + glyf_table.destroy (); } /* @@ -267,35 +255,37 @@ struct glyf * If true is returned a pointer to the composite glyph will be written into * composite. */ - inline bool get_composite (hb_codepoint_t glyph, - CompositeGlyphHeader::Iterator *composite /* OUT */) const + bool get_composite (hb_codepoint_t glyph, + CompositeGlyphHeader::Iterator *composite /* OUT */) const { - if (this->glyf_table == &Null(glyf) || !num_glyphs) + if (unlikely (!num_glyphs)) return false; unsigned int start_offset, end_offset; if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; /* glyph not found */ + return false; /* glyph not found */ - return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset, + return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset, end_offset - start_offset, composite); } enum simple_glyph_flag_t { + FLAG_ON_CURVE = 0x01, FLAG_X_SHORT = 0x02, FLAG_Y_SHORT = 0x04, FLAG_REPEAT = 0x08, FLAG_X_SAME = 0x10, - FLAG_Y_SAME = 0x20 + FLAG_Y_SAME = 0x20, + FLAG_RESERVED1 = 0x40, + FLAG_RESERVED2 = 0x80 }; /* based on FontTools _g_l_y_f.py::trim */ - inline bool remove_padding(unsigned int start_offset, - unsigned int *end_offset) const + bool remove_padding (unsigned int start_offset, + unsigned int *end_offset) const { - if (*end_offset - start_offset < GlyphHeader::static_size) - return true; + if (*end_offset - start_offset < GlyphHeader::static_size) return true; const char *glyph = ((const char *) glyf_table) + start_offset; const char * const glyph_end = glyph + (*end_offset - start_offset); @@ -303,143 +293,139 @@ struct glyf int16_t num_contours = (int16_t) glyph_header.numberOfContours; if (num_contours < 0) - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ - return true; + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + return true; else if (num_contours > 0) { - /* simple glyph w/contours, possibly trimmable */ - glyph += GlyphHeader::static_size + 2 * num_contours; - - if (unlikely (glyph + 2 >= glyph_end)) return false; - uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1; - uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0); - - glyph += 2 + nInstructions; - if (unlikely (glyph + 2 >= glyph_end)) return false; - - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; - while (glyph < glyph_end) - { - uint8_t flag = (uint8_t) *glyph; - glyph++; - - unsigned int repeat = 1; - if (flag & FLAG_REPEAT) - { - if (glyph >= glyph_end) - { - DEBUG_MSG(SUBSET, nullptr, "Bad flag"); - return false; - } - repeat = ((uint8_t) *glyph) + 1; - glyph++; - } - - unsigned int xBytes, yBytes; - xBytes = yBytes = 0; - if (flag & FLAG_X_SHORT) - xBytes = 1; - else if ((flag & FLAG_X_SAME) == 0) - xBytes = 2; - - if (flag & FLAG_Y_SHORT) - yBytes = 1; - else if ((flag & FLAG_Y_SAME) == 0) - yBytes = 2; - - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) - break; - } - - if (coordsWithFlags != nCoordinates) - { - DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); - return false; - } - glyph += coordBytes; - - if (glyph < glyph_end) - *end_offset -= glyph_end - glyph; + /* simple glyph w/contours, possibly trimmable */ + glyph += GlyphHeader::static_size + 2 * num_contours; + + if (unlikely (glyph + 2 >= glyph_end)) return false; + uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; + uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16> (glyph, 0); + + glyph += 2 + nInstructions; + if (unlikely (glyph + 2 >= glyph_end)) return false; + + unsigned int coordBytes = 0; + unsigned int coordsWithFlags = 0; + while (glyph < glyph_end) + { + uint8_t flag = (uint8_t) *glyph; + glyph++; + + unsigned int repeat = 1; + if (flag & FLAG_REPEAT) + { + if (glyph >= glyph_end) + { + DEBUG_MSG(SUBSET, nullptr, "Bad flag"); + return false; + } + repeat = ((uint8_t) *glyph) + 1; + glyph++; + } + + unsigned int xBytes, yBytes; + xBytes = yBytes = 0; + if (flag & FLAG_X_SHORT) xBytes = 1; + else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; + + if (flag & FLAG_Y_SHORT) yBytes = 1; + else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; + + coordBytes += (xBytes + yBytes) * repeat; + coordsWithFlags += repeat; + if (coordsWithFlags >= nCoordinates) + break; + } + + if (coordsWithFlags != nCoordinates) + { + DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); + return false; + } + glyph += coordBytes; + + if (glyph < glyph_end) + *end_offset -= glyph_end - glyph; } return true; } - inline bool get_offsets (hb_codepoint_t glyph, - unsigned int *start_offset /* OUT */, - unsigned int *end_offset /* OUT */) const + bool get_offsets (hb_codepoint_t glyph, + unsigned int *start_offset /* OUT */, + unsigned int *end_offset /* OUT */) const { if (unlikely (glyph >= num_glyphs)) return false; if (short_offset) { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ; + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; *start_offset = 2 * offsets[glyph]; *end_offset = 2 * offsets[glyph + 1]; } else { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ; + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; *start_offset = offsets[glyph]; *end_offset = offsets[glyph + 1]; } - if (*start_offset > *end_offset || *end_offset > glyf_len) + if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) return false; return true; } - inline bool get_instruction_offsets(unsigned int start_offset, - unsigned int end_offset, - unsigned int *instruction_start /* OUT */, - unsigned int *instruction_end /* OUT */) const + bool get_instruction_offsets (unsigned int start_offset, + unsigned int end_offset, + unsigned int *instruction_start /* OUT */, + unsigned int *instruction_end /* OUT */) const { if (end_offset - start_offset < GlyphHeader::static_size) { - *instruction_start = 0; - *instruction_end = 0; - return true; /* Empty glyph; no instructions. */ + *instruction_start = 0; + *instruction_end = 0; + return true; /* Empty glyph; no instructions. */ } const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); int16_t num_contours = (int16_t) glyph_header.numberOfContours; if (num_contours < 0) { - CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!CompositeGlyphHeader::get_iterator ( - (const char*) this->glyf_table + start_offset, - end_offset - start_offset, &composite_it))) return false; - const CompositeGlyphHeader *last; - do { - last = composite_it.current; - } while (composite_it.move_to_next()); - - if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size(); - else - *instruction_start = end_offset; - *instruction_end = end_offset; - if (unlikely (*instruction_start > *instruction_end)) - { - DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset); - return false; - } + CompositeGlyphHeader::Iterator composite_it; + if (unlikely (!CompositeGlyphHeader::get_iterator ( + (const char*) this->glyf_table + start_offset, + end_offset - start_offset, &composite_it))) return false; + const CompositeGlyphHeader *last; + do { + last = composite_it.current; + } while (composite_it.move_to_next ()); + + if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) + *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size (); + else + *instruction_start = end_offset; + *instruction_end = end_offset; + if (unlikely (*instruction_start > *instruction_end)) + { + DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset); + return false; + } } else { - unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; + unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; if (unlikely (instruction_length_offset + 2 > end_offset)) { DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength."); return false; } - const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset); + const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset); unsigned int start = instruction_length_offset + 2; unsigned int end = start + (uint16_t) instruction_length; if (unlikely (end > end_offset)) // Out of bounds of the current glyph @@ -449,17 +435,16 @@ struct glyf } *instruction_start = start; - *instruction_end = end; + *instruction_end = end; } return true; } - inline bool get_extents (hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { unsigned int start_offset, end_offset; if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; + return false; if (end_offset - start_offset < GlyphHeader::static_size) return true; /* Empty glyph; zero extents. */ @@ -477,19 +462,20 @@ struct glyf private: bool short_offset; unsigned int num_glyphs; - const loca *loca_table; - const glyf *glyf_table; - hb_blob_t *loca_blob; - hb_blob_t *glyf_blob; - unsigned int glyf_len; + hb_blob_ptr_t<loca> loca_table; + hb_blob_ptr_t<glyf> glyf_table; }; protected: - HBUINT8 dataZ[VAR]; /* Glyphs data. */ - - DEFINE_SIZE_ARRAY (0, dataZ); + UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */ + public: + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it MIN() instead. */ }; +struct glyf_accelerator_t : glyf::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index d406e3e..95229c5 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -27,8 +27,7 @@ #ifndef HB_OT_HDMX_TABLE_HH #define HB_OT_HDMX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" /* * hdmx -- Horizontal Device Metrics @@ -45,57 +44,51 @@ struct DeviceRecord struct SubsetView { const DeviceRecord *source_device_record; - unsigned int size_device_record; + unsigned int sizeDeviceRecord; hb_subset_plan_t *subset_plan; - inline void init(const DeviceRecord *source_device_record, - unsigned int size_device_record, - hb_subset_plan_t *subset_plan) + void init (const DeviceRecord *source_device_record, + unsigned int sizeDeviceRecord, + hb_subset_plan_t *subset_plan) { this->source_device_record = source_device_record; - this->size_device_record = size_device_record; + this->sizeDeviceRecord = sizeDeviceRecord; this->subset_plan = subset_plan; } - inline unsigned int len () const - { - return this->subset_plan->glyphs.len; - } + unsigned int len () const + { return this->subset_plan->glyphs.length; } - inline const HBUINT8* operator [] (unsigned int i) const + const HBUINT8* operator [] (unsigned int i) const { - if (unlikely (i >= len())) return nullptr; + if (unlikely (i >= len ())) return nullptr; hb_codepoint_t gid = this->subset_plan->glyphs [i]; - const HBUINT8* width = &(this->source_device_record->widths[gid]); - - if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record) - return width; - else - return nullptr; + if (gid >= sizeDeviceRecord - DeviceRecord::min_size) + return nullptr; + return &(this->source_device_record->widthsZ[gid]); } }; - static inline unsigned int get_size (unsigned int count) - { - unsigned int raw_size = min_size + count * HBUINT8::static_size; - if (raw_size % 4) - /* Align to 32 bits */ - return raw_size + (4 - (raw_size % 4)); - return raw_size; - } + static unsigned int get_size (unsigned int count) + { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } - inline bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view) + bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view) { TRACE_SERIALIZE (this); - if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len())))) + unsigned int size = get_size (subset_view.len ()); + if (unlikely (!c->allocate_size<DeviceRecord> (size))) + { + DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.", + size); return_trace (false); + } - this->pixel_size.set (subset_view.source_device_record->pixel_size); - this->max_width.set (subset_view.source_device_record->max_width); + this->pixelSize.set (subset_view.source_device_record->pixelSize); + this->maxWidth.set (subset_view.source_device_record->maxWidth); - for (unsigned int i = 0; i < subset_view.len(); i++) + for (unsigned int i = 0; i < subset_view.len (); i++) { const HBUINT8 *width = subset_view[i]; if (!width) @@ -103,56 +96,56 @@ struct DeviceRecord DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i); return_trace (false); } - widths[i].set (*width); + widthsZ[i].set (*width); } return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int size_device_record) const + bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - c->check_range (this, size_device_record))); + c->check_range (this, sizeDeviceRecord))); } - HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */ - HBUINT8 max_width; /* Maximum width. */ - HBUINT8 widths[VAR]; /* Array of widths (numGlyphs is from the 'maxp' table). */ + HBUINT8 pixelSize; /* Pixel size for following widths (as ppem). */ + HBUINT8 maxWidth; /* Maximum width. */ + UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ public: - DEFINE_SIZE_ARRAY (2, widths); + DEFINE_SIZE_ARRAY (2, widthsZ); }; struct hdmx { - static const hb_tag_t tableTag = HB_OT_TAG_hdmx; + static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx; - inline unsigned int get_size (void) const - { - return min_size + num_records * size_device_record; - } + unsigned int get_size () const + { return min_size + numRecords * sizeDeviceRecord; } - inline const DeviceRecord& operator [] (unsigned int i) const + const DeviceRecord& operator [] (unsigned int i) const { - if (unlikely (i >= num_records)) return Null(DeviceRecord); - return StructAtOffset<DeviceRecord> (this->data, i * size_device_record); + /* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed. + * https://github.com/harfbuzz/harfbuzz/issues/1300 */ + if (unlikely (i >= numRecords)) return Null (DeviceRecord); + return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord); } - inline bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) + bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min ((*this)))) return_trace (false); this->version.set (source_hdmx->version); - this->num_records.set (source_hdmx->num_records); - this->size_device_record.set (DeviceRecord::get_size (plan->glyphs.len)); + this->numRecords.set (source_hdmx->numRecords); + this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length)); - for (unsigned int i = 0; i < source_hdmx->num_records; i++) + for (unsigned int i = 0; i < source_hdmx->numRecords; i++) { DeviceRecord::SubsetView subset_view; - subset_view.init (&(*source_hdmx)[i], source_hdmx->size_device_record, plan); + subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan); if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view)) return_trace (false); @@ -161,14 +154,14 @@ struct hdmx return_trace (true); } - static inline size_t get_subsetted_size (hb_subset_plan_t *plan) + static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) { - return min_size + DeviceRecord::get_size (plan->glyphs.len); + return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length); } - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { - size_t dest_size = get_subsetted_size (plan); + size_t dest_size = get_subsetted_size (this, plan); hdmx *dest = (hdmx *) malloc (dest_size); if (unlikely (!dest)) { @@ -178,8 +171,10 @@ struct hdmx hb_serialize_context_t c (dest, dest_size); hdmx *hdmx_prime = c.start_serialize<hdmx> (); - if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) { + if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) + { free (dest); + DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx."); return false; } c.end_serialize (); @@ -195,22 +190,22 @@ struct hdmx return result; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && version == 0 && - !_hb_unsigned_int_mul_overflows (num_records, size_device_record) && - size_device_record >= DeviceRecord::min_size && - c->check_range (this, get_size())); + return_trace (c->check_struct (this) && + !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) && + sizeDeviceRecord >= DeviceRecord::min_size && + c->check_range (this, get_size ())); } protected: - HBUINT16 version; /* Table version number (0) */ - HBUINT16 num_records; /* Number of device records. */ - HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */ - HBUINT8 data[VAR]; /* Array of device records. */ + HBUINT16 version; /* Table version number (0) */ + HBUINT16 numRecords; /* Number of device records. */ + HBUINT32 sizeDeviceRecord; /* Size of a device record, 32-bit aligned. */ + DeviceRecord firstDeviceRecord; /* Array of device records. */ public: - DEFINE_SIZE_ARRAY (8, data); + DEFINE_SIZE_MIN (8); }; } /* namespace OT */ diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh index 965e30a..3c0bb3d 100644 --- a/src/hb-ot-head-table.hh +++ b/src/hb-ot-head-table.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_HEAD_TABLE_HH #define HB_OT_HEAD_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * head -- Font Header @@ -45,16 +45,29 @@ struct head { friend struct OffsetTable; - static const hb_tag_t tableTag = HB_OT_TAG_head; + static constexpr hb_tag_t tableTag = HB_OT_TAG_head; - inline unsigned int get_upem (void) const + unsigned int get_upem () const { unsigned int upem = unitsPerEm; /* If no valid head table found, assume 1000, which matches typical Type1 usage. */ return 16 <= upem && upem <= 16384 ? upem : 1000; } - inline bool sanitize (hb_sanitize_context_t *c) const + enum mac_style_flag_t { + BOLD = 1u<<0, + ITALIC = 1u<<1, + UNDERLINE = 1u<<2, + OUTLINE = 1u<<3, + SHADOW = 1u<<4, + CONDENSED = 1u<<5 + }; + + bool is_bold () const { return macStyle & BOLD; } + bool is_italic () const { return macStyle & ITALIC; } + bool is_condensed () const { return macStyle & CONDENSED; } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -141,8 +154,8 @@ struct head * -1: Only strongly right to left; * -2: Like -1 but also contains neutrals. */ public: - HBINT16 indexToLocFormat; /* 0 for short offsets, 1 for long. */ - HBINT16 glyphDataFormat; /* 0 for current format. */ + HBUINT16 indexToLocFormat; /* 0 for short offsets, 1 for long. */ + HBUINT16 glyphDataFormat; /* 0 for current format. */ DEFINE_SIZE_STATIC (54); }; diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh index efb42b6..c3155b7 100644 --- a/src/hb-ot-hhea-table.hh +++ b/src/hb-ot-hhea-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_HHEA_TABLE_HH #define HB_OT_HHEA_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * hhea -- Horizontal Header @@ -45,7 +45,7 @@ namespace OT { template <typename T> struct _hea { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && likely (version.major == 1)); @@ -86,10 +86,10 @@ struct _hea }; struct hhea : _hea<hhea> { - static const hb_tag_t tableTag = HB_OT_TAG_hhea; + static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea; }; struct vhea : _hea<vhea> { - static const hb_tag_t tableTag = HB_OT_TAG_vhea; + static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea; }; diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 2c62664..a95a56f 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -27,11 +27,10 @@ #ifndef HB_OT_HMTX_TABLE_HH #define HB_OT_HMTX_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" -#include "hb-subset-plan.hh" /* * hmtx -- Horizontal Metrics @@ -49,7 +48,7 @@ namespace OT { struct LongMetric { UFWORD advance; /* Advance width/height. */ - FWORD lsb; /* Leading (left/top) side bearing. */ + FWORD sb; /* Leading (left/top) side bearing. */ public: DEFINE_SIZE_STATIC (4); }; @@ -57,7 +56,7 @@ struct LongMetric template <typename T, typename H> struct hmtxvmtx { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); /* We don't check for anything specific here. The users of the @@ -66,11 +65,11 @@ struct hmtxvmtx } - inline bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + bool subset_update_header (hb_subset_plan_t *plan, + unsigned int num_hmetrics) const { - hb_blob_t *src_blob = OT::Sanitizer<H> ().sanitize (plan->source->reference_table (H::tableTag)); - hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail(src_blob); + hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag); + hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); hb_blob_destroy (src_blob); if (unlikely (!dest_blob)) { @@ -87,7 +86,7 @@ struct hmtxvmtx return result; } - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { typename T::accelerator_t _mtx; _mtx.init (plan->source); @@ -95,33 +94,33 @@ struct hmtxvmtx /* All the trailing glyphs with the same advance can use one LongMetric * and just keep LSB */ hb_vector_t<hb_codepoint_t> &gids = plan->glyphs; - unsigned int num_advances = gids.len; + unsigned int num_advances = gids.length; unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]); - while (num_advances > 1 - && last_advance == _mtx.get_advance (gids[num_advances - 2])) + while (num_advances > 1 && + last_advance == _mtx.get_advance (gids[num_advances - 2])) { num_advances--; } /* alloc the new table */ size_t dest_sz = num_advances * 4 - + (gids.len - num_advances) * 2; + + (gids.length - num_advances) * 2; void *dest = (void *) malloc (dest_sz); if (unlikely (!dest)) { return false; } DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances); - DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.len - num_advances, (unsigned int) dest_sz); + DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz); - const char *source_table = hb_blob_get_data (_mtx.blob, nullptr); + const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr); // Copy everything over LongMetric * old_metrics = (LongMetric *) source_table; FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances); char * dest_pos = (char *) dest; bool failed = false; - for (unsigned int i = 0; i < gids.len; i++) + for (unsigned int i = 0; i < gids.length; i++) { /* the last metric or the one for gids[i] */ LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]); @@ -135,8 +134,8 @@ struct hmtxvmtx } else { - /* dest just lsb */ - *((FWORD *) dest_pos) = src_metric->lsb; + /* dest just sb */ + *((FWORD *) dest_pos) = src_metric->sb; } } else @@ -148,18 +147,18 @@ struct hmtxvmtx failed = true; break; } - FWORD src_lsb = *(lsbs + gids[i] - _mtx.num_advances); + FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances); if (i < num_advances) { /* dest needs a full LongMetric */ LongMetric *metric = (LongMetric *)dest_pos; metric->advance = src_metric->advance; - metric->lsb = src_lsb; + metric->sb = src_sb; } else { - /* dest just needs an lsb */ - *((FWORD *) dest_pos) = src_lsb; + /* dest just needs an sb */ + *((FWORD *) dest_pos) = src_sb; } } dest_pos += (i < num_advances ? 4 : 2); @@ -187,34 +186,27 @@ struct hmtxvmtx { friend struct hmtxvmtx; - inline void init (hb_face_t *face, + void init (hb_face_t *face, unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); bool got_font_extents = false; - if (T::os2Tag) + if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ()) { - hb_blob_t *os2_blob = Sanitizer<os2> ().sanitize (face->reference_table (T::os2Tag)); - const os2 *os2_table = os2_blob->as<os2> (); -#define USE_TYPO_METRICS (1u<<7) - if (0 != (os2_table->fsSelection & USE_TYPO_METRICS)) - { - ascender = os2_table->sTypoAscender; - descender = os2_table->sTypoDescender; - line_gap = os2_table->sTypoLineGap; - got_font_extents = (ascender | descender) != 0; - } - hb_blob_destroy (os2_blob); + ascender = abs (face->table.OS2->sTypoAscender); + descender = -abs (face->table.OS2->sTypoDescender); + line_gap = face->table.OS2->sTypoLineGap; + got_font_extents = (ascender | descender) != 0; } - hb_blob_t *_hea_blob = Sanitizer<H> ().sanitize (face->reference_table (H::tableTag)); + hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face); const H *_hea_table = _hea_blob->as<H> (); num_advances = _hea_table->numberOfLongMetrics; if (!got_font_extents) { - ascender = _hea_table->ascender; - descender = _hea_table->descender; + ascender = abs (_hea_table->ascender); + descender = -abs (_hea_table->descender); line_gap = _hea_table->lineGap; got_font_extents = (ascender | descender) != 0; } @@ -222,10 +214,10 @@ struct hmtxvmtx has_font_extents = got_font_extents; - blob = Sanitizer<hmtxvmtx> ().sanitize (face->reference_table (T::tableTag)); + table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag); /* Cap num_metrics() and num_advances() based on table length. */ - unsigned int len = hb_blob_get_length (blob); + unsigned int len = table.get_length (); if (unlikely (num_advances * 4 > len)) num_advances = len / 4; num_metrics = num_advances + (len - 4 * num_advances) / 2; @@ -235,53 +227,64 @@ struct hmtxvmtx if (unlikely (!num_advances)) { num_metrics = num_advances = 0; - hb_blob_destroy (blob); - blob = hb_blob_get_empty (); + table.destroy (); + table = hb_blob_get_empty (); } - table = blob->as<hmtxvmtx> (); - var_blob = Sanitizer<HVARVVAR> ().sanitize (face->reference_table (T::variationsTag)); - var_table = var_blob->as<HVARVVAR> (); + var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag); } - inline void fini (void) + void fini () { - hb_blob_destroy (blob); - hb_blob_destroy (var_blob); + table.destroy (); + var_table.destroy (); } - inline unsigned int get_advance (hb_codepoint_t glyph) const + /* TODO Add variations version. */ + unsigned int get_side_bearing (hb_codepoint_t glyph) const + { + if (glyph < num_advances) + return table->longMetricZ[glyph].sb; + + if (unlikely (glyph >= num_metrics)) + return 0; + + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; + return bearings[glyph - num_advances]; + } + + unsigned int get_advance (hb_codepoint_t glyph) const { if (unlikely (glyph >= num_metrics)) { - /* If num_metrics is zero, it means we don't have the metrics table - * for this direction: return default advance. Otherwise, it means that the - * glyph index is out of bound: return zero. */ - if (num_metrics) - return 0; - else - return default_advance; + /* If num_metrics is zero, it means we don't have the metrics table + * for this direction: return default advance. Otherwise, it means that the + * glyph index is out of bound: return zero. */ + if (num_metrics) + return 0; + else + return default_advance; } - return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance; + return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance; } - inline unsigned int get_advance (hb_codepoint_t glyph, - hb_font_t *font) const + unsigned int get_advance (hb_codepoint_t glyph, + hb_font_t *font) const { unsigned int advance = get_advance (glyph); - if (likely(glyph < num_metrics)) + if (likely (glyph < num_metrics)) { - advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! + advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! } return advance; } public: bool has_font_extents; - unsigned short ascender; - unsigned short descender; - unsigned short line_gap; + int ascender; + int descender; + int line_gap; protected: unsigned int num_metrics; @@ -289,14 +292,12 @@ struct hmtxvmtx unsigned int default_advance; private: - const hmtxvmtx *table; - hb_blob_t *blob; - const HVARVVAR *var_table; - hb_blob_t *var_blob; + hb_blob_ptr_t<hmtxvmtx> table; + hb_blob_ptr_t<HVARVVAR> var_table; }; protected: - LongMetric longMetric[VAR]; /* Paired advance width and leading + UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading * bearing values for each glyph. The * value numOfHMetrics comes from * the 'hhea' table. If the font is @@ -304,7 +305,7 @@ struct hmtxvmtx * be in the array, but that entry is * required. The last entry applies to * all subsequent glyphs. */ -/*FWORD leadingBearingX[VAR];*/ /* Here the advance is assumed +/*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed * to be the same as the advance * for the last entry above. The * number of entries in this array is @@ -318,20 +319,23 @@ struct hmtxvmtx * font to vary the side bearing * values for each glyph. */ public: - DEFINE_SIZE_ARRAY (0, longMetric); + DEFINE_SIZE_ARRAY (0, longMetricZ); }; struct hmtx : hmtxvmtx<hmtx, hhea> { - static const hb_tag_t tableTag = HB_OT_TAG_hmtx; - static const hb_tag_t variationsTag = HB_OT_TAG_HVAR; - static const hb_tag_t os2Tag = HB_OT_TAG_os2; + static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; + static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; + static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2; }; struct vmtx : hmtxvmtx<vmtx, vhea> { - static const hb_tag_t tableTag = HB_OT_TAG_vmtx; - static const hb_tag_t variationsTag = HB_OT_TAG_VVAR; - static const hb_tag_t os2Tag = HB_TAG_NONE; + static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; + static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; + static constexpr hb_tag_t os2Tag = HB_TAG_NONE; }; +struct hmtx_accelerator_t : hmtx::accelerator_t {}; +struct vmtx_accelerator_t : vmtx::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh index b0fdea4..ec6a3c8 100644 --- a/src/hb-ot-kern-table.hh +++ b/src/hb-ot-kern-table.hh @@ -27,7 +27,8 @@ #ifndef HB_OT_KERN_TABLE_HH #define HB_OT_KERN_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-aat-layout-kerx-table.hh" + /* * kern -- Kerning @@ -40,354 +41,297 @@ namespace OT { -struct hb_glyph_pair_t -{ - hb_codepoint_t left; - hb_codepoint_t right; -}; - -struct KernPair -{ - inline int get_kerning (void) const - { return value; } - - inline int cmp (const hb_glyph_pair_t &o) const - { - int ret = left.cmp (o.left); - if (ret) return ret; - return right.cmp (o.right); - } - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - protected: - GlyphID left; - GlyphID right; - FWORD value; - public: - DEFINE_SIZE_STATIC (6); -}; - -struct KernSubTableFormat0 +template <typename KernSubTableHeader> +struct KernSubTableFormat3 { - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - hb_glyph_pair_t pair = {left, right}; - int i = pairs.bsearch (pair); - if (i == -1) + hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount); + hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (kernValue).as_array (glyphCount); + hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (leftClass).as_array (glyphCount); + hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8> > (rightClass).as_array (leftClassCount * rightClassCount); + + unsigned int leftC = leftClass[left]; + unsigned int rightC = rightClass[right]; + if (unlikely (leftC >= leftClassCount || rightC >= rightClassCount)) return 0; - return pairs[i].get_kerning (); + unsigned int i = leftC * rightClassCount + rightC; + return kernValue[kernIndex[i]]; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool apply (AAT::hb_aat_apply_context_t *c) const { - TRACE_SANITIZE (this); - return_trace (pairs.sanitize (c)); - } - - protected: - BinSearchArrayOf<KernPair> pairs; /* Array of kerning pairs. */ - public: - DEFINE_SIZE_ARRAY (8, pairs); -}; + TRACE_APPLY (this); -struct KernClassTable -{ - inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; } + if (!c->plan->requested_kerning) + return false; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (firstGlyph.sanitize (c) && classes.sanitize (c)); - } + if (header.coverage & header.Backwards) + return false; - protected: - HBUINT16 firstGlyph; /* First glyph in class range. */ - ArrayOf<HBUINT16> classes; /* Glyph classes. */ - public: - DEFINE_SIZE_ARRAY (4, classes); -}; + hb_kern_machine_t<KernSubTableFormat3> machine (*this, header.coverage & header.CrossStream); + machine.kern (c->font, c->buffer, c->plan->kern_mask); -struct KernSubTableFormat2 -{ - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const - { - unsigned int l = (this+leftClassTable).get_class (left); - unsigned int r = (this+rightClassTable).get_class (right); - unsigned int offset = l * rowWidth + r * sizeof (FWORD); - const FWORD *arr = &(this+array); - if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) - return 0; - const FWORD *v = &StructAtOffset<FWORD> (arr, offset); - if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) - return 0; - return *v; + return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (rowWidth.sanitize (c) && - leftClassTable.sanitize (c, this) && - rightClassTable.sanitize (c, this) && - array.sanitize (c, this)); + return_trace (c->check_struct (this) && + c->check_range (kernValueZ, + kernValueCount * sizeof (FWORD) + + glyphCount * 2 + + leftClassCount * rightClassCount)); } protected: - HBUINT16 rowWidth; /* The width, in bytes, of a row in the table. */ - OffsetTo<KernClassTable> - leftClassTable; /* Offset from beginning of this subtable to - * left-hand class table. */ - OffsetTo<KernClassTable> - rightClassTable;/* Offset from beginning of this subtable to - * right-hand class table. */ - OffsetTo<FWORD> - array; /* Offset from beginning of this subtable to - * the start of the kerning array. */ + KernSubTableHeader header; + HBUINT16 glyphCount; /* The number of glyphs in this font. */ + HBUINT8 kernValueCount; /* The number of kerning values. */ + HBUINT8 leftClassCount; /* The number of left-hand classes. */ + HBUINT8 rightClassCount;/* The number of right-hand classes. */ + HBUINT8 flags; /* Set to zero (reserved for future use). */ + UnsizedArrayOf<FWORD> kernValueZ; /* The kerning values. + * Length kernValueCount. */ +#if 0 + UnsizedArrayOf<HBUINT8>leftClass; /* The left-hand classes. + * Length glyphCount. */ + UnsizedArrayOf<HBUINT8>rightClass; /* The right-hand classes. + * Length glyphCount. */ + UnsizedArrayOf<HBUINT8>kernIndex; /* The indices into the kernValue array. + * Length leftClassCount * rightClassCount */ +#endif public: - DEFINE_SIZE_MIN (8); + DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ); }; +template <typename KernSubTableHeader> struct KernSubTable { - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const + unsigned int get_size () const { return u.header.length; } + unsigned int get_type () const { return u.header.format; } + + int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - switch (format) { + switch (get_type ()) { + /* This method hooks up to hb_font_t's get_h_kerning. Only support Format0. */ case 0: return u.format0.get_kerning (left, right); - case 2: return u.format2.get_kerning (left, right, end); default:return 0; } } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const + template <typename context_t> + typename context_t::return_t dispatch (context_t *c) const { - TRACE_SANITIZE (this); - switch (format) { - case 0: return_trace (u.format0.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - default:return_trace (true); + unsigned int subtable_type = get_type (); + TRACE_DISPATCH (this, subtable_type); + switch (subtable_type) { + case 0: return_trace (c->dispatch (u.format0)); + case 1: return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ()); + case 2: return_trace (c->dispatch (u.format2)); + case 3: return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ()); + default: return_trace (c->default_return_value ()); } } - protected: + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.header.sanitize (c) || + u.header.length < u.header.min_size || + !c->check_range (this, u.header.length))) return_trace (false); + + return_trace (dispatch (c)); + } + + public: union { - KernSubTableFormat0 format0; - KernSubTableFormat2 format2; + KernSubTableHeader header; + AAT::KerxSubTableFormat0<KernSubTableHeader> format0; + AAT::KerxSubTableFormat1<KernSubTableHeader> format1; + AAT::KerxSubTableFormat2<KernSubTableHeader> format2; + KernSubTableFormat3<KernSubTableHeader> format3; } u; public: - DEFINE_SIZE_MIN (0); + DEFINE_SIZE_MIN (KernSubTableHeader::static_size); }; -template <typename T> -struct KernSubTableWrapper +struct KernOTSubTableHeader { - /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ - inline const T* thiz (void) const { return static_cast<const T *> (this); } - - inline bool is_horizontal (void) const - { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; } + static constexpr bool apple = false; + typedef AAT::ObsoleteTypes Types; - inline bool is_override (void) const - { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); } + unsigned int tuple_count () const { return 0; } + bool is_horizontal () const { return (coverage & Horizontal); } - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const - { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); } - - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const - { return is_horizontal () ? get_kerning (left, right, end) : 0; } - - inline unsigned int get_size (void) const { return thiz()->length; } + enum Coverage + { + Horizontal = 0x01u, + Minimum = 0x02u, + CrossStream = 0x04u, + Override = 0x08u, + + /* Not supported: */ + Backwards = 0x00u, + Variation = 0x00u, + }; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (thiz()) && - thiz()->length >= T::min_size && - c->check_array (thiz(), 1, thiz()->length) && - thiz()->subtable.sanitize (c, thiz()->format)); + return_trace (c->check_struct (this)); } + + public: + HBUINT16 versionZ; /* Unused. */ + HBUINT16 length; /* Length of the subtable (including this header). */ + HBUINT8 format; /* Subtable format. */ + HBUINT8 coverage; /* Coverage bits. */ + public: + DEFINE_SIZE_STATIC (6); }; -template <typename T> -struct KernTable +struct KernOT : AAT::KerxTable<KernOT> { - /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ - inline const T* thiz (void) const { return static_cast<const T *> (this); } + friend struct AAT::KerxTable<KernOT>; - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const - { - int v = 0; - const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data); - unsigned int count = thiz()->nTables; - for (unsigned int i = 0; i < count; i++) - { - if (st->is_override ()) - v = 0; - v += st->get_h_kerning (left, right, table_length + (const char *) this); - st = &StructAfter<typename T::SubTableWrapper> (*st); - } - return v; - } + static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; + static constexpr unsigned minVersion = 0u; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (thiz()) || - thiz()->version != T::VERSION)) - return_trace (false); - - const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data); - unsigned int count = thiz()->nTables; - for (unsigned int i = 0; i < count; i++) - { - if (unlikely (!st->sanitize (c))) - return_trace (false); - st = &StructAfter<typename T::SubTableWrapper> (*st); - } + typedef KernOTSubTableHeader SubTableHeader; + typedef SubTableHeader::Types Types; + typedef KernSubTable<SubTableHeader> SubTable; - return_trace (true); - } + protected: + HBUINT16 version; /* Version--0x0000u */ + HBUINT16 tableCount; /* Number of subtables in the kerning table. */ + SubTable firstSubTable; /* Subtables. */ + public: + DEFINE_SIZE_MIN (4); }; -struct KernOT : KernTable<KernOT> + +struct KernAATSubTableHeader { - friend struct KernTable<KernOT>; + static constexpr bool apple = true; + typedef AAT::ObsoleteTypes Types; - static const uint16_t VERSION = 0x0000u; + unsigned int tuple_count () const { return 0; } + bool is_horizontal () const { return !(coverage & Vertical); } - struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper> + enum Coverage { - friend struct KernSubTableWrapper<SubTableWrapper>; - - enum coverage_flags_t { - COVERAGE_DIRECTION_FLAG = 0x01u, - COVERAGE_MINIMUM_FLAG = 0x02u, - COVERAGE_CROSSSTREAM_FLAG = 0x04u, - COVERAGE_OVERRIDE_FLAG = 0x08u, - - COVERAGE_VARIATION_FLAG = 0x00u, /* Not supported. */ - - COVERAGE_CHECK_FLAGS = 0x07u, - COVERAGE_CHECK_HORIZONTAL = 0x01u - }; - - protected: - HBUINT16 versionZ; /* Unused. */ - HBUINT16 length; /* Length of the subtable (including this header). */ - HBUINT8 format; /* Subtable format. */ - HBUINT8 coverage; /* Coverage bits. */ - KernSubTable subtable; /* Subtable data. */ - public: - DEFINE_SIZE_MIN (6); + Vertical = 0x80u, + CrossStream = 0x40u, + Variation = 0x20u, + + /* Not supported: */ + Backwards = 0x00u, }; - protected: - HBUINT16 version; /* Version--0x0000u */ - HBUINT16 nTables; /* Number of subtables in the kerning table. */ - HBUINT8 data[VAR]; + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT32 length; /* Length of the subtable (including this header). */ + HBUINT8 coverage; /* Coverage bits. */ + HBUINT8 format; /* Subtable format. */ + HBUINT16 tupleIndex; /* The tuple index (used for variations fonts). + * This value specifies which tuple this subtable covers. + * Note: We don't implement. */ public: - DEFINE_SIZE_ARRAY (4, data); + DEFINE_SIZE_STATIC (8); }; -struct KernAAT : KernTable<KernAAT> +struct KernAAT : AAT::KerxTable<KernAAT> { - friend struct KernTable<KernAAT>; + friend struct AAT::KerxTable<KernAAT>; - static const uint32_t VERSION = 0x00010000u; + static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; + static constexpr unsigned minVersion = 0x00010000u; - struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper> - { - friend struct KernSubTableWrapper<SubTableWrapper>; - - enum coverage_flags_t { - COVERAGE_DIRECTION_FLAG = 0x80u, - COVERAGE_CROSSSTREAM_FLAG = 0x40u, - COVERAGE_VARIATION_FLAG = 0x20u, - - COVERAGE_OVERRIDE_FLAG = 0x00u, /* Not supported. */ - - COVERAGE_CHECK_FLAGS = 0xE0u, - COVERAGE_CHECK_HORIZONTAL = 0x00u - }; - - protected: - HBUINT32 length; /* Length of the subtable (including this header). */ - HBUINT8 coverage; /* Coverage bits. */ - HBUINT8 format; /* Subtable format. */ - HBUINT16 tupleIndex; /* The tuple index (used for variations fonts). - * This value specifies which tuple this subtable covers. */ - KernSubTable subtable; /* Subtable data. */ - public: - DEFINE_SIZE_MIN (8); - }; + typedef KernAATSubTableHeader SubTableHeader; + typedef SubTableHeader::Types Types; + typedef KernSubTable<SubTableHeader> SubTable; protected: - HBUINT32 version; /* Version--0x00010000u */ - HBUINT32 nTables; /* Number of subtables in the kerning table. */ - HBUINT8 data[VAR]; + HBUINT32 version; /* Version--0x00010000u */ + HBUINT32 tableCount; /* Number of subtables in the kerning table. */ + SubTable firstSubTable; /* Subtables. */ public: - DEFINE_SIZE_ARRAY (8, data); + DEFINE_SIZE_MIN (8); }; struct kern { - static const hb_tag_t tableTag = HB_OT_TAG_kern; + static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const + bool has_data () const { return u.version32; } + unsigned int get_type () const { return u.major; } + + bool has_state_machine () const { - switch (u.major) { - case 0: return u.ot.get_h_kerning (left, right, table_length); - case 1: return u.aat.get_h_kerning (left, right, table_length); - default:return 0; + switch (get_type ()) { + case 0: return u.ot.has_state_machine (); + case 1: return u.aat.has_state_machine (); + default:return false; } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool has_cross_stream () const { - TRACE_SANITIZE (this); - if (!u.major.sanitize (c)) return_trace (false); - switch (u.major) { - case 0: return_trace (u.ot.sanitize (c)); - case 1: return_trace (u.aat.sanitize (c)); - default:return_trace (true); + switch (get_type ()) { + case 0: return u.ot.has_cross_stream (); + case 1: return u.aat.has_cross_stream (); + default:return false; } } - struct accelerator_t + int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - inline void init (hb_face_t *face) - { - blob = Sanitizer<kern>().sanitize (face->reference_table (HB_OT_TAG_kern)); - table = blob->as<kern> (); - table_length = blob->length; - } - inline void fini (void) - { - hb_blob_destroy (blob); + switch (get_type ()) { + case 0: return u.ot.get_h_kerning (left, right); + case 1: return u.aat.get_h_kerning (left, right); + default:return 0; } + } - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const - { return table->get_h_kerning (left, right, table_length); } + bool apply (AAT::hb_aat_apply_context_t *c) const + { return dispatch (c); } - private: - hb_blob_t *blob; - const kern *table; - unsigned int table_length; - }; + template <typename context_t> + typename context_t::return_t dispatch (context_t *c) const + { + unsigned int subtable_type = get_type (); + TRACE_DISPATCH (this, subtable_type); + switch (subtable_type) { + case 0: return_trace (c->dispatch (u.ot)); + case 1: return_trace (c->dispatch (u.aat)); + default: return_trace (c->default_return_value ()); + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.version32.sanitize (c)) return_trace (false); + return_trace (dispatch (c)); + } protected: union { + HBUINT32 version32; HBUINT16 major; KernOT ot; KernAAT aat; } u; public: - DEFINE_SIZE_UNION (2, major); + DEFINE_SIZE_UNION (4, version32); }; } /* namespace OT */ diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 33dce89..dd0fba1 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -1,6 +1,7 @@ /* * Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu> * Copyright © 2018 Google, Inc. + * Copyright © 2018 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -28,12 +29,13 @@ #ifndef HB_OT_LAYOUT_BASE_TABLE_HH #define HB_OT_LAYOUT_BASE_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" -namespace OT { +/* To be removed */ +typedef hb_tag_t hb_ot_layout_baseline_t; -#define NOT_INDEXED ((unsigned int) -1) +namespace OT { /* * BASE -- Baseline @@ -42,30 +44,30 @@ namespace OT { struct BaseCoordFormat1 { - inline int get_coord (void) const { return coordinate; } + hb_position_t get_coord () const { return coordinate; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + return_trace (likely (c->check_struct (this))); } protected: HBUINT16 format; /* Format identifier--format = 1 */ - HBINT16 coordinate; /* X or Y value, in design units */ + FWORD coordinate; /* X or Y value, in design units */ public: DEFINE_SIZE_STATIC (4); }; struct BaseCoordFormat2 { - inline int get_coord (void) const + hb_position_t get_coord () const { /* TODO */ return coordinate; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -73,7 +75,7 @@ struct BaseCoordFormat2 protected: HBUINT16 format; /* Format identifier--format = 2 */ - HBINT16 coordinate; /* X or Y value, in design units */ + FWORD coordinate; /* X or Y value, in design units */ GlyphID referenceGlyph; /* Glyph ID of control glyph */ HBUINT16 coordPoint; /* Index of contour point on the * reference glyph */ @@ -83,44 +85,53 @@ struct BaseCoordFormat2 struct BaseCoordFormat3 { - inline int get_coord (void) const + hb_position_t get_coord (hb_font_t *font, + const VariationStore &var_store, + hb_direction_t direction) const { - /* TODO */ - return coordinate; + const Device &device = this+deviceTable; + return coordinate + (HB_DIRECTION_IS_VERTICAL (direction) ? + device.get_y_delta (font, var_store) : + device.get_x_delta (font, var_store)); } - inline bool sanitize (hb_sanitize_context_t *c) const + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + deviceTable.sanitize (c, this))); } protected: - HBUINT16 format; /* Format identifier--format = 3 */ - HBINT16 coordinate; /* X or Y value, in design units */ - OffsetTo<Device> deviceTable; /* Offset to Device table for X or - * Y value, from beginning of - * BaseCoord table (may be NULL). */ + HBUINT16 format; /* Format identifier--format = 3 */ + FWORD coordinate; /* X or Y value, in design units */ + OffsetTo<Device> + deviceTable; /* Offset to Device table for X or + * Y value, from beginning of + * BaseCoord table (may be NULL). */ public: DEFINE_SIZE_STATIC (6); }; struct BaseCoord { - inline int get_coord (void) const + hb_position_t get_coord (hb_font_t *font, + const VariationStore &var_store, + hb_direction_t direction) const { switch (u.format) { case 1: return u.format1.get_coord (); case 2: return u.format2.get_coord (); - case 3: return u.format3.get_coord (); + case 3: return u.format3.get_coord (font, var_store, direction); default:return 0; } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); + if (unlikely (!u.format.sanitize (c))) return_trace (false); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); @@ -142,32 +153,40 @@ struct BaseCoord struct FeatMinMaxRecord { - inline int get_min_value (void) const - { return (this+minCoord).get_coord(); } - - inline int get_max_value (void) const - { return (this+maxCoord).get_coord(); } + static int cmp (const void *key_, const void *entry_) + { + hb_tag_t key = * (hb_tag_t *) key_; + const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_; + return key < (unsigned int) entry.tag ? -1 : + key > (unsigned int) entry.tag ? 1 : + 0; + } - inline const Tag &get_tag () const - { return tag; } + void get_min_max (const BaseCoord **min, const BaseCoord **max) const + { + if (likely (min)) *min = &(this+minCoord); + if (likely (max)) *max = &(this+maxCoord); + } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - minCoord.sanitize (c, base) && - maxCoord.sanitize (c, base)); + return_trace (likely (c->check_struct (this) && + minCoord.sanitize (c, this) && + maxCoord.sanitize (c, this))); } protected: - Tag tag; /* 4-byte feature identification tag--must - * match feature tag in FeatureList */ - OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines - * the minimum extent value, from beginning - * of MinMax table (may be NULL) */ - OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines - * the maximum extent value, from beginning - * of MinMax table (may be NULL) */ + Tag tag; /* 4-byte feature identification tag--must + * match feature tag in FeatureList */ + OffsetTo<BaseCoord> + minCoord; /* Offset to BaseCoord table that defines + * the minimum extent value, from beginning + * of MinMax table (may be NULL) */ + OffsetTo<BaseCoord> + maxCoord; /* Offset to BaseCoord table that defines + * the maximum extent value, from beginning + * of MinMax table (may be NULL) */ public: DEFINE_SIZE_STATIC (8); @@ -175,356 +194,269 @@ struct FeatMinMaxRecord struct MinMax { - inline unsigned int get_feature_tag_index (Tag featureTableTag) const - { - /* TODO bsearch */ - unsigned int count = featMinMaxRecords.len; - for (unsigned int i = 0; i < count; i++) + void get_min_max (hb_tag_t feature_tag, + const BaseCoord **min, + const BaseCoord **max) const + { + /* TODO Replace hb_bsearch() with .bsearch(). */ + const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *) + hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ, + featMinMaxRecords.len, + FeatMinMaxRecord::static_size, + FeatMinMaxRecord::cmp); + if (minMaxCoord) + minMaxCoord->get_min_max (min, max); + else { - Tag tag = featMinMaxRecords[i].get_tag(); - int cmp = tag.cmp(featureTableTag); - if (cmp == 0) return i; - if (cmp > 0) return NOT_INDEXED; + if (likely (min)) *min = &(this+minCoord); + if (likely (max)) *max = &(this+maxCoord); } - return NOT_INDEXED; - } - - inline int get_min_value (unsigned int featureTableTagIndex) const - { - if (featureTableTagIndex == NOT_INDEXED) - return (this+minCoord).get_coord(); - return featMinMaxRecords[featureTableTagIndex].get_min_value(); - } - - inline int get_max_value (unsigned int featureTableTagIndex) const - { - if (featureTableTagIndex == NOT_INDEXED) - return (this+maxCoord).get_coord(); - return featMinMaxRecords[featureTableTagIndex].get_max_value(); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - minCoord.sanitize (c, this) && - maxCoord.sanitize (c, this) && - featMinMaxRecords.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + minCoord.sanitize (c, this) && + maxCoord.sanitize (c, this) && + featMinMaxRecords.sanitize (c, this))); } protected: - OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines - * minimum extent value, from the beginning - * of MinMax table (may be NULL) */ - OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines - * maximum extent value, from the beginning - * of MinMax table (may be NULL) */ - ArrayOf<FeatMinMaxRecord> - featMinMaxRecords; /* Array of FeatMinMaxRecords, in alphabetical - * order by featureTableTag */ + OffsetTo<BaseCoord> + minCoord; /* Offset to BaseCoord table that defines + * minimum extent value, from the beginning + * of MinMax table (may be NULL) */ + OffsetTo<BaseCoord> + maxCoord; /* Offset to BaseCoord table that defines + * maximum extent value, from the beginning + * of MinMax table (may be NULL) */ + SortedArrayOf<FeatMinMaxRecord> + featMinMaxRecords; + /* Array of FeatMinMaxRecords, in alphabetical + * order by featureTableTag */ public: DEFINE_SIZE_ARRAY (6, featMinMaxRecords); }; -/* TODO... */ -struct BaseLangSysRecord -{ - inline const Tag& get_tag(void) const - { return baseLangSysTag; } - - inline unsigned int get_feature_tag_index (Tag featureTableTag) const - { return (this+minMax).get_feature_tag_index(featureTableTag); } - - inline int get_min_value (unsigned int featureTableTagIndex) const - { return (this+minMax).get_min_value(featureTableTagIndex); } - - inline int get_max_value (unsigned int featureTableTagIndex) const - { return (this+minMax).get_max_value(featureTableTagIndex); } - - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - minMax.sanitize (c, base)); - } - - protected: - Tag baseLangSysTag; - OffsetTo<MinMax> minMax; - public: - DEFINE_SIZE_STATIC (6); - -}; - struct BaseValues { - inline unsigned int get_default_base_tag_index (void) const - { return defaultIndex; } - - inline int get_base_coord (unsigned int baselineTagIndex) const + const BaseCoord &get_base_coord (int baseline_tag_index) const { - return (this+baseCoords[baselineTagIndex]).get_coord(); + if (baseline_tag_index == -1) baseline_tag_index = defaultIndex; + return this+baseCoords[baseline_tag_index]; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - defaultIndex <= baseCoordCount && - baseCoords.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + baseCoords.sanitize (c, this))); } protected: - Index defaultIndex; - HBUINT16 baseCoordCount; - OffsetArrayOf<BaseCoord> baseCoords; + Index defaultIndex; /* Index number of default baseline for this + * script — equals index position of baseline tag + * in baselineTags array of the BaseTagList */ + OffsetArrayOf<BaseCoord> + baseCoords; /* Number of BaseCoord tables defined — should equal + * baseTagCount in the BaseTagList + * + * Array of offsets to BaseCoord tables, from beginning of + * BaseValues table — order matches baselineTags array in + * the BaseTagList */ public: - DEFINE_SIZE_ARRAY (6, baseCoords); - + DEFINE_SIZE_ARRAY (4, baseCoords); }; -struct BaseScript { - - inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const - { - Tag tag; - int cmp; - for (unsigned int i = 0; i < baseLangSysCount; i++) { - tag = baseLangSysRecords[i].get_tag(); - // taking advantage of alphabetical order - cmp = tag.cmp(baseLangSysTag); - if (cmp == 0) return i; - if (cmp > 0) return NOT_INDEXED; - } - return NOT_INDEXED; - } - - inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const - { - if (baseLangSysIndex == NOT_INDEXED) { - if (unlikely(defaultMinMax)) return NOT_INDEXED; - return (this+defaultMinMax).get_feature_tag_index(featureTableTag); - } - if (unlikely(baseLangSysIndex >= baseLangSysCount)) return NOT_INDEXED; - return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index(featureTableTag); - } - - inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - if (baseLangSysIndex == NOT_INDEXED) - return (this+defaultMinMax).get_min_value(featureTableTagIndex); - return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex); - } - - inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const +struct BaseLangSysRecord +{ + static int cmp (const void *key_, const void *entry_) { - if (baseLangSysIndex == NOT_INDEXED) - return (this+defaultMinMax).get_min_value(featureTableTagIndex); - return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex); + hb_tag_t key = * (hb_tag_t *) key_; + const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_; + return key < (unsigned int) entry.baseLangSysTag ? -1 : + key > (unsigned int) entry.baseLangSysTag ? 1 : + 0; } - inline unsigned int get_default_base_tag_index (void) const - { return (this+baseValues).get_default_base_tag_index(); } + const MinMax &get_min_max () const + { return this+minMax; } - inline int get_base_coord (unsigned int baselineTagIndex) const - { return (this+baseValues).get_base_coord(baselineTagIndex); } - - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - baseValues.sanitize (c, this) && - defaultMinMax.sanitize (c, this) && - baseLangSysRecords.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + minMax.sanitize (c, this))); } protected: - OffsetTo<BaseValues> baseValues; - OffsetTo<MinMax> defaultMinMax; - HBUINT16 baseLangSysCount; - ArrayOf<BaseLangSysRecord> baseLangSysRecords; - + Tag baseLangSysTag; /* 4-byte language system identification tag */ + OffsetTo<MinMax> + minMax; /* Offset to MinMax table, from beginning + * of BaseScript table */ public: - DEFINE_SIZE_ARRAY (8, baseLangSysRecords); + DEFINE_SIZE_STATIC (6); }; +struct BaseScript +{ + const MinMax &get_min_max (hb_tag_t language_tag) const + { + /* TODO Replace hb_bsearch() with .bsearch(). */ + const BaseLangSysRecord* record = (const BaseLangSysRecord *) + hb_bsearch (&language_tag, baseLangSysRecords.arrayZ, + baseLangSysRecords.len, + BaseLangSysRecord::static_size, + BaseLangSysRecord::cmp); + return record ? record->get_min_max () : this+defaultMinMax; + } -struct BaseScriptRecord { - - inline const Tag& get_tag (void) const - { return baseScriptTag; } - - inline unsigned int get_default_base_tag_index(void) const - { return (this+baseScript).get_default_base_tag_index(); } - - inline int get_base_coord(unsigned int baselineTagIndex) const - { return (this+baseScript).get_base_coord(baselineTagIndex); } - - inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const - { return (this+baseScript).get_lang_tag_index(baseLangSysTag); } - - inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const - { return (this+baseScript).get_feature_tag_index(baseLangSysIndex, featureTableTag); } - - inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { return (this+baseScript).get_max_value(baseLangSysIndex, featureTableTagIndex); } + const BaseCoord &get_base_coord (int baseline_tag_index) const + { return (this+baseValues).get_base_coord (baseline_tag_index); } - inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { return (this+baseScript).get_min_value(baseLangSysIndex, featureTableTagIndex); } + bool is_empty () const { return !baseValues; } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - baseScript != Null(OffsetTo<BaseScript>) && - baseScript.sanitize (c, base)); + return_trace (likely (c->check_struct (this) && + baseValues.sanitize (c, this) && + defaultMinMax.sanitize (c, this) && + baseLangSysRecords.sanitize (c, this))); } protected: - Tag baseScriptTag; - OffsetTo<BaseScript> baseScript; + OffsetTo<BaseValues> + baseValues; /* Offset to BaseValues table, from beginning + * of BaseScript table (may be NULL) */ + OffsetTo<MinMax> + defaultMinMax; /* Offset to MinMax table, from beginning of + * BaseScript table (may be NULL) */ + SortedArrayOf<BaseLangSysRecord> + baseLangSysRecords; + /* Number of BaseLangSysRecords + * defined — may be zero (0) */ public: - DEFINE_SIZE_STATIC (6); + DEFINE_SIZE_ARRAY (6, baseLangSysRecords); }; -struct BaseScriptList { - - inline unsigned int get_base_script_index (Tag baseScriptTag) const - { - for (unsigned int i = 0; i < baseScriptCount; i++) - if (baseScriptRecords[i].get_tag() == baseScriptTag) - return i; - return NOT_INDEXED; - } - - inline unsigned int get_default_base_tag_index (unsigned int baseScriptIndex) const - { - if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; - return baseScriptRecords[baseScriptIndex].get_default_base_tag_index(); - } - - inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const - { - return baseScriptRecords[baseScriptIndex].get_base_coord(baselineTagIndex); - } - - inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const - { - if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; - return baseScriptRecords[baseScriptIndex].get_lang_tag_index(baseLangSysTag); - } - - inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const - { - if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; - return baseScriptRecords[baseScriptIndex].get_feature_tag_index(baseLangSysIndex, featureTableTag); - } - - inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const +struct BaseScriptList; +struct BaseScriptRecord +{ + static int cmp (const void *key_, const void *entry_) { - return baseScriptRecords[baseScriptIndex].get_max_value(baseLangSysIndex, featureTableTagIndex); + hb_tag_t key = * (hb_tag_t *) key_; + const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_; + return key < (unsigned int) entry.baseScriptTag ? -1 : + key > (unsigned int) entry.baseScriptTag ? 1 : + 0; } - inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return baseScriptRecords[baseScriptIndex].get_min_value(baseLangSysIndex, featureTableTagIndex); - } + const BaseScript &get_base_script (const BaseScriptList *list) const + { return list+baseScript; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - baseScriptRecords.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + baseScript.sanitize (c, base))); } protected: - HBUINT16 baseScriptCount; - ArrayOf<BaseScriptRecord> baseScriptRecords; + Tag baseScriptTag; /* 4-byte script identification tag */ + OffsetTo<BaseScript> + baseScript; /* Offset to BaseScript table, from beginning + * of BaseScriptList */ public: - DEFINE_SIZE_ARRAY (4, baseScriptRecords); - + DEFINE_SIZE_STATIC (6); }; -struct BaseTagList +struct BaseScriptList { + const BaseScriptRecord *find_record (hb_tag_t script) const + { + /* TODO Replace hb_bsearch() with .bsearch(). */ + return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ, + baseScriptRecords.len, + BaseScriptRecord::static_size, + BaseScriptRecord::cmp); + } - inline unsigned int get_tag_index(Tag baselineTag) const + /* TODO: Or client should handle fallback? */ + const BaseScript &get_base_script (hb_tag_t script) const { - for (unsigned int i = 0; i < baseTagCount; i++) - if (baselineTags[i] == baselineTag) - return i; - return NOT_INDEXED; + const BaseScriptRecord *record = find_record (script); + if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T')); + + return record ? record->get_base_script (this) : Null (BaseScript); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + return_trace (c->check_struct (this) && + baseScriptRecords.sanitize (c, this)); } protected: - HBUINT16 baseTagCount; - SortedArrayOf<Tag> baselineTags; + SortedArrayOf<BaseScriptRecord> + baseScriptRecords; public: - DEFINE_SIZE_ARRAY (4, baselineTags); + DEFINE_SIZE_ARRAY (2, baseScriptRecords); }; struct Axis { - - inline unsigned int get_base_tag_index(Tag baselineTag) const + bool get_baseline (hb_ot_layout_baseline_t baseline, + hb_tag_t script_tag, + hb_tag_t language_tag, + const BaseCoord **coord) const { - if (unlikely(baseTagList == Null(OffsetTo<BaseTagList>))) return NOT_INDEXED; - return (this+baseTagList).get_tag_index(baselineTag); - } + const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); + if (base_script.is_empty ()) return false; - inline unsigned int get_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const - { - if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED; - return (this+baseScriptList).get_default_base_tag_index(baseScriptIndex); - } - - inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const - { - return (this+baseScriptList).get_base_coord(baseScriptIndex, baselineTagIndex); - } + if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline)); - inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const - { - if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED; - return (this+baseScriptList).get_lang_tag_index(baseScriptIndex, baseLangSysTag); + return true; } - inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const + bool get_min_max (hb_tag_t script_tag, + hb_tag_t language_tag, + hb_tag_t feature_tag, + const BaseCoord **min_coord, + const BaseCoord **max_coord) const { - if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED; - return (this+baseScriptList).get_feature_tag_index(baseScriptIndex, baseLangSysIndex, featureTableTag); - } + const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); + if (base_script.is_empty ()) return false; - inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+baseScriptList).get_max_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex); - } + base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord); - inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+baseScriptList).get_min_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + return true; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - baseTagList.sanitize (c, this) && - baseScriptList.sanitize (c, this)); + return_trace (likely (c->check_struct (this) && + (this+baseTagList).sanitize (c) && + (this+baseScriptList).sanitize (c))); } protected: - OffsetTo<BaseTagList> baseTagList; - OffsetTo<BaseScriptList> baseScriptList; + OffsetTo<SortedArrayOf<Tag> > + baseTagList; /* Offset to BaseTagList table, from beginning + * of Axis table (may be NULL) + * Array of 4-byte baseline identification tags — must + * be in alphabetical order */ + OffsetTo<BaseScriptList> + baseScriptList; /* Offset to BaseScriptList table, from beginning + * of Axis table + * Array of BaseScriptRecords, in alphabetical order + * by baseScriptTag */ public: DEFINE_SIZE_STATIC (4); @@ -532,119 +464,72 @@ struct Axis struct BASE { - static const hb_tag_t tableTag = HB_OT_TAG_BASE; - - inline bool has_vert_axis(void) - { return vertAxis != Null(OffsetTo<Axis>); } + static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE; - inline bool has_horiz_axis(void) - { return horizAxis != Null(OffsetTo<Axis>); } + const Axis &get_axis (hb_direction_t direction) const + { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; } - // horizontal axis base coords: + const VariationStore &get_var_store () const + { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; } - inline unsigned int get_horiz_base_tag_index(Tag baselineTag) const + bool get_baseline (hb_font_t *font, + hb_ot_layout_baseline_t baseline, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *base) const { - if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+horizAxis).get_base_tag_index(baselineTag); - } + const BaseCoord *base_coord; + if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord)) + return false; - inline unsigned int get_horiz_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const - { - if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+horizAxis).get_default_base_tag_index_for_script_index(baseScriptIndex); + if (likely (base && base_coord)) *base = base_coord->get_coord (font, + get_var_store (), + direction); + return true; } - inline int get_horiz_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const + /* TODO: Expose this separately sometime? */ + bool get_min_max (hb_font_t *font, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_tag_t feature_tag, + hb_position_t *min, + hb_position_t *max) { - return (this+horizAxis).get_base_coord(baseScriptIndex, baselineTagIndex); - } - - // vertical axis base coords: - - inline unsigned int get_vert_base_tag_index(Tag baselineTag) const - { - if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+vertAxis).get_base_tag_index(baselineTag); - } - - inline unsigned int get_vert_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const - { - if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+vertAxis).get_default_base_tag_index_for_script_index(baseScriptIndex); - } - - inline int get_vert_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const - { - return (this+vertAxis).get_base_coord(baseScriptIndex, baselineTagIndex); - } - - // horizontal axis min/max coords: - - inline unsigned int get_horiz_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const - { - if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+horizAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag); - } - - inline unsigned int get_horiz_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const - { - if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+horizAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag); - } + const BaseCoord *min_coord, *max_coord; + if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag, + &min_coord, &max_coord)) + return false; - inline int get_horiz_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+horizAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); - } - - inline int get_horiz_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+horizAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); - } - - // vertical axis min/max coords: - - inline unsigned int get_vert_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const - { - if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+vertAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag); - } - - inline unsigned int get_vert_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const - { - if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED; - return (this+vertAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag); - } - - inline int get_vert_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+vertAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + const VariationStore &var_store = get_var_store (); + if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction); + if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction); + return true; } - inline int get_vert_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const - { - return (this+vertAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); - } - - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - likely (version.major == 1) && - horizAxis.sanitize (c, this) && - vertAxis.sanitize (c, this) && - (version.to_int () < 0x00010001u || varStore.sanitize (c, this))); + return_trace (likely (c->check_struct (this) && + likely (version.major == 1) && + hAxis.sanitize (c, this) && + vAxis.sanitize (c, this) && + (version.to_int () < 0x00010001u || varStore.sanitize (c, this)))); } protected: - FixedVersion<> version; - OffsetTo<Axis> horizAxis; - OffsetTo<Axis> vertAxis; + FixedVersion<>version; /* Version of the BASE table */ + OffsetTo<Axis>hAxis; /* Offset to horizontal Axis table, from beginning + * of BASE table (may be NULL) */ + OffsetTo<Axis>vAxis; /* Offset to vertical Axis table, from beginning + * of BASE table (may be NULL) */ LOffsetTo<VariationStore> - varStore; /* Offset to the table of Item Variation - * Store--from beginning of BASE - * header (may be NULL). Introduced - * in version 0x00010001. */ + varStore; /* Offset to the table of Item Variation + * Store--from beginning of BASE + * header (may be NULL). Introduced + * in version 0x00010001. */ public: DEFINE_SIZE_MIN (8); }; diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common.hh index 763ea92..39a8bba 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common.hh @@ -26,14 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH -#define HB_OT_LAYOUT_COMMON_PRIVATE_HH +#ifndef HB_OT_LAYOUT_COMMON_HH +#define HB_OT_LAYOUT_COMMON_HH -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-ot-layout-private.hh" -#include "hb-open-type-private.hh" -#include "hb-set-private.hh" +#include "hb.hh" +#include "hb-ot-layout.hh" +#include "hb-open-type.hh" +#include "hb-set.hh" #ifndef HB_MAX_NESTING_LEVEL @@ -42,6 +41,23 @@ #ifndef HB_MAX_CONTEXT_LENGTH #define HB_MAX_CONTEXT_LENGTH 64 #endif +#ifndef HB_CLOSURE_MAX_STAGES +/* + * The maximum number of times a lookup can be applied during shaping. + * Used to limit the number of iterations of the closure algorithm. + * This must be larger than the number of times add_pause() is + * called in a collect_features call of any shaper. + */ +#define HB_CLOSURE_MAX_STAGES 32 +#endif + +#ifndef HB_MAX_SCRIPTS +#define HB_MAX_SCRIPTS 500 +#endif + +#ifndef HB_MAX_LANGSYS +#define HB_MAX_LANGSYS 2000 +#endif namespace OT { @@ -62,21 +78,20 @@ namespace OT { * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList */ +struct Record_sanitize_closure_t { + hb_tag_t tag; + const void *list_base; +}; + template <typename Type> struct Record { - inline int cmp (hb_tag_t a) const { - return tag.cmp (a); - } + int cmp (hb_tag_t a) const { return tag.cmp (a); } - struct sanitize_closure_t { - hb_tag_t tag; - const void *list_base; - }; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - const sanitize_closure_t closure = {tag, base}; + const Record_sanitize_closure_t closure = {tag, base}; return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); } @@ -89,18 +104,17 @@ struct Record }; template <typename Type> -struct RecordArrayOf : SortedArrayOf<Record<Type> > { - inline const Tag& get_tag (unsigned int i) const - { - /* We cheat slightly and don't define separate Null objects - * for Record types. Instead, we return the correct Null(Tag) - * here. */ - if (unlikely (i >= this->len)) return Null(Tag); - return (*this)[i].tag; - } - inline unsigned int get_tags (unsigned int start_offset, - unsigned int *record_count /* IN/OUT */, - hb_tag_t *record_tags /* OUT */) const +struct RecordArrayOf : SortedArrayOf<Record<Type> > +{ + const OffsetTo<Type>& get_offset (unsigned int i) const + { return (*this)[i].offset; } + OffsetTo<Type>& get_offset (unsigned int i) + { return (*this)[i].offset; } + const Tag& get_tag (unsigned int i) const + { return (*this)[i].tag; } + unsigned int get_tags (unsigned int start_offset, + unsigned int *record_count /* IN/OUT */, + hb_tag_t *record_tags /* OUT */) const { if (record_count) { const Record<Type> *arr = this->sub_array (start_offset, record_count); @@ -110,27 +124,30 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > { } return this->len; } - inline bool find_index (hb_tag_t tag, unsigned int *index) const + bool find_index (hb_tag_t tag, unsigned int *index) const { - /* If we want to allow non-sorted data, we can lsearch(). */ - int i = this->/*lsearch*/bsearch (tag); - if (i != -1) { - if (index) *index = i; - return true; - } else { - if (index) *index = Index::NOT_FOUND_INDEX; - return false; - } + return this->bfind (tag, index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); } }; template <typename Type> struct RecordListOf : RecordArrayOf<Type> { - inline const Type& operator [] (unsigned int i) const - { return this+RecordArrayOf<Type>::operator [](i).offset; } + const Type& operator [] (unsigned int i) const + { return this+this->get_offset (i); } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct RecordListOf<Type> *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + unsigned int count = this->len; + for (unsigned int i = 0; i < count; i++) + out->get_offset (i).serialize_subset (c, (*this)[i], out); + return_trace (true); + } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (RecordArrayOf<Type>::sanitize (c, this)); @@ -140,24 +157,21 @@ struct RecordListOf : RecordArrayOf<Type> struct RangeRecord { - inline int cmp (hb_codepoint_t g) const { - return g < start ? -1 : g <= end ? 0 : +1 ; - } + int cmp (hb_codepoint_t g) const + { return g < start ? -1 : g <= end ? 0 : +1; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - inline bool intersects (const hb_set_t *glyphs) const { - return glyphs->intersects (start, end); - } + bool intersects (const hb_set_t *glyphs) const + { return glyphs->intersects (start, end); } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { - return glyphs->add_range (start, end); - } + bool add_coverage (set_t *glyphs) const + { return glyphs->add_range (start, end); } GlyphID start; /* First GlyphID in the range */ GlyphID end; /* Last GlyphID in the range */ @@ -165,14 +179,14 @@ struct RangeRecord public: DEFINE_SIZE_STATIC (6); }; -DEFINE_NULL_DATA (OT, RangeRecord, "\000\001"); +DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord); struct IndexArray : ArrayOf<Index> { - inline unsigned int get_indexes (unsigned int start_offset, - unsigned int *_count /* IN/OUT */, - unsigned int *_indexes /* OUT */) const + unsigned int get_indexes (unsigned int start_offset, + unsigned int *_count /* IN/OUT */, + unsigned int *_indexes /* OUT */) const { if (_count) { const HBUINT16 *arr = this->sub_array (start_offset, _count); @@ -182,6 +196,11 @@ struct IndexArray : ArrayOf<Index> } return this->len; } + + void add_indexes_to (hb_set_t* output /* OUT */) const + { + output->add_array (arrayZ, len); + } }; @@ -192,25 +211,33 @@ struct Feature; struct LangSys { - inline unsigned int get_feature_count (void) const + unsigned int get_feature_count () const { return featureIndex.len; } - inline hb_tag_t get_feature_index (unsigned int i) const + hb_tag_t get_feature_index (unsigned int i) const { return featureIndex[i]; } - inline unsigned int get_feature_indexes (unsigned int start_offset, - unsigned int *feature_count /* IN/OUT */, - unsigned int *feature_indexes /* OUT */) const + unsigned int get_feature_indexes (unsigned int start_offset, + unsigned int *feature_count /* IN/OUT */, + unsigned int *feature_indexes /* OUT */) const { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } + void add_feature_indexes_to (hb_set_t *feature_indexes) const + { featureIndex.add_indexes_to (feature_indexes); } - inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; } - inline unsigned int get_required_feature_index (void) const + bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; } + unsigned int get_required_feature_index () const { if (reqFeatureIndex == 0xFFFFu) return Index::NOT_FOUND_INDEX; return reqFeatureIndex;; } - inline bool sanitize (hb_sanitize_context_t *c, - const Record<LangSys>::sanitize_closure_t * = nullptr) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (c->serializer->embed (*this)); + } + + bool sanitize (hb_sanitize_context_t *c, + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && featureIndex.sanitize (c)); @@ -223,34 +250,45 @@ struct LangSys * = 0xFFFFu */ IndexArray featureIndex; /* Array of indices into the FeatureList */ public: - DEFINE_SIZE_ARRAY (6, featureIndex); + DEFINE_SIZE_ARRAY_SIZED (6, featureIndex); }; -DEFINE_NULL_DATA (OT, LangSys, "\0\0\xFF\xFF"); - +DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys); struct Script { - inline unsigned int get_lang_sys_count (void) const + unsigned int get_lang_sys_count () const { return langSys.len; } - inline const Tag& get_lang_sys_tag (unsigned int i) const + const Tag& get_lang_sys_tag (unsigned int i) const { return langSys.get_tag (i); } - inline unsigned int get_lang_sys_tags (unsigned int start_offset, - unsigned int *lang_sys_count /* IN/OUT */, - hb_tag_t *lang_sys_tags /* OUT */) const + unsigned int get_lang_sys_tags (unsigned int start_offset, + unsigned int *lang_sys_count /* IN/OUT */, + hb_tag_t *lang_sys_tags /* OUT */) const { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } - inline const LangSys& get_lang_sys (unsigned int i) const + const LangSys& get_lang_sys (unsigned int i) const { if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); return this+langSys[i].offset; } - inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const + bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const { return langSys.find_index (tag, index); } - inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } - inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } + bool has_default_lang_sys () const { return defaultLangSys != 0; } + const LangSys& get_default_lang_sys () const { return this+defaultLangSys; } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Script *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out); + unsigned int count = langSys.len; + for (unsigned int i = 0; i < count; i++) + out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out); + return_trace (true); + } - inline bool sanitize (hb_sanitize_context_t *c, - const Record<Script>::sanitize_closure_t * = nullptr) const + bool sanitize (hb_sanitize_context_t *c, + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); @@ -264,7 +302,7 @@ struct Script langSys; /* Array of LangSysRecords--listed * alphabetically by LangSysTag */ public: - DEFINE_SIZE_ARRAY (4, langSys); + DEFINE_SIZE_ARRAY_SIZED (4, langSys); }; typedef RecordListOf<Script> ScriptList; @@ -273,7 +311,7 @@ typedef RecordListOf<Script> ScriptList; /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ struct FeatureParamsSize { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); @@ -358,7 +396,7 @@ struct FeatureParamsSize * same subfamily value. If this value is * zero, the remaining fields in the array * will be ignored. */ - HBUINT16 subfamilyNameID;/* If the preceding value is non-zero, this + NameID subfamilyNameID;/* If the preceding value is non-zero, this * value must be set in the range 256 - 32767 * (inclusive). It records the value of a * field in the name table, which must @@ -385,7 +423,7 @@ struct FeatureParamsSize /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */ struct FeatureParamsStylisticSet { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Right now minorVersion is at zero. Which means, any table supports @@ -419,7 +457,7 @@ struct FeatureParamsStylisticSet /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */ struct FeatureParamsCharacterVariants { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -431,7 +469,7 @@ struct FeatureParamsCharacterVariants * specifies a string (or strings, * for multiple languages) for a * user-interface label for this - * feature. (May be nullptr.) */ + * feature. (May be NULL.) */ NameID featUITooltipTextNameID;/* The ‘name’ table name ID that * specifies a string (or strings, * for multiple languages) that an @@ -441,7 +479,7 @@ struct FeatureParamsCharacterVariants NameID sampleTextNameID; /* The ‘name’ table name ID that * specifies sample text that * illustrates the effect of this - * feature. (May be nullptr.) */ + * feature. (May be NULL.) */ HBUINT16 numNamedParameters; /* Number of named parameters. (May * be zero.) */ NameID firstParamUILabelNameID;/* The first ‘name’ table name ID @@ -460,7 +498,7 @@ struct FeatureParamsCharacterVariants struct FeatureParams { - inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const + bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const { TRACE_SANITIZE (this); if (tag == HB_TAG ('s','i','z','e')) @@ -472,11 +510,25 @@ struct FeatureParams return_trace (true); } - inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const + const FeatureParamsSize& get_size_params (hb_tag_t tag) const { if (tag == HB_TAG ('s','i','z','e')) return u.size; - return Null(FeatureParamsSize); + return Null (FeatureParamsSize); + } + + const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const + { + if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return u.stylisticSet; + return Null (FeatureParamsStylisticSet); + } + + const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const + { + if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return u.characterVariants; + return Null (FeatureParamsCharacterVariants); } private: @@ -485,25 +537,37 @@ struct FeatureParams FeatureParamsStylisticSet stylisticSet; FeatureParamsCharacterVariants characterVariants; } u; + public: DEFINE_SIZE_STATIC (17); }; struct Feature { - inline unsigned int get_lookup_count (void) const + unsigned int get_lookup_count () const { return lookupIndex.len; } - inline hb_tag_t get_lookup_index (unsigned int i) const + hb_tag_t get_lookup_index (unsigned int i) const { return lookupIndex[i]; } - inline unsigned int get_lookup_indexes (unsigned int start_index, - unsigned int *lookup_count /* IN/OUT */, - unsigned int *lookup_tags /* OUT */) const + unsigned int get_lookup_indexes (unsigned int start_index, + unsigned int *lookup_count /* IN/OUT */, + unsigned int *lookup_tags /* OUT */) const { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } + void add_lookup_indexes_to (hb_set_t *lookup_indexes) const + { lookupIndex.add_indexes_to (lookup_indexes); } - inline const FeatureParams &get_feature_params (void) const + const FeatureParams &get_feature_params () const { return this+featureParams; } - inline bool sanitize (hb_sanitize_context_t *c, - const Record<Feature>::sanitize_closure_t *closure = nullptr) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Feature *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + out->featureParams.set (0); /* TODO(subset) FeatureParams. */ + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c, + const Record_sanitize_closure_t *closure = nullptr) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) @@ -541,9 +605,6 @@ struct Feature c->try_set (&featureParams, new_offset) && !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) return_trace (false); - - if (c->edit_count > 1) - c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */ } return_trace (true); @@ -556,7 +617,7 @@ struct Feature * if not required */ IndexArray lookupIndex; /* Array of LookupList indices */ public: - DEFINE_SIZE_ARRAY (4, lookupIndex); + DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex); }; typedef RecordListOf<Feature> FeatureList; @@ -585,25 +646,33 @@ namespace OT { struct Lookup { - inline unsigned int get_subtable_count (void) const { return subTable.len; } + unsigned int get_subtable_count () const { return subTable.len; } + + template <typename TSubTable> + const TSubTable& get_subtable (unsigned int i) const + { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; } - template <typename SubTableType> - inline const SubTableType& get_subtable (unsigned int i) const - { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; } + template <typename TSubTable> + const OffsetArrayOf<TSubTable>& get_subtables () const + { return CastR<OffsetArrayOf<TSubTable> > (subTable); } + template <typename TSubTable> + OffsetArrayOf<TSubTable>& get_subtables () + { return CastR<OffsetArrayOf<TSubTable> > (subTable); } - template <typename SubTableType> - inline const OffsetArrayOf<SubTableType>& get_subtables (void) const - { return CastR<OffsetArrayOf<SubTableType> > (subTable); } - template <typename SubTableType> - inline OffsetArrayOf<SubTableType>& get_subtables (void) - { return CastR<OffsetArrayOf<SubTableType> > (subTable); } + unsigned int get_size () const + { + const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable); + if (lookupFlag & LookupFlag::UseMarkFilteringSet) + return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this; + return (const char *) &markFilteringSet - (const char *) this; + } - inline unsigned int get_type (void) const { return lookupType; } + unsigned int get_type () const { return lookupType; } /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and * higher 16-bit is mark-filtering-set if the lookup uses one. * Not to be confused with glyph_props which is very similar. */ - inline uint32_t get_props (void) const + uint32_t get_props () const { unsigned int flag = lookupFlag; if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) @@ -614,24 +683,24 @@ struct Lookup return flag; } - template <typename SubTableType, typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + template <typename TSubTable, typename context_t> + typename context_t::return_t dispatch (context_t *c) const { unsigned int lookup_type = get_type (); TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); + typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type); if (c->stop_sublookup_iteration (r)) - return_trace (r); + return_trace (r); } return_trace (c->default_return_value ()); } - inline bool serialize (hb_serialize_context_t *c, - unsigned int lookup_type, - uint32_t lookup_props, - unsigned int num_subtables) + bool serialize (hb_serialize_context_t *c, + unsigned int lookup_type, + uint32_t lookup_props, + unsigned int num_subtables) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -640,22 +709,89 @@ struct Lookup if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { + if (unlikely (!c->extend (*this))) return_trace (false); HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); markFilteringSet.set (lookup_props >> 16); } return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + /* Older compilers need this to NOT be locally defined in a function. */ + template <typename TSubTable> + struct SubTableSubsetWrapper + { + SubTableSubsetWrapper (const TSubTable &subtable_, + unsigned int lookup_type_) : + subtable (subtable_), + lookup_type (lookup_type_) {} + + bool subset (hb_subset_context_t *c) const + { return subtable.dispatch (c, lookup_type); } + + private: + const TSubTable &subtable; + unsigned int lookup_type; + }; + + template <typename TSubTable> + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Lookup *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + /* Subset the actual subtables. */ + /* TODO Drop empty ones, either by calling intersects() beforehand, + * or just dropping null offsets after. */ + const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> (); + OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> (); + unsigned int count = subTable.len; + for (unsigned int i = 0; i < count; i++) + { + SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ()); + + out_subtables[i].serialize_subset (c, wrapper, out); + } + + return_trace (true); + } + + /* Older compilers need this to NOT be locally defined in a function. */ + template <typename TSubTable> + struct SubTableSanitizeWrapper : TSubTable + { + bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const + { return this->dispatch (c, lookup_type); } + }; + + template <typename TSubTable> + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* Real sanitize of the subtables is done by GSUB/GPOS/... */ if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); if (!markFilteringSet.sanitize (c)) return_trace (false); } + + if (unlikely (!CastR<OffsetArrayOf<SubTableSanitizeWrapper<TSubTable> > > (subTable) + .sanitize (c, this, get_type ()))) + return_trace (false); + + if (unlikely (get_type () == TSubTable::Extension)) + { + /* The spec says all subtables of an Extension lookup should + * have the same type, which shall not be the Extension type + * itself (but we already checked for that). + * This is specially important if one has a reverse type! */ + unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 1; i < count; i++) + if (get_subtable<TSubTable> (i).u.extension.get_type () != type) + return_trace (false); + } + return_trace (true); return_trace (true); } @@ -664,11 +800,11 @@ struct Lookup HBUINT16 lookupFlag; /* Lookup qualifiers */ ArrayOf<Offset16> subTable; /* Array of SubTables */ - HBUINT16 markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets +/*HBUINT16 markFilteringSetX[VAR];*//* Index (base 0) into GDEF mark glyph sets * structure. This field is only present if bit * UseMarkFilteringSet of lookup flags is set. */ public: - DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); + DEFINE_SIZE_ARRAY (6, subTable); }; typedef OffsetListOf<Lookup> LookupList; @@ -683,50 +819,53 @@ struct CoverageFormat1 friend struct Coverage; private: - inline unsigned int get_coverage (hb_codepoint_t glyph_id) const + unsigned int get_coverage (hb_codepoint_t glyph_id) const { - int i = glyphArray.bsearch (glyph_id); - static_assert ((((unsigned int) -1) == NOT_COVERED), ""); + unsigned int i; + glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED); return i; } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - glyphArray.len.set (num_glyphs); - if (unlikely (!c->extend (glyphArray))) return_trace (false); - for (unsigned int i = 0; i < num_glyphs; i++) - glyphArray[i] = glyphs[i]; - glyphs += num_glyphs; - return_trace (true); + return_trace (glyphArray.serialize (c, glyphs)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (glyphArray.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - return glyphs->has (glyphArray[index]); + bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = glyphArray.len; + for (unsigned int i = 0; i < count; i++) + if (glyphs->has (glyphArray[i])) + return true; + return false; } + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { return glyphs->has (glyphArray[index]); } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + bool add_coverage (set_t *glyphs) const + { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); } public: /* Older compilers need this to be public. */ struct Iter { - inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; - inline bool more (void) { return i < c->glyphArray.len; } - inline void next (void) { i++; } - inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; } - inline unsigned int get_coverage (void) { return i; } + void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; } + void fini () {} + bool more () { return i < c->glyphArray.len; } + void next () { i++; } + hb_codepoint_t get_glyph () { return c->glyphArray[i]; } + unsigned int get_coverage () { return i; } private: const struct CoverageFormat1 *c; @@ -747,59 +886,66 @@ struct CoverageFormat2 friend struct Coverage; private: - inline unsigned int get_coverage (hb_codepoint_t glyph_id) const + unsigned int get_coverage (hb_codepoint_t glyph_id) const { - int i = rangeRecord.bsearch (glyph_id); - if (i != -1) { - const RangeRecord &range = rangeRecord[i]; - return (unsigned int) range.value + (glyph_id - range.start); - } - return NOT_COVERED; + const RangeRecord &range = rangeRecord.bsearch (glyph_id); + return likely (range.start <= range.end) ? + (unsigned int) range.value + (glyph_id - range.start) : + NOT_COVERED; } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!num_glyphs)) + if (unlikely (!glyphs.length)) { rangeRecord.len.set (0); return_trace (true); } unsigned int num_ranges = 1; - for (unsigned int i = 1; i < num_glyphs; i++) + for (unsigned int i = 1; i < glyphs.length; i++) if (glyphs[i - 1] + 1 != glyphs[i]) - num_ranges++; + num_ranges++; rangeRecord.len.set (num_ranges); if (unlikely (!c->extend (rangeRecord))) return_trace (false); unsigned int range = 0; rangeRecord[range].start = glyphs[0]; rangeRecord[range].value.set (0); - for (unsigned int i = 1; i < num_glyphs; i++) - if (glyphs[i - 1] + 1 != glyphs[i]) { + for (unsigned int i = 1; i < glyphs.length; i++) + { + if (glyphs[i - 1] + 1 != glyphs[i]) + { range++; rangeRecord[range].start = glyphs[i]; rangeRecord[range].value.set (i); - rangeRecord[range].end = glyphs[i]; - } else { - rangeRecord[range].end = glyphs[i]; } - glyphs += num_glyphs; + rangeRecord[range].end = glyphs[i]; + } return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (rangeRecord.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { + bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { unsigned int i; unsigned int count = rangeRecord.len; for (i = 0; i < count; i++) { @@ -807,19 +953,20 @@ struct CoverageFormat2 if (range.value <= index && index < (unsigned int) range.value + (range.end - range.start) && range.intersects (glyphs)) - return true; + return true; else if (index < range.value) - return false; + return false; } return false; } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + bool add_coverage (set_t *glyphs) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (unlikely (!rangeRecord[i].add_coverage (glyphs))) - return false; + return false; return true; } @@ -827,22 +974,35 @@ struct CoverageFormat2 /* Older compilers need this to be public. */ struct Iter { - inline void init (const CoverageFormat2 &c_) + void init (const CoverageFormat2 &c_) { c = &c_; coverage = 0; i = 0; - j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; + j = c->rangeRecord.len ? c->rangeRecord[0].start : 0; + if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end)) + { + /* Broken table. Skip. */ + i = c->rangeRecord.len; + } } - inline bool more (void) { return i < c->rangeRecord.len; } - inline void next (void) + void fini () {} + bool more () { return i < c->rangeRecord.len; } + void next () { if (j >= c->rangeRecord[i].end) { - i++; + i++; if (more ()) { + hb_codepoint_t old = j; j = c->rangeRecord[i].start; + if (unlikely (j <= old)) + { + /* Broken table. Skip. Important to avoid DoS. */ + i = c->rangeRecord.len; + return; + } coverage = c->rangeRecord[i].value; } return; @@ -850,12 +1010,13 @@ struct CoverageFormat2 coverage++; j++; } - inline hb_codepoint_t get_glyph (void) { return j; } - inline unsigned int get_coverage (void) { return coverage; } + hb_codepoint_t get_glyph () { return j; } + unsigned int get_coverage () { return coverage; } private: const struct CoverageFormat2 *c; - unsigned int i, j, coverage; + unsigned int i, coverage; + hb_codepoint_t j; }; private: @@ -871,7 +1032,7 @@ struct CoverageFormat2 struct Coverage { - inline unsigned int get_coverage (hb_codepoint_t glyph_id) const + unsigned int get_coverage (hb_codepoint_t glyph_id) const { switch (u.format) { case 1: return u.format1.get_coverage (glyph_id); @@ -880,47 +1041,51 @@ struct Coverage } } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); + unsigned int num_ranges = 1; - for (unsigned int i = 1; i < num_glyphs; i++) + for (unsigned int i = 1; i < glyphs.length; i++) if (glyphs[i - 1] + 1 != glyphs[i]) - num_ranges++; - u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); - case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); + num_ranges++; + u.format.set (glyphs.length * 2 < num_ranges * 3 ? 1 : 2); + + switch (u.format) + { + case 1: return_trace (u.format1.serialize (c, glyphs)); + case 2: return_trace (u.format2.serialize (c, glyphs)); default:return_trace (false); } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); - switch (u.format) { + switch (u.format) + { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); default:return_trace (true); } } - inline bool intersects (const hb_set_t *glyphs) const { - /* TODO speed this up */ - Coverage::Iter iter; - for (iter.init (*this); iter.more (); iter.next ()) { - if (glyphs->has (iter.get_glyph ())) - return true; + bool intersects (const hb_set_t *glyphs) const + { + switch (u.format) + { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; } - return false; } - - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - switch (u.format) { + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { + switch (u.format) + { case 1: return u.format1.intersects_coverage (glyphs, index); case 2: return u.format2.intersects_coverage (glyphs, index); default:return false; @@ -930,47 +1095,60 @@ struct Coverage /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { - switch (u.format) { + bool add_coverage (set_t *glyphs) const + { + switch (u.format) + { case 1: return u.format1.add_coverage (glyphs); case 2: return u.format2.add_coverage (glyphs); default:return false; } } - struct Iter { - Iter (void) : format (0), u () {}; - inline void init (const Coverage &c_) { + struct Iter + { + Iter (const Coverage &c_) + { + memset (this, 0, sizeof (*this)); format = c_.u.format; - switch (format) { + switch (format) + { case 1: u.format1.init (c_.u.format1); return; case 2: u.format2.init (c_.u.format2); return; - default: return; + default: return; } } - inline bool more (void) { - switch (format) { + bool more () + { + switch (format) + { case 1: return u.format1.more (); case 2: return u.format2.more (); default:return false; } } - inline void next (void) { - switch (format) { + void next () + { + switch (format) + { case 1: u.format1.next (); break; case 2: u.format2.next (); break; - default: break; + default: break; } } - inline hb_codepoint_t get_glyph (void) { - switch (format) { + hb_codepoint_t get_glyph () + { + switch (format) + { case 1: return u.format1.get_glyph (); case 2: return u.format2.get_glyph (); default:return 0; } } - inline unsigned int get_coverage (void) { - switch (format) { + unsigned int get_coverage () + { + switch (format) + { case 1: return u.format1.get_coverage (); case 2: return u.format2.get_coverage (); default:return -1; @@ -1000,33 +1178,85 @@ struct Coverage * Class Definition Table */ +static inline void ClassDef_serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const HBUINT16> klasses); + struct ClassDefFormat1 { friend struct ClassDef; private: - inline unsigned int get_class (hb_codepoint_t glyph_id) const + unsigned int get_class (hb_codepoint_t glyph_id) const + { + return classValue[(unsigned int) (glyph_id - startGlyph)]; + } + + bool serialize (hb_serialize_context_t *c, + hb_array_t<const HBUINT16> glyphs, + hb_array_t<const HBUINT16> klasses) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + + if (unlikely (!glyphs.length)) + { + startGlyph.set (0); + classValue.len.set (0); + return_trace (true); + } + + hb_codepoint_t glyph_min = glyphs[0]; + hb_codepoint_t glyph_max = glyphs[glyphs.length - 1]; + + startGlyph.set (glyph_min); + classValue.len.set (glyph_max - glyph_min + 1); + if (unlikely (!c->extend (classValue))) return_trace (false); + + for (unsigned int i = 0; i < glyphs.length; i++) + classValue[glyphs[i] - glyph_min] = klasses[i]; + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const { - unsigned int i = (unsigned int) (glyph_id - startGlyph); - if (unlikely (i < classValue.len)) - return classValue[i]; - return 0; + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset; + const hb_map_t &glyph_map = *c->plan->glyph_map; + hb_vector_t<GlyphID> glyphs; + hb_vector_t<HBUINT16> klasses; + + hb_codepoint_t start = startGlyph; + hb_codepoint_t end = start + classValue.len; + for (hb_codepoint_t g = start; g < end; g++) + { + unsigned int value = classValue[g - start]; + if (!value) continue; + if (!glyphset.has (g)) continue; + glyphs.push()->set (glyph_map[g]); + klasses.push()->set (value); + } + c->serializer->propagate_error (glyphs, klasses); + ClassDef_serialize (c->serializer, glyphs, klasses); + return_trace (glyphs.length); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && classValue.sanitize (c)); } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + bool add_coverage (set_t *glyphs) const + { unsigned int start = 0; unsigned int count = classValue.len; for (unsigned int i = 0; i < count; i++) { if (classValue[i]) - continue; + continue; if (start != i) if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i))) @@ -1042,42 +1272,48 @@ struct ClassDefFormat1 } template <typename set_t> - inline bool add_class (set_t *glyphs, unsigned int klass) const { + bool add_class (set_t *glyphs, unsigned int klass) const + { unsigned int count = classValue.len; for (unsigned int i = 0; i < count; i++) - { - if (classValue[i] == klass) - glyphs->add (startGlyph + i); - } + if (classValue[i] == klass) glyphs->add (startGlyph + i); return true; } - inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next()? */ + hb_codepoint_t start = startGlyph; + hb_codepoint_t end = startGlyph + classValue.len; + for (hb_codepoint_t iter = startGlyph - 1; + hb_set_next (glyphs, &iter) && iter < end;) + if (classValue[iter - start]) return true; + return false; + } + bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const + { unsigned int count = classValue.len; if (klass == 0) { /* Match if there's any glyph that is not listed! */ hb_codepoint_t g = HB_SET_VALUE_INVALID; - if (!hb_set_next (glyphs, &g)) - return false; - if (g < startGlyph) - return true; + if (!hb_set_next (glyphs, &g)) return false; + if (g < startGlyph) return true; g = startGlyph + count - 1; - if (hb_set_next (glyphs, &g)) - return true; + if (hb_set_next (glyphs, &g)) return true; /* Fall through. */ } for (unsigned int i = 0; i < count; i++) if (classValue[i] == klass && glyphs->has (startGlyph + i)) - return true; + return true; return false; } protected: - HBUINT16 classFormat; /* Format identifier--format = 1 */ - GlyphID startGlyph; /* First GlyphID of the classValueArray */ + HBUINT16 classFormat; /* Format identifier--format = 1 */ + GlyphID startGlyph; /* First GlyphID of the classValueArray */ ArrayOf<HBUINT16> - classValue; /* Array of Class Values--one per GlyphID */ + classValue; /* Array of Class Values--one per GlyphID */ public: DEFINE_SIZE_ARRAY (6, classValue); }; @@ -1087,22 +1323,85 @@ struct ClassDefFormat2 friend struct ClassDef; private: - inline unsigned int get_class (hb_codepoint_t glyph_id) const + unsigned int get_class (hb_codepoint_t glyph_id) const + { + return rangeRecord.bsearch (glyph_id).value; + } + + bool serialize (hb_serialize_context_t *c, + hb_array_t<const HBUINT16> glyphs, + hb_array_t<const HBUINT16> klasses) { - int i = rangeRecord.bsearch (glyph_id); - if (unlikely (i != -1)) - return rangeRecord[i].value; - return 0; + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + + if (unlikely (!glyphs.length)) + { + rangeRecord.len.set (0); + return_trace (true); + } + + unsigned int num_ranges = 1; + for (unsigned int i = 1; i < glyphs.length; i++) + if (glyphs[i - 1] + 1 != glyphs[i] || + klasses[i - 1] != klasses[i]) + num_ranges++; + rangeRecord.len.set (num_ranges); + if (unlikely (!c->extend (rangeRecord))) return_trace (false); + + unsigned int range = 0; + rangeRecord[range].start = glyphs[0]; + rangeRecord[range].value.set (klasses[0]); + for (unsigned int i = 1; i < glyphs.length; i++) + { + if (glyphs[i - 1] + 1 != glyphs[i] || + klasses[i - 1] != klasses[i]) + { + range++; + rangeRecord[range].start = glyphs[i]; + rangeRecord[range].value = klasses[i]; + } + rangeRecord[range].end = glyphs[i]; + } + return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset; + const hb_map_t &glyph_map = *c->plan->glyph_map; + hb_vector_t<GlyphID> glyphs; + hb_vector_t<HBUINT16> klasses; + + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + { + unsigned int value = rangeRecord[i].value; + if (!value) continue; + hb_codepoint_t start = rangeRecord[i].start; + hb_codepoint_t end = rangeRecord[i].end + 1; + for (hb_codepoint_t g = start; g < end; g++) + { + if (!glyphset.has (g)) continue; + glyphs.push ()->set (glyph_map[g]); + klasses.push ()->set (value); + } + } + c->serializer->propagate_error (glyphs, klasses); + ClassDef_serialize (c->serializer, glyphs, klasses); + return_trace (glyphs.length); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (rangeRecord.sanitize (c)); } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + bool add_coverage (set_t *glyphs) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value) @@ -1112,18 +1411,29 @@ struct ClassDefFormat2 } template <typename set_t> - inline bool add_class (set_t *glyphs, unsigned int klass) const { + bool add_class (set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) { if (rangeRecord[i].value == klass) - if (unlikely (!rangeRecord[i].add_coverage (glyphs))) + if (unlikely (!rangeRecord[i].add_coverage (glyphs))) return false; } return true; } - inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; if (klass == 0) { @@ -1138,12 +1448,12 @@ struct ClassDefFormat2 g = rangeRecord[i].end; } if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) - return true; + return true; /* Fall through. */ } for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) - return true; + return true; return false; } @@ -1158,7 +1468,7 @@ struct ClassDefFormat2 struct ClassDef { - inline unsigned int get_class (hb_codepoint_t glyph_id) const + unsigned int get_class (hb_codepoint_t glyph_id) const { switch (u.format) { case 1: return u.format1.get_class (glyph_id); @@ -1167,7 +1477,49 @@ struct ClassDef } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const HBUINT16> klasses) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + + unsigned int format = 2; + if (glyphs.length) + { + hb_codepoint_t glyph_min = glyphs[0]; + hb_codepoint_t glyph_max = glyphs[glyphs.length - 1]; + + unsigned int num_ranges = 1; + for (unsigned int i = 1; i < glyphs.length; i++) + if (glyphs[i - 1] + 1 != glyphs[i] || + klasses[i - 1] != klasses[i]) + num_ranges++; + + if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3) + format = 1; + } + u.format.set (format); + + switch (u.format) + { + case 1: return_trace (u.format1.serialize (c, glyphs, klasses)); + case 2: return_trace (u.format2.serialize (c, glyphs, klasses)); + default:return_trace (false); + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c)); + case 2: return_trace (u.format2.subset (c)); + default:return_trace (false); + } + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -1181,7 +1533,8 @@ struct ClassDef /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + bool add_coverage (set_t *glyphs) const + { switch (u.format) { case 1: return u.format1.add_coverage (glyphs); case 2: return u.format2.add_coverage (glyphs); @@ -1192,7 +1545,8 @@ struct ClassDef /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename set_t> - inline bool add_class (set_t *glyphs, unsigned int klass) const { + bool add_class (set_t *glyphs, unsigned int klass) const + { switch (u.format) { case 1: return u.format1.add_class (glyphs, klass); case 2: return u.format2.add_class (glyphs, klass); @@ -1200,7 +1554,16 @@ struct ClassDef } } - inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + bool intersects (const hb_set_t *glyphs) const + { + switch (u.format) { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; + } + } + bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const + { switch (u.format) { case 1: return u.format1.intersects_class (glyphs, klass); case 2: return u.format2.intersects_class (glyphs, klass); @@ -1218,6 +1581,11 @@ struct ClassDef DEFINE_SIZE_UNION (2, format); }; +static inline void ClassDef_serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const HBUINT16> klasses) +{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); } + /* * Item Variation Store @@ -1225,7 +1593,7 @@ struct ClassDef struct VarRegionAxis { - inline float evaluate (int coord) const + float evaluate (int coord) const { int start = startCoord, peak = peakCoord, end = endCoord; @@ -1248,7 +1616,7 @@ struct VarRegionAxis return float (end - coord) / (end - peak); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -1266,8 +1634,8 @@ struct VarRegionAxis struct VarRegionList { - inline float evaluate (unsigned int region_index, - int *coords, unsigned int coord_len) const + float evaluate (unsigned int region_index, + const int *coords, unsigned int coord_len) const { if (unlikely (region_index >= regionCount)) return 0.; @@ -1281,19 +1649,21 @@ struct VarRegionList int coord = i < coord_len ? coords[i] : 0; float factor = axes[i].evaluate (coord); if (factor == 0.f) - return 0.; + return 0.; v *= factor; } return v; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount)); } + unsigned int get_region_count () const { return regionCount; } + protected: HBUINT16 axisCount; HBUINT16 regionCount; @@ -1305,14 +1675,17 @@ struct VarRegionList struct VarData { - inline unsigned int get_row_size (void) const + unsigned int get_region_index_count () const + { return regionIndices.len; } + + unsigned int get_row_size () const { return shortCount + regionIndices.len; } - inline unsigned int get_size (void) const + unsigned int get_size () const { return itemCount * get_row_size (); } - inline float get_delta (unsigned int inner, - int *coords, unsigned int coord_count, + float get_delta (unsigned int inner, + const int *coords, unsigned int coord_count, const VarRegionList ®ions) const { if (unlikely (inner >= itemCount)) @@ -1343,29 +1716,42 @@ struct VarData return delta; } - inline bool sanitize (hb_sanitize_context_t *c) const + void get_scalars (int *coords, unsigned int coord_count, + const VarRegionList ®ions, + float *scalars /*OUT */, + unsigned int num_scalars) const + { + assert (num_scalars == regionIndices.len); + for (unsigned int i = 0; i < num_scalars; i++) + { + scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + } + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - regionIndices.sanitize(c) && + regionIndices.sanitize (c) && shortCount <= regionIndices.len && - c->check_array (&StructAfter<HBUINT8> (regionIndices), - get_row_size (), itemCount)); + c->check_range (&StructAfter<HBUINT8> (regionIndices), + itemCount, + get_row_size ())); } protected: HBUINT16 itemCount; HBUINT16 shortCount; ArrayOf<HBUINT16> regionIndices; - HBUINT8 bytesX[VAR]; +/*UnsizedArrayOf<HBUINT8>bytesX;*/ public: - DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX); + DEFINE_SIZE_ARRAY (6, regionIndices); }; struct VariationStore { - inline float get_delta (unsigned int outer, unsigned int inner, - int *coords, unsigned int coord_count) const + float get_delta (unsigned int outer, unsigned int inner, + const int *coords, unsigned int coord_count) const { if (unlikely (outer >= dataSets.len)) return 0.; @@ -1375,15 +1761,15 @@ struct VariationStore this+regions); } - inline float get_delta (unsigned int index, - int *coords, unsigned int coord_count) const + float get_delta (unsigned int index, + const int *coords, unsigned int coord_count) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; return get_delta (outer, inner, coords, coord_count); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -1392,10 +1778,22 @@ struct VariationStore dataSets.sanitize (c, this)); } + unsigned int get_region_index_count (unsigned int ivs) const + { return (this+dataSets[ivs]).get_region_index_count (); } + + void get_scalars (unsigned int ivs, + int *coords, unsigned int coord_count, + float *scalars /*OUT*/, + unsigned int num_scalars) const + { + (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions, + &scalars[0], num_scalars); + } + protected: HBUINT16 format; LOffsetTo<VarRegionList> regions; - OffsetArrayOf<VarData, HBUINT32> dataSets; + LOffsetArrayOf<VarData> dataSets; public: DEFINE_SIZE_ARRAY (8, dataSets); }; @@ -1409,13 +1807,13 @@ struct ConditionFormat1 friend struct Condition; private: - inline bool evaluate (const int *coords, unsigned int coord_len) const + bool evaluate (const int *coords, unsigned int coord_len) const { int coord = axisIndex < coord_len ? coords[axisIndex] : 0; return filterRangeMinValue <= coord && coord <= filterRangeMaxValue; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -1432,7 +1830,7 @@ struct ConditionFormat1 struct Condition { - inline bool evaluate (const int *coords, unsigned int coord_len) const + bool evaluate (const int *coords, unsigned int coord_len) const { switch (u.format) { case 1: return u.format1.evaluate (coords, coord_len); @@ -1440,7 +1838,7 @@ struct Condition } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -1461,23 +1859,23 @@ struct Condition struct ConditionSet { - inline bool evaluate (const int *coords, unsigned int coord_len) const + bool evaluate (const int *coords, unsigned int coord_len) const { unsigned int count = conditions.len; for (unsigned int i = 0; i < count; i++) if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len)) - return false; + return false; return true; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (conditions.sanitize (c, this)); } protected: - OffsetArrayOf<Condition, HBUINT32> conditions; + LOffsetArrayOf<Condition> conditions; public: DEFINE_SIZE_ARRAY (2, conditions); }; @@ -1486,7 +1884,7 @@ struct FeatureTableSubstitutionRecord { friend struct FeatureTableSubstitution; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && feature.sanitize (c, base)); @@ -1501,7 +1899,7 @@ struct FeatureTableSubstitutionRecord struct FeatureTableSubstitution { - inline const Feature *find_substitute (unsigned int feature_index) const + const Feature *find_substitute (unsigned int feature_index) const { unsigned int count = substitutions.len; for (unsigned int i = 0; i < count; i++) @@ -1513,7 +1911,7 @@ struct FeatureTableSubstitution return nullptr; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && @@ -1533,7 +1931,7 @@ struct FeatureVariationRecord { friend struct FeatureVariations; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (conditions.sanitize (c, base) && @@ -1551,9 +1949,9 @@ struct FeatureVariationRecord struct FeatureVariations { - static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu; + static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu; - inline bool find_index (const int *coords, unsigned int coord_len, + bool find_index (const int *coords, unsigned int coord_len, unsigned int *index) const { unsigned int count = varRecords.len; @@ -1570,14 +1968,20 @@ struct FeatureVariations return false; } - inline const Feature *find_substitute (unsigned int variations_index, - unsigned int feature_index) const + const Feature *find_substitute (unsigned int variations_index, + unsigned int feature_index) const { const FeatureVariationRecord &record = varRecords[variations_index]; return (this+record.substitutions).find_substitute (feature_index); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (c->serializer->embed (*this)); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && @@ -1590,7 +1994,7 @@ struct FeatureVariations LArrayOf<FeatureVariationRecord> varRecords; public: - DEFINE_SIZE_ARRAY (8, varRecords); + DEFINE_SIZE_ARRAY_SIZED (8, varRecords); }; @@ -1604,20 +2008,20 @@ struct HintingDevice private: - inline hb_position_t get_x_delta (hb_font_t *font) const + hb_position_t get_x_delta (hb_font_t *font) const { return get_delta (font->x_ppem, font->x_scale); } - inline hb_position_t get_y_delta (hb_font_t *font) const + hb_position_t get_y_delta (hb_font_t *font) const { return get_delta (font->y_ppem, font->y_scale); } - inline unsigned int get_size (void) const + unsigned int get_size () const { unsigned int f = deltaFormat; if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size; return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f))); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); @@ -1625,7 +2029,7 @@ struct HintingDevice private: - inline int get_delta (unsigned int ppem, int scale) const + int get_delta (unsigned int ppem, int scale) const { if (!ppem) return 0; @@ -1635,7 +2039,7 @@ struct HintingDevice return (int) (pixels * (int64_t) scale / ppem); } - inline int get_delta_pixels (unsigned int ppem_size) const + int get_delta_pixels (unsigned int ppem_size) const { unsigned int f = deltaFormat; if (unlikely (f < 1 || f > 3)) @@ -1646,7 +2050,7 @@ struct HintingDevice unsigned int s = ppem_size - startSize; - unsigned int byte = deltaValue[s >> (4 - f)]; + unsigned int byte = deltaValueZ[s >> (4 - f)]; unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); unsigned int mask = (0xFFFFu >> (16 - (1 << f))); @@ -1666,9 +2070,10 @@ struct HintingDevice * 2 Signed 4-bit value, 4 values per uint16 * 3 Signed 8-bit value, 2 values per uint16 */ - HBUINT16 deltaValue[VAR]; /* Array of compressed data */ + UnsizedArrayOf<HBUINT16> + deltaValueZ; /* Array of compressed data */ public: - DEFINE_SIZE_ARRAY (6, deltaValue); + DEFINE_SIZE_ARRAY (6, deltaValueZ); }; struct VariationDevice @@ -1677,13 +2082,13 @@ struct VariationDevice private: - inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const + hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const { return font->em_scalef_x (get_delta (font, store)); } - inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const + hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const { return font->em_scalef_y (get_delta (font, store)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -1691,7 +2096,7 @@ struct VariationDevice private: - inline float get_delta (hb_font_t *font, const VariationStore &store) const + float get_delta (hb_font_t *font, const VariationStore &store) const { return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords); } @@ -1717,7 +2122,7 @@ struct DeviceHeader struct Device { - inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const + hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const { switch (u.b.format) { @@ -1729,7 +2134,7 @@ struct Device return 0; } } - inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const + hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const { switch (u.b.format) { @@ -1742,7 +2147,7 @@ struct Device } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.b.format.sanitize (c)) return_trace (false); @@ -1770,4 +2175,4 @@ struct Device } /* namespace OT */ -#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_COMMON_HH */ diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh index 60a8d3a..06c26fb 100644 --- a/src/hb-ot-layout-gdef-table.hh +++ b/src/hb-ot-layout-gdef-table.hh @@ -29,9 +29,9 @@ #ifndef HB_OT_LAYOUT_GDEF_TABLE_HH #define HB_OT_LAYOUT_GDEF_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" -#include "hb-font-private.hh" +#include "hb-font.hh" namespace OT { @@ -46,10 +46,10 @@ typedef ArrayOf<HBUINT16> AttachPoint; /* Array of contour point indices--in struct AttachList { - inline unsigned int get_attach_points (hb_codepoint_t glyph_id, - unsigned int start_offset, - unsigned int *point_count /* IN/OUT */, - unsigned int *point_array /* OUT */) const + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const { unsigned int index = (this+coverage).get_coverage (glyph_id); if (index == NOT_COVERED) @@ -61,9 +61,10 @@ struct AttachList const AttachPoint &points = this+attachPoint[index]; - if (point_count) { - const HBUINT16 *array = points.sub_array (start_offset, point_count); - unsigned int count = *point_count; + if (point_count) + { + hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count); + unsigned int count = array.length; for (unsigned int i = 0; i < count; i++) point_array[i] = array[i]; } @@ -71,7 +72,7 @@ struct AttachList return points.len; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); @@ -97,12 +98,12 @@ struct CaretValueFormat1 friend struct CaretValue; private: - inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const { return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -120,16 +121,14 @@ struct CaretValueFormat2 friend struct CaretValue; private: - inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const { hb_position_t x, y; - if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y)) - return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; - else - return 0; + font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); + return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -146,14 +145,15 @@ struct CaretValueFormat3 { friend struct CaretValue; - inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, + const VariationStore &var_store) const { return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); @@ -172,7 +172,7 @@ struct CaretValueFormat3 struct CaretValue { - inline hb_position_t get_caret_value (hb_font_t *font, + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id, const VariationStore &var_store) const @@ -185,7 +185,7 @@ struct CaretValue } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -210,17 +210,18 @@ struct CaretValue struct LigGlyph { - inline unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph_id, - const VariationStore &var_store, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */) const + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const { - if (caret_count) { - const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count); - unsigned int count = *caret_count; + if (caret_count) + { + hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count); + unsigned int count = array.length; for (unsigned int i = 0; i < count; i++) caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store); } @@ -228,7 +229,7 @@ struct LigGlyph return carets.len; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (carets.sanitize (c, this)); @@ -245,13 +246,13 @@ struct LigGlyph struct LigCaretList { - inline unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph_id, - const VariationStore &var_store, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */) const + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const { unsigned int index = (this+coverage).get_coverage (glyph_id); if (index == NOT_COVERED) @@ -264,7 +265,7 @@ struct LigCaretList return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); @@ -284,10 +285,10 @@ struct LigCaretList struct MarkGlyphSetsFormat1 { - inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this)); @@ -304,7 +305,7 @@ struct MarkGlyphSetsFormat1 struct MarkGlyphSets { - inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { switch (u.format) { case 1: return u.format1.covers (set_index, glyph_id); @@ -312,7 +313,7 @@ struct MarkGlyphSets } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -337,9 +338,10 @@ struct MarkGlyphSets * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef */ + struct GDEF { - static const hb_tag_t tableTag = HB_OT_TAG_GDEF; + static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; enum GlyphClasses { UnclassifiedGlyph = 0, @@ -349,59 +351,47 @@ struct GDEF ComponentGlyph = 4 }; - inline bool has_glyph_classes (void) const { return glyphClassDef != 0; } - inline unsigned int get_glyph_class (hb_codepoint_t glyph) const + bool has_data () const { return version.to_int (); } + bool has_glyph_classes () const { return glyphClassDef != 0; } + unsigned int get_glyph_class (hb_codepoint_t glyph) const { return (this+glyphClassDef).get_class (glyph); } - inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const + void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const { (this+glyphClassDef).add_class (glyphs, klass); } - inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; } - inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const + bool has_mark_attachment_types () const { return markAttachClassDef != 0; } + unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const { return (this+markAttachClassDef).get_class (glyph); } - inline bool has_attach_points (void) const { return attachList != 0; } - inline unsigned int get_attach_points (hb_codepoint_t glyph_id, - unsigned int start_offset, - unsigned int *point_count /* IN/OUT */, - unsigned int *point_array /* OUT */) const + bool has_attach_points () const { return attachList != 0; } + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); } - inline bool has_lig_carets (void) const { return ligCaretList != 0; } - inline unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph_id, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */) const + bool has_lig_carets () const { return ligCaretList != 0; } + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, get_var_store(), start_offset, caret_count, caret_array); } - inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; } - inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; } + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); } - inline bool has_var_store (void) const { return version.to_int () >= 0x00010003u && varStore != 0; } - inline const VariationStore &get_var_store (void) const + bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; } + const VariationStore &get_var_store () const { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (version.sanitize (c) && - likely (version.major == 1) && - glyphClassDef.sanitize (c, this) && - attachList.sanitize (c, this) && - ligCaretList.sanitize (c, this) && - markAttachClassDef.sanitize (c, this) && - (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && - (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); - } - /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing - * glyph class and other bits, and high 8-bit gthe mark attachment type (if any). + * glyph class and other bits, and high 8-bit the mark attachment type (if any). * Not to be confused with lookup_props which is very similar. */ - inline unsigned int get_glyph_props (hb_codepoint_t glyph) const + unsigned int get_glyph_props (hb_codepoint_t glyph) const { unsigned int klass = get_glyph_class (glyph); @@ -419,6 +409,65 @@ struct GDEF } } + HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + hb_face_t *face) const; + + struct accelerator_t + { + void init (hb_face_t *face) + { + this->table = hb_sanitize_context_t().reference_table<GDEF> (face); + if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) + { + hb_blob_destroy (this->table.get_blob ()); + this->table = hb_blob_get_empty (); + } + } + + void fini () { this->table.destroy (); } + + hb_blob_ptr_t<GDEF> table; + }; + + unsigned int get_size () const + { + return min_size + + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + + (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct GDEF *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out); + out->attachList.set (0);//TODO(subset) serialize_subset (c, this+attachList, out); + out->ligCaretList.set (0);//TODO(subset) serialize_subset (c, this+ligCaretList, out); + out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out); + + if (version.to_int () >= 0x00010002u) + out->markGlyphSetsDef.set (0);// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out); + + if (version.to_int () >= 0x00010003u) + out->varStore.set (0);// TODO(subset) serialize_subset (c, this+varStore, out); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + likely (version.major == 1) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && + (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); + } protected: FixedVersion<>version; /* Version of the GDEF table--currently @@ -453,6 +502,7 @@ struct GDEF DEFINE_SIZE_MIN (12); }; +struct GDEF_accelerator_t : GDEF::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index bc8a5fd..e17a282 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH #define HB_OT_LAYOUT_GPOS_TABLE_HH -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" namespace OT { @@ -53,7 +53,7 @@ enum attach_type_t { typedef HBUINT16 Value; -typedef Value ValueRecord[VAR]; +typedef UnsizedArrayOf<Value> ValueRecord; struct ValueFormat : HBUINT16 { @@ -84,79 +84,79 @@ struct ValueFormat : HBUINT16 HBINT16 yAdvance; /* Vertical adjustment for advance--in * design units (only used for vertical * writing) */ - Offset xPlaDevice; /* Offset to Device table for + OffsetTo<Device> xPlaDevice; /* Offset to Device table for * horizontal placement--measured from * beginning of PosTable (may be NULL) */ - Offset yPlaDevice; /* Offset to Device table for vertical + OffsetTo<Device> yPlaDevice; /* Offset to Device table for vertical * placement--measured from beginning * of PosTable (may be NULL) */ - Offset xAdvDevice; /* Offset to Device table for + OffsetTo<Device> xAdvDevice; /* Offset to Device table for * horizontal advance--measured from * beginning of PosTable (may be NULL) */ - Offset yAdvDevice; /* Offset to Device table for vertical + OffsetTo<Device> yAdvDevice; /* Offset to Device table for vertical * advance--measured from beginning of * PosTable (may be NULL) */ #endif - inline unsigned int get_len (void) const - { return _hb_popcount ((unsigned int) *this); } - inline unsigned int get_size (void) const - { return get_len () * Value::static_size; } + unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } + unsigned int get_size () const { return get_len () * Value::static_size; } - void apply_value (hb_ot_apply_context_t *c, + bool apply_value (hb_ot_apply_context_t *c, const void *base, const Value *values, hb_glyph_position_t &glyph_pos) const { + bool ret = false; unsigned int format = *this; - if (!format) return; + if (!format) return ret; hb_font_t *font = c->font; - hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction); + bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction); - if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++)); - if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++)); + if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); + if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); if (format & xAdvance) { - if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values)); + if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); values++; } /* y_advance values grow downward but font-space grows upward, hence negation */ if (format & yAdvance) { - if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values)); + if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); values++; } - if (!has_device ()) return; + if (!has_device ()) return ret; bool use_x_device = font->x_ppem || font->num_coords; bool use_y_device = font->y_ppem || font->num_coords; - if (!use_x_device && !use_y_device) return; + if (!use_x_device && !use_y_device) return ret; const VariationStore &store = c->var_store; /* pixel -> fractional pixel */ if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font, store); + if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store); values++; } if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font, store); + if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store); values++; } if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font, store); + if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store); values++; } if (format & yAdvDevice) { /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font, store); + if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store); values++; } + return ret; } private: - inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const { unsigned int format = *this; @@ -173,39 +173,46 @@ struct ValueFormat : HBUINT16 return true; } - static inline OffsetTo<Device>& get_device (Value* value) - { return *CastP<OffsetTo<Device> > (value); } - static inline const OffsetTo<Device>& get_device (const Value* value) + static OffsetTo<Device>& get_device (Value* value) { return *CastP<OffsetTo<Device> > (value); } + static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr) + { + if (worked) *worked |= bool (*value); + return *CastP<OffsetTo<Device> > (value); + } - static inline const HBINT16& get_short (const Value* value) - { return *CastP<HBINT16> (value); } + static const HBINT16& get_short (const Value* value, bool *worked=nullptr) + { + if (worked) *worked |= bool (*value); + return *CastP<HBINT16> (value); + } public: - inline bool has_device (void) const { + bool has_device () const + { unsigned int format = *this; return (format & devices) != 0; } - inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const { TRACE_SANITIZE (this); return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); } - inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const + bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const { TRACE_SANITIZE (this); unsigned int len = get_len (); - if (!c->check_array (values, get_size (), count)) return_trace (false); + if (!c->check_range (values, count, get_size ())) return_trace (false); if (!has_device ()) return_trace (true); for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return_trace (false); + return_trace (false); values += len; } @@ -213,7 +220,7 @@ struct ValueFormat : HBUINT16 } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ - inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const + bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const { TRACE_SANITIZE (this); @@ -221,7 +228,7 @@ struct ValueFormat : HBUINT16 for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return_trace (false); + return_trace (false); values += stride; } @@ -232,15 +239,15 @@ struct ValueFormat : HBUINT16 struct AnchorFormat1 { - inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, - float *x, float *y) const + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, + float *x, float *y) const { hb_font_t *font = c->font; *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -256,22 +263,22 @@ struct AnchorFormat1 struct AnchorFormat2 { - inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, - float *x, float *y) const + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, + float *x, float *y) const { hb_font_t *font = c->font; unsigned int x_ppem = font->x_ppem; unsigned int y_ppem = font->y_ppem; hb_position_t cx = 0, cy = 0; - hb_bool_t ret; + bool ret; ret = (x_ppem || y_ppem) && - font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); + font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate); *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -288,8 +295,8 @@ struct AnchorFormat2 struct AnchorFormat3 { - inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, - float *x, float *y) const + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, + float *x, float *y) const { hb_font_t *font = c->font; *x = font->em_fscale_x (xCoordinate); @@ -301,7 +308,7 @@ struct AnchorFormat3 *y += (this+yDeviceTable).get_y_delta (font, c->var_store); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); @@ -325,8 +332,8 @@ struct AnchorFormat3 struct Anchor { - inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, - float *x, float *y) const + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, + float *x, float *y) const { *x = *y = 0; switch (u.format) { @@ -337,7 +344,7 @@ struct Anchor } } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); @@ -363,20 +370,22 @@ struct Anchor struct AnchorMatrix { - inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const { + const Anchor& get_anchor (unsigned int row, unsigned int col, + unsigned int cols, bool *found) const + { *found = false; if (unlikely (row >= rows || col >= cols)) return Null(Anchor); *found = !matrixZ[row * cols + col].is_null (); return this+matrixZ[row * cols + col]; } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const + bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); - if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false); + if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); unsigned int count = rows * cols; - if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false); + if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) if (!matrixZ[i].sanitize (c, this)) return_trace (false); return_trace (true); @@ -384,8 +393,8 @@ struct AnchorMatrix HBUINT16 rows; /* Number of rows */ protected: - OffsetTo<Anchor> - matrixZ[VAR]; /* Matrix of offsets to Anchor tables-- + UnsizedArrayOf<OffsetTo<Anchor> > + matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: DEFINE_SIZE_ARRAY (2, matrixZ); @@ -396,7 +405,7 @@ struct MarkRecord { friend struct MarkArray; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); @@ -413,10 +422,10 @@ struct MarkRecord struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */ { - inline bool apply (hb_ot_apply_context_t *c, - unsigned int mark_index, unsigned int glyph_index, - const AnchorMatrix &anchors, unsigned int class_count, - unsigned int glyph_pos) const + bool apply (hb_ot_apply_context_t *c, + unsigned int mark_index, unsigned int glyph_index, + const AnchorMatrix &anchors, unsigned int class_count, + unsigned int glyph_pos) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -447,7 +456,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (ArrayOf<MarkRecord>::sanitize (c, this)); @@ -459,18 +468,15 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde struct SinglePosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - TRACE_COLLECT_GLYPHS (this); - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - } + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -483,7 +489,14 @@ struct SinglePosFormat1 return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -507,18 +520,15 @@ struct SinglePosFormat1 struct SinglePosFormat2 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - TRACE_COLLECT_GLYPHS (this); - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - } + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -535,7 +545,14 @@ struct SinglePosFormat2 return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -560,7 +577,7 @@ struct SinglePosFormat2 struct SinglePos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -598,19 +615,36 @@ struct PairSet { friend struct PairPosFormat1; - inline void collect_glyphs (hb_collect_glyphs_context_t *c, + bool intersects (const hb_set_t *glyphs, + const ValueFormat *valueFormats) const + { + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (glyphs->has (record->secondGlyph)) + return true; + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + return false; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c, const ValueFormat *valueFormats) const { - TRACE_COLLECT_GLYPHS (this); unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); + const PairValueRecord *record = &firstPairValueRecord; c->input->add_array (&record->secondGlyph, len, record_size); } - inline bool apply (hb_ot_apply_context_t *c, + bool apply (hb_ot_apply_context_t *c, const ValueFormat *valueFormats, unsigned int pos) const { @@ -620,7 +654,6 @@ struct PairSet unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ); unsigned int count = len; /* Hand-coded bsearch. */ @@ -630,18 +663,19 @@ struct PairSet int min = 0, max = (int) count - 1; while (min <= max) { - int mid = (min + max) / 2; - const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid); + int mid = ((unsigned int) min + (unsigned int) max) / 2; + const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid); hb_codepoint_t mid_x = record->secondGlyph; if (x < mid_x) - max = mid - 1; + max = mid - 1; else if (x > mid_x) - min = mid + 1; + min = mid + 1; else { - buffer->unsafe_to_break (buffer->idx, pos + 1); - valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); - valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + /* Note the intentional use of "|" instead of short-circuit "||". */ + if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) | + valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos])) + buffer->unsafe_to_break (buffer->idx, pos + 1); if (len2) pos++; buffer->idx = pos; @@ -652,50 +686,65 @@ struct PairSet return_trace (false); } - struct sanitize_closure_t { + struct sanitize_closure_t + { const void *base; const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ unsigned int stride; /* 1 + len1 + len2 */ }; - inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const + bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const { TRACE_SANITIZE (this); if (!(c->check_struct (this) - && c->check_array (arrayZ, HBUINT16::static_size * closure->stride, len))) return_trace (false); + && c->check_range (&firstPairValueRecord, + len, + HBUINT16::static_size, + closure->stride))) return_trace (false); unsigned int count = len; - const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); + const PairValueRecord *record = &firstPairValueRecord; return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); } protected: - HBUINT16 len; /* Number of PairValueRecords */ - HBUINT16 arrayZ[VAR]; /* Array of PairValueRecords--ordered - * by GlyphID of the second glyph */ + HBUINT16 len; /* Number of PairValueRecords */ + PairValueRecord firstPairValueRecord; + /* Array of PairValueRecords--ordered + * by GlyphID of the second glyph */ public: - DEFINE_SIZE_ARRAY (2, arrayZ); + DEFINE_SIZE_MIN (2); }; struct PairPosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = pairSet.len; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; unsigned int count = pairSet.len; for (unsigned int i = 0; i < count; i++) (this+pairSet[i]).collect_glyphs (c, valueFormat); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -709,7 +758,14 @@ struct PairPosFormat1 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -717,7 +773,8 @@ struct PairPosFormat1 unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); - PairSet::sanitize_closure_t closure = { + PairSet::sanitize_closure_t closure = + { this, valueFormat, len1, @@ -747,19 +804,21 @@ struct PairPosFormat1 struct PairPosFormat2 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const { - TRACE_COLLECT_GLYPHS (this); - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - if (unlikely (!(this+classDef2).add_coverage (c->input))) return; + return (this+coverage).intersects (glyphs) && + (this+classDef2).intersects (glyphs); } - inline const Coverage &get_coverage (void) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - return this+coverage; + if (unlikely (!(this+coverage).add_coverage (c->input))) return; + if (unlikely (!(this+classDef2).add_coverage (c->input))) return; } - inline bool apply (hb_ot_apply_context_t *c) const + const Coverage &get_coverage () const { return this+coverage; } + + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -778,10 +837,11 @@ struct PairPosFormat2 unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); - buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + /* Note the intentional use of "|" instead of short-circuit "||". */ + if (valueFormat1.apply_value (c, this, v, buffer->cur_pos()) | + valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx])) + buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); buffer->idx = skippy_iter.idx; if (len2) @@ -790,7 +850,14 @@ struct PairPosFormat2 return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!(c->check_struct (this) @@ -803,7 +870,9 @@ struct PairPosFormat2 unsigned int stride = len1 + len2; unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return_trace (c->check_array (values, record_size, count) && + return_trace (c->check_range ((const void *) values, + count, + record_size) && valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } @@ -841,7 +910,7 @@ struct PairPosFormat2 struct PairPos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -865,7 +934,7 @@ struct EntryExitRecord { friend struct CursivePosFormat1; - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); @@ -889,39 +958,36 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc struct CursivePosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - TRACE_COLLECT_GLYPHS (this); - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - } + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.exitAnchor) return_trace (false); + if (!this_record.entryAnchor) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + if (!skippy_iter.prev ()) return_trace (false); - const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!next_record.entryAnchor) return_trace (false); + const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; + if (!prev_record.exitAnchor) return_trace (false); - unsigned int i = buffer->idx; - unsigned int j = skippy_iter.idx; + unsigned int i = skippy_iter.idx; + unsigned int j = buffer->idx; buffer->unsafe_to_break (i, j); float entry_x, entry_y, exit_x, exit_y; - (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); - (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); + (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); + (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); hb_glyph_position_t *pos = buffer->pos; @@ -968,7 +1034,7 @@ struct CursivePosFormat1 * parent. * * Optimize things for the case of RightToLeft, as that's most common in - * Arabinc. */ + * Arabic. */ unsigned int child = i; unsigned int parent = j; hb_position_t x_offset = entry_x - exit_x; @@ -997,11 +1063,18 @@ struct CursivePosFormat1 else pos[child].x_offset = x_offset; - buffer->idx = j; + buffer->idx++; return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); @@ -1022,7 +1095,7 @@ struct CursivePosFormat1 struct CursivePos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1047,19 +1120,19 @@ typedef AnchorMatrix BaseArray; /* base-major-- struct MarkBasePosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+baseCoverage).intersects (glyphs); } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return; } - inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + const Coverage &get_coverage () const { return this+markCoverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -1074,10 +1147,13 @@ struct MarkBasePosFormat1 if (!skippy_iter.prev ()) return_trace (false); /* We only want to attach to the first of a MultipleSubst sequence. * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others. */ + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || (skippy_iter.idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != @@ -1085,7 +1161,7 @@ struct MarkBasePosFormat1 )) break; skippy_iter.reject (); - } while (1); + } while (true); /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } @@ -1096,7 +1172,14 @@ struct MarkBasePosFormat1 return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -1128,7 +1211,7 @@ struct MarkBasePosFormat1 struct MarkBasePos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1158,19 +1241,19 @@ typedef OffsetListOf<LigatureAttach> LigatureArray; struct MarkLigPosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+ligatureCoverage).intersects (glyphs); } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return; } - inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + const Coverage &get_coverage () const { return this+markCoverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -1213,7 +1296,14 @@ struct MarkLigPosFormat1 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -1246,7 +1336,7 @@ struct MarkLigPosFormat1 struct MarkLigPos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1271,19 +1361,19 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- struct MarkMarkPosFormat1 { - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+mark1Coverage).intersects (glyphs) && + (this+mark2Coverage).intersects (glyphs); } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return; if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return; } - inline const Coverage &get_coverage (void) const - { - return this+mark1Coverage; - } + const Coverage &get_coverage () const { return this+mark1Coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -1309,7 +1399,7 @@ struct MarkMarkPosFormat1 if (id1 == 0) /* Marks belonging to the same base. */ goto good; else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ - goto good; + goto good; } else { /* If ligature ids don't match, it may be the case that one of the marks * itself is a ligature. In which case match. */ @@ -1327,7 +1417,14 @@ struct MarkMarkPosFormat1 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -1361,7 +1458,7 @@ struct MarkMarkPosFormat1 struct MarkMarkPos { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1385,7 +1482,7 @@ struct ChainContextPos : ChainContext {}; struct ExtensionPos : Extension<ExtensionPos> { - typedef struct PosLookupSubTable LookupSubTable; + typedef struct PosLookupSubTable SubTable; }; @@ -1397,6 +1494,7 @@ struct ExtensionPos : Extension<ExtensionPos> struct PosLookupSubTable { + friend struct Lookup; friend struct PosLookup; enum Type { @@ -1412,10 +1510,9 @@ struct PosLookupSubTable }; template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { TRACE_DISPATCH (this, lookup_type); - if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); switch (lookup_type) { case Single: return_trace (u.single.dispatch (c)); case Pair: return_trace (u.pair.dispatch (c)); @@ -1432,7 +1529,6 @@ struct PosLookupSubTable protected: union { - HBUINT16 sub_format; SinglePos single; PairPos pair; CursivePos cursive; @@ -1444,34 +1540,39 @@ struct PosLookupSubTable ExtensionPos extension; } u; public: - DEFINE_SIZE_UNION (2, sub_format); + DEFINE_SIZE_MIN (0); }; struct PosLookup : Lookup { - inline const PosLookupSubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<PosLookupSubTable> (i); } + typedef struct PosLookupSubTable SubTable; + + const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } - inline bool is_reverse (void) const + bool is_reverse () const { return false; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); return_trace (dispatch (c)); } - inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const + bool intersects (const hb_set_t *glyphs) const { - TRACE_COLLECT_GLYPHS (this); - return_trace (dispatch (c)); + hb_intersects_context_t c (glyphs); + return dispatch (&c); } + hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const + { return dispatch (c); } + template <typename set_t> - inline void add_coverage (set_t *glyphs) const + void add_coverage (set_t *glyphs) const { hb_add_coverage_context_t<set_t> c (glyphs); dispatch (&c); @@ -1480,21 +1581,18 @@ struct PosLookup : Lookup static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); template <typename context_t> - static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch<PosLookupSubTable> (c); } + typename context_t::return_t dispatch (context_t *c) const + { return Lookup::dispatch<SubTable> (c); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return_trace (false); - return_trace (dispatch (c)); - } -}; + bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } -typedef OffsetListOf<PosLookup> PosLookupList; + bool sanitize (hb_sanitize_context_t *c) const + { return Lookup::sanitize<SubTable> (c); } +}; /* * GPOS -- Glyph Positioning @@ -1503,22 +1601,25 @@ typedef OffsetListOf<PosLookup> PosLookupList; struct GPOS : GSUBGPOS { - static const hb_tag_t tableTag = HB_OT_TAG_GPOS; + static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; - inline const PosLookup& get_lookup (unsigned int i) const + const PosLookup& get_lookup (unsigned int i) const { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); - const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); - return_trace (list.sanitize (c, this)); - } + bool subset (hb_subset_context_t *c) const + { return GSUBGPOS::subset<PosLookup> (c); } + + bool sanitize (hb_sanitize_context_t *c) const + { return GSUBGPOS::sanitize<PosLookup> (c); } + + HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + hb_face_t *face) const; + + typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t; }; @@ -1548,7 +1649,10 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc pos[j].attach_type() = type; } static void -propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) +propagate_attachment_offsets (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction) { /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate * offset of glyph they are attached to. */ @@ -1556,11 +1660,14 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direc if (likely (!chain)) return; + pos[i].attach_chain() = 0; + unsigned int j = (int) i + chain; - pos[i].attach_chain() = 0; + if (unlikely (j >= len)) + return; - propagate_attachment_offsets (pos, j, direction); + propagate_attachment_offsets (pos, len, j, direction); assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE)); @@ -1599,7 +1706,7 @@ GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) } void -GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) +GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) { //_hb_buffer_assert_gsubgpos_vars (buffer); } @@ -1616,24 +1723,25 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) for (unsigned int i = 0; i < len; i++) - propagate_attachment_offsets (pos, i, direction); + propagate_attachment_offsets (pos, len, i, direction); } +struct GPOS_accelerator_t : GPOS::accelerator_t {}; + + /* Out-of-class implementation for methods recursing */ template <typename context_t> /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); - const PosLookup &l = gpos.get_lookup (lookup_index); + const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); return l.dispatch (c); } /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); - const PosLookup &l = gpos.get_lookup (lookup_index); + const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; unsigned int saved_lookup_index = c->lookup_index; c->set_lookup_index (lookup_index); @@ -1645,10 +1753,6 @@ template <typename context_t> } -#undef attach_chain -#undef attach_type - - } /* namespace OT */ diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index bd72fe6..33b8f0e 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -29,34 +29,37 @@ #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH #define HB_OT_LAYOUT_GSUB_TABLE_HH -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" namespace OT { +static inline void SingleSubst_serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const GlyphID> substitutes); + struct SingleSubstFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); - Coverage::Iter iter; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { /* TODO Switch to range-based API to work around malicious fonts. * https://github.com/harfbuzz/harfbuzz/issues/363 */ hb_codepoint_t glyph_id = iter.get_glyph (); if (c->glyphs->has (glyph_id)) - c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu); + c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu); } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { /* TODO Switch to range-based API to work around malicious fonts. * https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -65,18 +68,15 @@ struct SingleSubstFormat1 } } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; @@ -91,19 +91,37 @@ struct SingleSubstFormat1 return_trace (true); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - unsigned int num_glyphs, - int delta) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + int delta) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); - deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false); + deltaGlyphID.set (delta); /* TODO(serialize) overflow? */ return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset; + const hb_map_t &glyph_map = *c->plan->glyph_map; + hb_vector_t<GlyphID> from; + hb_vector_t<GlyphID> to; + hb_codepoint_t delta = deltaGlyphID; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (!glyphset.has (iter.get_glyph ())) continue; + from.push ()->set (glyph_map[iter.get_glyph ()]); + to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]); + } + c->serializer->propagate_error (from, to); + SingleSubst_serialize (c->serializer, from, to); + return_trace (from.length); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); @@ -122,27 +140,26 @@ struct SingleSubstFormat1 struct SingleSubstFormat2 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ if (c->glyphs->has (iter.get_glyph ())) - c->glyphs->add (substitute[iter.get_coverage ()]); + c->out->add (substitute[iter.get_coverage ()]); } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -150,45 +167,57 @@ struct SingleSubstFormat2 } } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); if (unlikely (index >= substitute.len)) return_trace (false); - glyph_id = substitute[index]; - c->replace_glyph (glyph_id); + c->replace_glyph (substitute[index]); return_trace (true); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<GlyphID> &substitutes, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const GlyphID> substitutes) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); + if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false); + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false); return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset; + const hb_map_t &glyph_map = *c->plan->glyph_map; + hb_vector_t<GlyphID> from; + hb_vector_t<GlyphID> to; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (!glyphset.has (iter.get_glyph ())) continue; + from.push ()->set (glyph_map[iter.get_glyph ()]); + to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]); + } + c->serializer->propagate_error (from, to); + SingleSubst_serialize (c->serializer, from, to); + return_trace (from.length); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); @@ -208,35 +237,35 @@ struct SingleSubstFormat2 struct SingleSubst { - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<GlyphID> &substitutes, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const GlyphID> substitutes) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 2; int delta = 0; - if (num_glyphs) { + if (glyphs.length) + { format = 1; /* TODO(serialize) check for wrap-around */ delta = substitutes[0] - glyphs[0]; - for (unsigned int i = 1; i < num_glyphs; i++) - if (delta != substitutes[i] - glyphs[i]) { + for (unsigned int i = 1; i < glyphs.length; i++) + if (delta != (int) (substitutes[i] - glyphs[i])) { format = 2; break; } } u.format.set (format); switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta)); - case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); + case 1: return_trace (u.format1.serialize (c, glyphs, delta)); + case 2: return_trace (u.format2.serialize (c, glyphs, substitutes)); default:return_trace (false); } } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -255,24 +284,25 @@ struct SingleSubst } u; }; +static inline void +SingleSubst_serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const GlyphID> substitutes) +{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); } struct Sequence { - inline void closure (hb_closure_context_t *c) const + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); unsigned int count = substitute.len; for (unsigned int i = 0; i < count; i++) - c->glyphs->add (substitute[i]); + c->out->add (substitute[i]); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - TRACE_COLLECT_GLYPHS (this); - c->output->add_array (substitute.arrayZ, substitute.len); - } + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { c->output->add_array (substitute.arrayZ, substitute.len); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int count = substitute.len; @@ -304,17 +334,14 @@ struct Sequence return_trace (true); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - unsigned int num_glyphs) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false); - return_trace (true); + return_trace (substitute.serialize (c, glyphs)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (substitute.sanitize (c)); @@ -329,12 +356,13 @@ struct Sequence struct MultipleSubstFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = sequence.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -343,27 +371,23 @@ struct MultipleSubstFormat1 } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; unsigned int count = sequence.len; for (unsigned int i = 0; i < count; i++) - (this+sequence[i]).collect_glyphs (c); + (this+sequence[i]).collect_glyphs (c); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -373,25 +397,33 @@ struct MultipleSubstFormat1 return_trace ((this+sequence[index]).apply (c)); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &substitute_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &substitute_glyphs_list) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const GlyphID> substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false); - for (unsigned int i = 0; i < num_glyphs; i++) - if (unlikely (!sequence[i].serialize (c, this).serialize (c, - substitute_glyphs_list, - substitute_len_list[i]))) return_trace (false); - substitute_len_list += num_glyphs; - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); - return_trace (true); + if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int substitute_len = substitute_len_list[i]; + if (unlikely (!sequence[i].serialize (c, this) + .serialize (c, substitute_glyphs_list.sub_array (0, substitute_len)))) + return_trace (false); + substitute_glyphs_list += substitute_len; + } + return_trace (coverage.serialize (c, this).serialize (c, glyphs)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); @@ -411,24 +443,23 @@ struct MultipleSubstFormat1 struct MultipleSubst { - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &substitute_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &substitute_glyphs_list) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const GlyphID> substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format.set (format); switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); + case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); default:return_trace (false); } } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -445,103 +476,138 @@ struct MultipleSubst } u; }; +struct AlternateSet +{ + void closure (hb_closure_context_t *c) const + { + unsigned int count = alternates.len; + for (unsigned int i = 0; i < count; i++) + c->out->add (alternates[i]); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { c->output->add_array (alternates.arrayZ, alternates.len); } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = alternates.len; + + if (unlikely (!count)) return_trace (false); + + hb_mask_t glyph_mask = c->buffer->cur().mask; + hb_mask_t lookup_mask = c->lookup_mask; + + /* Note: This breaks badly if two features enabled this lookup together. */ + unsigned int shift = hb_ctz (lookup_mask); + unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); + + /* If alt_index is MAX, randomize feature if it is the rand feature. */ + if (alt_index == HB_OT_MAP_MAX_VALUE && c->random) + alt_index = c->random_number () % count + 1; -typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in + if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); + + c->replace_glyph (alternates[alt_index - 1]); + + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs) + { + TRACE_SERIALIZE (this); + return_trace (alternates.serialize (c, glyphs)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (alternates.sanitize (c)); + } + + protected: + ArrayOf<GlyphID> + alternates; /* Array of alternate GlyphIDs--in * arbitrary order */ + public: + DEFINE_SIZE_ARRAY (2, alternates); +}; struct AlternateSubstFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = alternateSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) { - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - unsigned int count = alt_set.len; - for (unsigned int i = 0; i < count; i++) - c->glyphs->add (alt_set[i]); - } + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+alternateSet[iter.get_coverage ()]).closure (c); } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = alternateSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - c->output->add_array (alt_set.arrayZ, alt_set.len); + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c); } } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const AlternateSet &alt_set = this+alternateSet[index]; - - if (unlikely (!alt_set.len)) return_trace (false); - - hb_mask_t glyph_mask = c->buffer->cur().mask; - hb_mask_t lookup_mask = c->lookup_mask; - - /* Note: This breaks badly if two features enabled this lookup together. */ - unsigned int shift = _hb_ctz (lookup_mask); - unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - - if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); - - glyph_id = alt_set[alt_index - 1]; - - c->replace_glyph (glyph_id); - - return_trace (true); + return_trace ((this+alternateSet[index]).apply (c)); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &alternate_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &alternate_glyphs_list) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const GlyphID> alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false); - for (unsigned int i = 0; i < num_glyphs; i++) - if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, - alternate_glyphs_list, - alternate_len_list[i]))) return_trace (false); - alternate_len_list += num_glyphs; - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); - return_trace (true); + if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int alternate_len = alternate_len_list[i]; + if (unlikely (!alternateSet[i].serialize (c, this) + .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len)))) + return_trace (false); + alternate_glyphs_list += alternate_len; + } + return_trace (coverage.serialize (c, this).serialize (c, glyphs)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); @@ -561,24 +627,23 @@ struct AlternateSubstFormat1 struct AlternateSubst { - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &alternate_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &alternate_glyphs_list) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const GlyphID> alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format.set (format); switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); + case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); default:return_trace (false); } } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -598,27 +663,34 @@ struct AlternateSubst struct Ligature { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const { - TRACE_CLOSURE (this); - unsigned int count = component.len; + unsigned int count = component.lenP1; + for (unsigned int i = 1; i < count; i++) + if (!glyphs->has (component[i])) + return false; + return true; + } + + void closure (hb_closure_context_t *c) const + { + unsigned int count = component.lenP1; for (unsigned int i = 1; i < count; i++) if (!c->glyphs->has (component[i])) return; - c->glyphs->add (ligGlyph); + c->out->add (ligGlyph); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); - c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0); + c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0); c->output->add (ligGlyph); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - if (c->len != component.len) + if (c->len != component.lenP1) return_trace (false); for (unsigned int i = 1; i < c->len; i++) @@ -628,10 +700,10 @@ struct Ligature return_trace (true); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - unsigned int count = component.len; + unsigned int count = component.lenP1; if (unlikely (!count)) return_trace (false); @@ -643,7 +715,6 @@ struct Ligature return_trace (true); } - bool is_mark_ligature = false; unsigned int total_component_count = 0; unsigned int match_length = 0; @@ -655,7 +726,6 @@ struct Ligature nullptr, &match_length, match_positions, - &is_mark_ligature, &total_component_count))) return_trace (false); @@ -664,26 +734,24 @@ struct Ligature match_positions, match_length, ligGlyph, - is_mark_ligature, total_component_count); return_trace (true); } - inline bool serialize (hb_serialize_context_t *c, - GlyphID ligature, - Supplier<GlyphID> &components, /* Starting from second */ - unsigned int num_components /* Including first component */) + bool serialize (hb_serialize_context_t *c, + GlyphID ligature, + hb_array_t<const GlyphID> components /* Starting from second */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); ligGlyph = ligature; - if (unlikely (!component.serialize (c, components, num_components))) return_trace (false); + if (unlikely (!component.serialize (c, components))) return_trace (false); return_trace (true); } public: - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); @@ -701,23 +769,30 @@ struct Ligature struct LigatureSet { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + if ((this+ligature[i]).intersects (glyphs)) + return true; + return false; + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) (this+ligature[i]).closure (c); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) (this+ligature[i]).collect_glyphs (c); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); unsigned int num_ligs = ligature.len; @@ -730,7 +805,7 @@ struct LigatureSet return_trace (false); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int num_ligs = ligature.len; @@ -743,26 +818,28 @@ struct LigatureSet return_trace (false); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &ligatures, - Supplier<unsigned int> &component_count_list, - unsigned int num_ligatures, - Supplier<GlyphID> &component_list /* Starting from second for each ligature */) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> ligatures, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false); - for (unsigned int i = 0; i < num_ligatures; i++) - if (unlikely (!ligature[i].serialize (c, this).serialize (c, - ligatures[i], - component_list, - component_count_list[i]))) return_trace (false); - ligatures += num_ligatures; - component_count_list += num_ligatures; + if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); + for (unsigned int i = 0; i < ligatures.length; i++) + { + unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0); + if (unlikely (!ligature[i].serialize (c, this) + .serialize (c, + ligatures[i], + component_list.sub_array (0, component_count)))) + return_trace (false); + component_list += component_count; + } return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (ligature.sanitize (c, this)); @@ -778,12 +855,24 @@ struct LigatureSet struct LigatureSubstFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = ligatureSet.len; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs)) + return true; + } + return false; + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = ligatureSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -792,13 +881,11 @@ struct LigatureSubstFormat1 } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = ligatureSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -806,12 +893,9 @@ struct LigatureSubstFormat1 } } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); @@ -821,41 +905,49 @@ struct LigatureSubstFormat1 return_trace (lig_set.would_apply (c)); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; return_trace (lig_set.apply (c)); } - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &first_glyphs, - Supplier<unsigned int> &ligature_per_first_glyph_count_list, - unsigned int num_first_glyphs, - Supplier<GlyphID> &ligatures_list, - Supplier<unsigned int> &component_count_list, - Supplier<GlyphID> &component_list /* Starting from second for each ligature */) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const GlyphID> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false); - for (unsigned int i = 0; i < num_first_glyphs; i++) - if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, - ligatures_list, - component_count_list, - ligature_per_first_glyph_count_list[i], - component_list))) return_trace (false); - ligature_per_first_glyph_count_list += num_first_glyphs; - if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false); - return_trace (true); + if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < first_glyphs.length; i++) + { + unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; + if (unlikely (!ligatureSet[i].serialize (c, this) + .serialize (c, + ligatures_list.sub_array (0, ligature_count), + component_count_list.sub_array (0, ligature_count), + component_list))) return_trace (false); + ligatures_list += ligature_count; + component_count_list += ligature_count; + } + return_trace (coverage.serialize (c, this).serialize (c, first_glyphs)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); @@ -875,13 +967,12 @@ struct LigatureSubstFormat1 struct LigatureSubst { - inline bool serialize (hb_serialize_context_t *c, - Supplier<GlyphID> &first_glyphs, - Supplier<unsigned int> &ligature_per_first_glyph_count_list, - unsigned int num_first_glyphs, - Supplier<GlyphID> &ligatures_list, - Supplier<unsigned int> &component_count_list, - Supplier<GlyphID> &component_list /* Starting from second for each ligature */) + bool serialize (hb_serialize_context_t *c, + hb_array_t<const GlyphID> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const GlyphID> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); @@ -891,7 +982,6 @@ struct LigatureSubst case 1: return_trace (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, - num_first_glyphs, ligatures_list, component_count_list, component_list)); @@ -900,7 +990,7 @@ struct LigatureSubst } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -924,17 +1014,38 @@ struct ChainContextSubst : ChainContext {}; struct ExtensionSubst : Extension<ExtensionSubst> { - typedef struct SubstLookupSubTable LookupSubTable; + typedef struct SubstLookupSubTable SubTable; - inline bool is_reverse (void) const; + bool is_reverse () const; }; struct ReverseChainSingleSubstFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+backtrack[i]).intersects (glyphs)) + return false; + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+lookahead[i]).intersects (glyphs)) + return false; + + return true; + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); unsigned int count; @@ -950,20 +1061,18 @@ struct ReverseChainSingleSubstFormat1 return; const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); - Coverage::Iter iter; count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ if (c->glyphs->has (iter.get_glyph ())) - c->glyphs->add (substitute[iter.get_coverage ()]); + c->out->add (substitute[iter.get_coverage ()]); } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; unsigned int count; @@ -982,18 +1091,15 @@ struct ReverseChainSingleSubstFormat1 c->output->add_array (substitute.arrayZ, substitute.len); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) @@ -1026,7 +1132,14 @@ struct ReverseChainSingleSubstFormat1 return_trace (false); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) @@ -1045,7 +1158,7 @@ struct ReverseChainSingleSubstFormat1 * beginning of table */ OffsetArrayOf<Coverage> backtrack; /* Array of coverage tables - * in backtracking sequence, in glyph + * in backtracking sequence, in glyph * sequence order */ OffsetArrayOf<Coverage> lookaheadX; /* Array of coverage tables @@ -1061,7 +1174,7 @@ struct ReverseChainSingleSubstFormat1 struct ReverseChainSingleSubst { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1086,6 +1199,7 @@ struct ReverseChainSingleSubst struct SubstLookupSubTable { + friend struct Lookup; friend struct SubstLookup; enum Type { @@ -1100,10 +1214,9 @@ struct SubstLookupSubTable }; template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { TRACE_DISPATCH (this, lookup_type); - if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); switch (lookup_type) { case Single: return_trace (u.single.dispatch (c)); case Multiple: return_trace (u.multiple.dispatch (c)); @@ -1119,7 +1232,6 @@ struct SubstLookupSubTable protected: union { - HBUINT16 sub_format; SingleSubst single; MultipleSubst multiple; AlternateSubst alternate; @@ -1130,58 +1242,69 @@ struct SubstLookupSubTable ReverseChainSingleSubst reverseChainContextSingle; } u; public: - DEFINE_SIZE_UNION (2, sub_format); + DEFINE_SIZE_MIN (0); }; struct SubstLookup : Lookup { - inline const SubstLookupSubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<SubstLookupSubTable> (i); } + typedef SubstLookupSubTable SubTable; + + const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } - inline static bool lookup_type_is_reverse (unsigned int lookup_type) - { return lookup_type == SubstLookupSubTable::ReverseChainSingle; } + static bool lookup_type_is_reverse (unsigned int lookup_type) + { return lookup_type == SubTable::ReverseChainSingle; } - inline bool is_reverse (void) const + bool is_reverse () const { unsigned int type = get_type (); - if (unlikely (type == SubstLookupSubTable::Extension)) + if (unlikely (type == SubTable::Extension)) return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); return lookup_type_is_reverse (type); } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); return_trace (dispatch (c)); } - inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const + bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + + hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const { - TRACE_CLOSURE (this); if (!c->should_visit_lookup (this_index)) - return_trace (HB_VOID); + return hb_closure_context_t::default_return_value (); c->set_recurse_func (dispatch_closure_recurse_func); - return_trace (dispatch (c)); + + hb_closure_context_t::return_t ret = dispatch (c); + + c->flush (); + + return ret; } - inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const + hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); - return_trace (dispatch (c)); + return dispatch (c); } template <typename set_t> - inline void add_coverage (set_t *glyphs) const + void add_coverage (set_t *glyphs) const { hb_add_coverage_context_t<set_t> c (glyphs); dispatch (&c); } - inline bool would_apply (hb_would_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t *accel) const + bool would_apply (hb_would_apply_context_t *c, + const hb_ot_layout_lookup_accelerator_t *accel) const { TRACE_WOULD_APPLY (this); if (unlikely (!c->len)) return_trace (false); @@ -1191,111 +1314,95 @@ struct SubstLookup : Lookup static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); - inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, - unsigned int i) - { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); } + SubTable& serialize_subtable (hb_serialize_context_t *c, + unsigned int i) + { return get_subtables<SubTable> ()[i].serialize (c, this); } - inline bool serialize_single (hb_serialize_context_t *c, - uint32_t lookup_props, - Supplier<GlyphID> &glyphs, - Supplier<GlyphID> &substitutes, - unsigned int num_glyphs) + bool serialize_single (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const GlyphID> substitutes) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false); - return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); + if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); + return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes)); } - inline bool serialize_multiple (hb_serialize_context_t *c, - uint32_t lookup_props, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &substitute_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &substitute_glyphs_list) + bool serialize_multiple (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> substitute_len_list, + hb_array_t<const GlyphID> substitute_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, - num_glyphs, substitute_glyphs_list)); } - inline bool serialize_alternate (hb_serialize_context_t *c, - uint32_t lookup_props, - Supplier<GlyphID> &glyphs, - Supplier<unsigned int> &alternate_len_list, - unsigned int num_glyphs, - Supplier<GlyphID> &alternate_glyphs_list) + bool serialize_alternate (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_array_t<const GlyphID> glyphs, + hb_array_t<const unsigned int> alternate_len_list, + hb_array_t<const GlyphID> alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, - num_glyphs, alternate_glyphs_list)); } - inline bool serialize_ligature (hb_serialize_context_t *c, - uint32_t lookup_props, - Supplier<GlyphID> &first_glyphs, - Supplier<unsigned int> &ligature_per_first_glyph_count_list, - unsigned int num_first_glyphs, - Supplier<GlyphID> &ligatures_list, - Supplier<unsigned int> &component_count_list, - Supplier<GlyphID> &component_list /* Starting from second for each ligature */) + bool serialize_ligature (hb_serialize_context_t *c, + uint32_t lookup_props, + hb_array_t<const GlyphID> first_glyphs, + hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, + hb_array_t<const GlyphID> ligatures_list, + hb_array_t<const unsigned int> component_count_list, + hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, - num_first_glyphs, ligatures_list, component_count_list, component_list)); } template <typename context_t> - static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index) + static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index) { if (!c->should_visit_lookup (lookup_index)) return HB_VOID; - return dispatch_recurse_func (c, lookup_index); + + hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index); + + /* While in theory we should flush here, it will cause timeouts because a recursive + * lookup can keep growing the glyph set. Skip, and outer loop will retry up to + * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */ + //c->flush (); + + return ret; } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch<SubstLookupSubTable> (c); } + typename context_t::return_t dispatch (context_t *c) const + { return Lookup::dispatch<SubTable> (c); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return_trace (false); - if (unlikely (!dispatch (c))) return_trace (false); + bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } - if (unlikely (get_type () == SubstLookupSubTable::Extension)) - { - /* The spec says all subtables of an Extension lookup should - * have the same type, which shall not be the Extension type - * itself (but we already checked for that). - * This is specially important if one has a reverse type! */ - unsigned int type = get_subtable (0).u.extension.get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 1; i < count; i++) - if (get_subtable (i).u.extension.get_type () != type) - return_trace (false); - } - return_trace (true); - } + bool sanitize (hb_sanitize_context_t *c) const + { return Lookup::sanitize<SubTable> (c); } }; -typedef OffsetListOf<SubstLookup> SubstLookupList; - /* * GSUB -- Glyph Substitution * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub @@ -1303,61 +1410,47 @@ typedef OffsetListOf<SubstLookup> SubstLookupList; struct GSUB : GSUBGPOS { - static const hb_tag_t tableTag = HB_OT_TAG_GSUB; + static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB; - inline const SubstLookup& get_lookup (unsigned int i) const + const SubstLookup& get_lookup (unsigned int i) const { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } - static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); + bool subset (hb_subset_context_t *c) const + { return GSUBGPOS::subset<SubstLookup> (c); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); - const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); - return_trace (list.sanitize (c, this)); - } -}; + bool sanitize (hb_sanitize_context_t *c) const + { return GSUBGPOS::sanitize<SubstLookup> (c); } + HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + hb_face_t *face) const; -void -GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) -{ - _hb_buffer_assert_gsubgpos_vars (buffer); + typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t; +}; - const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - { - _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); - _hb_glyph_info_clear_lig_props (&buffer->info[i]); - buffer->info[i].syllable() = 0; - } -} + +struct GSUB_accelerator_t : GSUB::accelerator_t {}; /* Out-of-class implementation for methods recursing */ -/*static*/ inline bool ExtensionSubst::is_reverse (void) const +/*static*/ inline bool ExtensionSubst::is_reverse () const { unsigned int type = get_type (); - if (unlikely (type == SubstLookupSubTable::Extension)) - return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse (); + if (unlikely (type == SubTable::Extension)) + return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse (); return SubstLookup::lookup_type_is_reverse (type); } template <typename context_t> /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { - const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); - const SubstLookup &l = gsub.get_lookup (lookup_index); + const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); return l.dispatch (c); } /*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { - const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); - const SubstLookup &l = gsub.get_lookup (lookup_index); + const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; unsigned int saved_lookup_index = c->lookup_index; c->set_lookup_index (lookup_index); @@ -1368,7 +1461,6 @@ template <typename context_t> return ret; } - } /* namespace OT */ diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos.hh index 661085d..88d834d 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -26,38 +26,54 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH -#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH - -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-buffer-private.hh" -#include "hb-map-private.hh" +#ifndef HB_OT_LAYOUT_GSUBGPOS_HH +#define HB_OT_LAYOUT_GSUBGPOS_HH + +#include "hb.hh" +#include "hb-buffer.hh" +#include "hb-map.hh" +#include "hb-set.hh" +#include "hb-ot-map.hh" +#include "hb-ot-layout-common.hh" #include "hb-ot-layout-gdef-table.hh" -#include "hb-set-private.hh" namespace OT { +struct hb_intersects_context_t : + hb_dispatch_context_t<hb_intersects_context_t, bool, 0> +{ + const char *get_name () { return "INTERSECTS"; } + template <typename T> + return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } + static return_t default_return_value () { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_set_t *glyphs; + unsigned int debug_depth; + + hb_intersects_context_t (const hb_set_t *glyphs_) : + glyphs (glyphs_), + debug_depth (0) {} +}; + struct hb_closure_context_t : - hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> + hb_dispatch_context_t<hb_closure_context_t, hb_void_t, 0> { - inline const char *get_name (void) { return "CLOSURE"; } + const char *get_name () { return "CLOSURE"; } typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); template <typename T> - inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } - static return_t default_return_value (void) { return HB_VOID; } - bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } + static return_t default_return_value () { return HB_VOID; } + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; nesting_level_left--; recurse_func (this, lookup_index); nesting_level_left++; - return HB_VOID; } bool should_visit_lookup (unsigned int lookup_index) @@ -70,29 +86,38 @@ struct hb_closure_context_t : bool is_lookup_done (unsigned int lookup_index) { - // Have we visited this lookup with the current set of glyphs? + /* Have we visited this lookup with the current set of glyphs? */ return done_lookups->get (lookup_index) == glyphs->get_population (); } hb_face_t *face; hb_set_t *glyphs; + hb_set_t out[1]; recurse_func_t recurse_func; unsigned int nesting_level_left; unsigned int debug_depth; hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, - hb_map_t *done_lookups_, - unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : + hb_map_t *done_lookups_, + unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), glyphs (glyphs_), recurse_func (nullptr), nesting_level_left (nesting_level_left_), debug_depth (0), - done_lookups (done_lookups_) {} + done_lookups (done_lookups_) {} + + ~hb_closure_context_t () { flush (); } void set_recurse_func (recurse_func_t func) { recurse_func = func; } + void flush () + { + hb_set_union (glyphs, out); + hb_set_clear (out); + } + private: hb_map_t *done_lookups; }; @@ -101,10 +126,10 @@ struct hb_closure_context_t : struct hb_would_apply_context_t : hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY> { - inline const char *get_name (void) { return "WOULD_APPLY"; } + const char *get_name () { return "WOULD_APPLY"; } template <typename T> - inline return_t dispatch (const T &obj) { return obj.would_apply (this); } - static return_t default_return_value (void) { return false; } + return_t dispatch (const T &obj) { return obj.would_apply (this); } + static return_t default_return_value () { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } hb_face_t *face; @@ -126,18 +151,17 @@ struct hb_would_apply_context_t : struct hb_collect_glyphs_context_t : - hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS> + hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, 0> { - inline const char *get_name (void) { return "COLLECT_GLYPHS"; } + const char *get_name () { return "COLLECT_GLYPHS"; } typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); template <typename T> - inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } - static return_t default_return_value (void) { return HB_VOID; } - bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } + static return_t default_return_value () { return HB_VOID; } + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get * past the previous check. For GSUB, we only want to collect the output @@ -150,11 +174,11 @@ struct hb_collect_glyphs_context_t : */ if (output == hb_set_get_empty ()) - return HB_VOID; + return; /* Return if new lookup was recursed to before. */ if (recursed_lookups->has (lookup_index)) - return HB_VOID; + return; hb_set_t *old_before = before; hb_set_t *old_input = input; @@ -170,8 +194,6 @@ struct hb_collect_glyphs_context_t : after = old_after; recursed_lookups->add (lookup_index); - - return HB_VOID; } hb_face_t *face; @@ -185,10 +207,10 @@ struct hb_collect_glyphs_context_t : unsigned int debug_depth; hb_collect_glyphs_context_t (hb_face_t *face_, - hb_set_t *glyphs_before, /* OUT. May be nullptr */ - hb_set_t *glyphs_input, /* OUT. May be nullptr */ - hb_set_t *glyphs_after, /* OUT. May be nullptr */ - hb_set_t *glyphs_output, /* OUT. May be nullptr */ + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output, /* OUT. May be NULL */ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), before (glyphs_before ? glyphs_before : hb_set_get_empty ()), @@ -196,33 +218,25 @@ struct hb_collect_glyphs_context_t : after (glyphs_after ? glyphs_after : hb_set_get_empty ()), output (glyphs_output ? glyphs_output : hb_set_get_empty ()), recurse_func (nullptr), - recursed_lookups (nullptr), + recursed_lookups (hb_set_create ()), nesting_level_left (nesting_level_left_), - debug_depth (0) - { - recursed_lookups = hb_set_create (); - } - ~hb_collect_glyphs_context_t (void) - { - hb_set_destroy (recursed_lookups); - } + debug_depth (0) {} + ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); } void set_recurse_func (recurse_func_t func) { recurse_func = func; } }; -/* XXX Can we remove this? */ - template <typename set_t> struct hb_add_coverage_context_t : hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> { - inline const char *get_name (void) { return "GET_COVERAGE"; } + const char *get_name () { return "GET_COVERAGE"; } typedef const Coverage &return_t; template <typename T> - inline return_t dispatch (const T &obj) { return obj.get_coverage (); } - static return_t default_return_value (void) { return Null(Coverage); } + return_t dispatch (const T &obj) { return obj.get_coverage (); } + static return_t default_return_value () { return Null(Coverage); } bool stop_sublookup_iteration (return_t r) const { r.add_coverage (set); @@ -243,7 +257,7 @@ struct hb_ot_apply_context_t : { struct matcher_t { - inline matcher_t (void) : + matcher_t () : lookup_props (0), ignore_zwnj (false), ignore_zwj (false), @@ -252,16 +266,16 @@ struct hb_ot_apply_context_t : syllable arg1(0), #undef arg1 match_func (nullptr), - match_data (nullptr) {}; + match_data (nullptr) {} typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); - inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } - inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } - inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } - inline void set_mask (hb_mask_t mask_) { mask = mask_; } - inline void set_syllable (uint8_t syllable_) { syllable = syllable_; } - inline void set_match_func (match_func_t match_func_, + void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } + void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } + void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } + void set_mask (hb_mask_t mask_) { mask = mask_; } + void set_syllable (uint8_t syllable_) { syllable = syllable_; } + void set_match_func (match_func_t match_func_, const void *match_data_) { match_func = match_func_; match_data = match_data_; } @@ -271,15 +285,15 @@ struct hb_ot_apply_context_t : MATCH_MAYBE }; - inline may_match_t may_match (const hb_glyph_info_t &info, - const HBUINT16 *glyph_data) const + may_match_t may_match (const hb_glyph_info_t &info, + const HBUINT16 *glyph_data) const { if (!(info.mask & mask) || (syllable && syllable != info.syllable ())) return MATCH_NO; if (match_func) - return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; + return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; return MATCH_MAYBE; } @@ -290,9 +304,8 @@ struct hb_ot_apply_context_t : SKIP_MAYBE }; - inline may_skip_t - may_skip (const hb_ot_apply_context_t *c, - const hb_glyph_info_t &info) const + may_skip_t may_skip (const hb_ot_apply_context_t *c, + const hb_glyph_info_t &info) const { if (!c->check_glyph_property (&info, lookup_props)) return SKIP_YES; @@ -317,31 +330,31 @@ struct hb_ot_apply_context_t : struct skipping_iterator_t { - inline void init (hb_ot_apply_context_t *c_, bool context_match = false) + void init (hb_ot_apply_context_t *c_, bool context_match = false) { c = c_; match_glyph_data = nullptr; matcher.set_match_func (nullptr, nullptr); matcher.set_lookup_props (c->lookup_props); - /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */ matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj)); - /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ - matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj)); + /* Ignore ZWJ if we are matching context, or asked to. */ + matcher.set_ignore_zwj (context_match || c->auto_zwj); matcher.set_mask (context_match ? -1 : c->lookup_mask); } - inline void set_lookup_props (unsigned int lookup_props) + void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } - inline void set_match_func (matcher_t::match_func_t match_func_, - const void *match_data_, - const HBUINT16 glyph_data[]) + void set_match_func (matcher_t::match_func_t match_func_, + const void *match_data_, + const HBUINT16 glyph_data[]) { matcher.set_match_func (match_func_, match_data_); match_glyph_data = glyph_data; } - inline void reset (unsigned int start_index_, + void reset (unsigned int start_index_, unsigned int num_items_) { idx = start_index_; @@ -350,15 +363,13 @@ struct hb_ot_apply_context_t : matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } - inline void reject (void) { num_items++; match_glyph_data--; } + void reject () { num_items++; match_glyph_data--; } - inline matcher_t::may_skip_t - may_skip (const hb_glyph_info_t &info) const - { - return matcher.may_skip (c, info); - } + matcher_t::may_skip_t + may_skip (const hb_glyph_info_t &info) const + { return matcher.may_skip (c, info); } - inline bool next (void) + bool next () { assert (num_items > 0); while (idx + num_items < end) @@ -385,10 +396,10 @@ struct hb_ot_apply_context_t : } return false; } - inline bool prev (void) + bool prev () { assert (num_items > 0); - while (idx >= num_items) + while (idx > num_items - 1) { idx--; const hb_glyph_info_t &info = c->buffer->out_info[idx]; @@ -424,11 +435,11 @@ struct hb_ot_apply_context_t : }; - inline const char *get_name (void) { return "APPLY"; } + const char *get_name () { return "APPLY"; } typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index); template <typename T> - inline return_t dispatch (const T &obj) { return obj.apply (this); } - static return_t default_return_value (void) { return false; } + return_t dispatch (const T &obj) { return obj.apply (this); } + static return_t default_return_value () { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } return_t recurse (unsigned int sub_lookup_index) { @@ -458,9 +469,12 @@ struct hb_ot_apply_context_t : unsigned int nesting_level_left; unsigned int debug_depth; + bool has_glyph_classes; bool auto_zwnj; bool auto_zwj; - bool has_glyph_classes; + bool random; + + uint32_t random_state; hb_ot_apply_context_t (unsigned int table_index_, @@ -469,7 +483,7 @@ struct hb_ot_apply_context_t : iter_input (), iter_context (), font (font_), face (font->face), buffer (buffer_), recurse_func (nullptr), - gdef (*hb_ot_layout_from_face (face)->gdef), + gdef (*face->table.GDEF->table), var_store (gdef.get_var_store ()), direction (buffer_->props.direction), lookup_mask (1), @@ -478,26 +492,36 @@ struct hb_ot_apply_context_t : lookup_props (0), nesting_level_left (HB_MAX_NESTING_LEVEL), debug_depth (0), + has_glyph_classes (gdef.has_glyph_classes ()), auto_zwnj (true), auto_zwj (true), - has_glyph_classes (gdef.has_glyph_classes ()) {} + random (false), + random_state (1) { init_iters (); } - inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } - inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } - inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; } - inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } - inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } - inline void set_lookup_props (unsigned int lookup_props_) + void init_iters () { - lookup_props = lookup_props_; iter_input.init (this, false); iter_context.init (this, true); } - inline bool - match_properties_mark (hb_codepoint_t glyph, - unsigned int glyph_props, - unsigned int match_props) const + void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); } + void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } + void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } + void set_random (bool random_) { random = random_; } + void set_recurse_func (recurse_func_t func) { recurse_func = func; } + void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } + void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); } + + uint32_t random_number () + { + /* http://www.cplusplus.com/reference/random/minstd_rand/ */ + random_state = random_state * 48271 % 2147483647; + return random_state; + } + + bool match_properties_mark (hb_codepoint_t glyph, + unsigned int glyph_props, + unsigned int match_props) const { /* If using mark filtering sets, the high short of * match_props has the set index. @@ -515,9 +539,8 @@ struct hb_ot_apply_context_t : return true; } - inline bool - check_glyph_property (const hb_glyph_info_t *info, - unsigned int match_props) const + bool check_glyph_property (const hb_glyph_info_t *info, + unsigned int match_props) const { hb_codepoint_t glyph = info->codepoint; unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); @@ -534,7 +557,7 @@ struct hb_ot_apply_context_t : return true; } - inline void _set_glyph_props (hb_codepoint_t glyph_index, + void _set_glyph_props (hb_codepoint_t glyph_index, unsigned int class_guess = 0, bool ligature = false, bool component = false) const @@ -547,7 +570,7 @@ struct hb_ot_apply_context_t : add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; /* In the only place that the MULTIPLIED bit is used, Uniscribe * seems to only care about the "last" transformation between - * Ligature and Multiple substitions. Ie. if you ligate, expand, + * Ligature and Multiple substitutions. Ie. if you ligate, expand, * and ligate again, it forgives the multiplication and acts as * if only ligation happened. As such, clear MULTIPLIED bit. */ @@ -561,23 +584,23 @@ struct hb_ot_apply_context_t : _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); } - inline void replace_glyph (hb_codepoint_t glyph_index) const + void replace_glyph (hb_codepoint_t glyph_index) const { _set_glyph_props (glyph_index); buffer->replace_glyph (glyph_index); } - inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const + void replace_glyph_inplace (hb_codepoint_t glyph_index) const { _set_glyph_props (glyph_index); buffer->cur().codepoint = glyph_index; } - inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, + void replace_glyph_with_ligature (hb_codepoint_t glyph_index, unsigned int class_guess) const { _set_glyph_props (glyph_index, class_guess, true); buffer->replace_glyph (glyph_index); } - inline void output_glyph_for_component (hb_codepoint_t glyph_index, + void output_glyph_for_component (hb_codepoint_t glyph_index, unsigned int class_guess) const { _set_glyph_props (glyph_index, class_guess, false, true); @@ -586,8 +609,65 @@ struct hb_ot_apply_context_t : }; +struct hb_get_subtables_context_t : + hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> +{ + template <typename Type> + static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) + { + const Type *typed_obj = (const Type *) obj; + return typed_obj->apply (c); + } + + typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); + + struct hb_applicable_t + { + template <typename T> + void init (const T &obj_, hb_apply_func_t apply_func_) + { + obj = &obj_; + apply_func = apply_func_; + digest.init (); + obj_.get_coverage ().add_coverage (&digest); + } + + bool apply (OT::hb_ot_apply_context_t *c) const + { + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); + } + + private: + const void *obj; + hb_apply_func_t apply_func; + hb_set_digest_t digest; + }; + + typedef hb_vector_t<hb_applicable_t> array_t; + + /* Dispatch interface. */ + const char *get_name () { return "GET_SUBTABLES"; } + template <typename T> + return_t dispatch (const T &obj) + { + hb_applicable_t *entry = array.push(); + entry->init (obj, apply_to<T>); + return HB_VOID; + } + static return_t default_return_value () { return HB_VOID; } + + hb_get_subtables_context_t (array_t &array_) : + array (array_), + debug_depth (0) {} + + array_t &array; + unsigned int debug_depth; +}; + + + -typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); +typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); @@ -605,29 +685,29 @@ struct ContextApplyFuncs }; -static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) +static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) { return glyphs->has (value); } -static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); return class_def.intersects_class (glyphs, value); } -static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; return (data+coverage).intersects (glyphs); } -static inline bool intersects_array (hb_closure_context_t *c, +static inline bool intersects_array (const hb_set_t *glyphs, unsigned int count, const HBUINT16 values[], intersects_func_t intersects_func, const void *intersects_data) { for (unsigned int i = 0; i < count; i++) - if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) + if (likely (!intersects_func (glyphs, values[i], intersects_data))) return false; return true; } @@ -696,7 +776,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, const void *match_data, unsigned int *end_offset, unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], - bool *p_is_mark_ligature = nullptr, unsigned int *p_total_component_count = nullptr) { TRACE_APPLY (nullptr); @@ -733,8 +812,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, * https://github.com/harfbuzz/harfbuzz/issues/545 */ - bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); - unsigned int total_component_count = 0; total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); @@ -764,9 +841,9 @@ static inline bool match_input (hb_ot_apply_context_t *c, * component, otherwise we shouldn't ligate them... */ if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) { - /* ...unless, we are attached to a base ligature and that base + /* ...unless, we are attached to a base ligature and that base * ligature is ignorable. */ - if (ligbase == LIGBASE_NOT_CHECKED) + if (ligbase == LIGBASE_NOT_CHECKED) { bool found = false; const hb_glyph_info_t *out = buffer->out_info; @@ -788,7 +865,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, ligbase = LIGBASE_MAY_NOT_SKIP; } - if (ligbase == LIGBASE_MAY_NOT_SKIP) + if (ligbase == LIGBASE_MAY_NOT_SKIP) return_trace (false); } } @@ -801,15 +878,11 @@ static inline bool match_input (hb_ot_apply_context_t *c, return_trace (false); } - is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); } *end_offset = skippy_iter.idx - buffer->idx + 1; - if (p_is_mark_ligature) - *p_is_mark_ligature = is_mark_ligature; - if (p_total_component_count) *p_total_component_count = total_component_count; @@ -817,10 +890,9 @@ static inline bool match_input (hb_ot_apply_context_t *c, } static inline bool ligate_input (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ + const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int match_length, hb_codepoint_t lig_glyph, - bool is_mark_ligature, unsigned int total_component_count) { TRACE_APPLY (nullptr); @@ -829,11 +901,15 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, buffer->merge_clusters (buffer->idx, buffer->idx + match_length); - /* - * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave + /* - If a base and one or more marks ligate, consider that as a base, NOT + * ligature, such that all following marks can still attach to it. + * https://github.com/harfbuzz/harfbuzz/issues/1109 + * + * - If all components of the ligature were marks, we call this a mark ligature. + * If it *is* a mark ligature, we don't allocate a new ligature id, and leave * the ligature to keep its old ligature id. This will allow it to attach to * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, - * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a + * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature * later, we don't want them to lose their ligature id/component, otherwise * GPOS will fail to correctly position the mark ligature on top of the @@ -857,13 +933,24 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, * https://bugzilla.gnome.org/show_bug.cgi?id=437633 */ - unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; - unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); + bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]); + bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]); + for (unsigned int i = 1; i < count; i++) + if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]])) + { + is_base_ligature = false; + is_mark_ligature = false; + break; + } + bool is_ligature = !is_base_ligature && !is_mark_ligature; + + unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0; + unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0; unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); unsigned int components_so_far = last_num_components; - if (!is_mark_ligature) + if (is_ligature) { _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) @@ -877,8 +964,9 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, { while (buffer->idx < match_positions[i] && buffer->successful) { - if (!is_mark_ligature) { - unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); + if (is_ligature) + { + unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (this_comp == 0) this_comp = last_num_components; unsigned int new_lig_comp = components_so_far - last_num_components + @@ -900,7 +988,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, /* Re-adjust components for any marks following. */ for (unsigned int i = buffer->idx; i < buffer->len; i++) { if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { - unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]); + unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]); if (!this_comp) break; unsigned int new_lig_comp = components_so_far - last_num_components + @@ -962,7 +1050,7 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c, struct LookupRecord { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -976,7 +1064,6 @@ struct LookupRecord DEFINE_SIZE_STATIC (4); }; - template <typename context_t> static inline void recurse_lookups (context_t *c, unsigned int lookupCount, @@ -1035,7 +1122,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, int delta = new_len - orig_len; if (!delta) - continue; + continue; /* Recursed lookup changed buffer len. Adjust. * @@ -1129,6 +1216,16 @@ struct ContextApplyLookupContext const void *match_data; }; +static inline bool context_intersects (const hb_set_t *glyphs, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + ContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data); +} + static inline void context_closure_lookup (hb_closure_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ const HBUINT16 input[], /* Array of input values--start with second glyph */ @@ -1136,9 +1233,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data)) + if (context_intersects (c->glyphs, + inputCount, input, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } @@ -1190,48 +1287,60 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, struct Rule { - inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const + bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + return context_intersects (glyphs, + inputCount, inputZ.arrayZ, + lookup_context); + } + + void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const + { + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > + (inputZ.as_array ((inputCount ? inputCount - 1 : 0))); context_closure_lookup (c, - inputCount, inputZ, - lookupCount, lookupRecord, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const + void collect_glyphs (hb_collect_glyphs_context_t *c, + ContextCollectGlyphsLookupContext &lookup_context) const { - TRACE_COLLECT_GLYPHS (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > + (inputZ.as_array (inputCount ? inputCount - 1 : 0)); context_collect_glyphs_lookup (c, - inputCount, inputZ, - lookupCount, lookupRecord, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + bool would_apply (hb_would_apply_context_t *c, + ContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > + (inputZ.as_array (inputCount ? inputCount - 1 : 0)); + return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); } - inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + bool apply (hb_ot_apply_context_t *c, + ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > + (inputZ.as_array (inputCount ? inputCount - 1 : 0)); + return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); } public: - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (inputCount.sanitize (c) && lookupCount.sanitize (c) && - c->check_range (inputZ, - inputZ[0].static_size * inputCount + + c->check_range (inputZ.arrayZ, + inputZ.item_size * (inputCount ? inputCount - 1 : 0) + LookupRecord::static_size * lookupCount)); } @@ -1240,9 +1349,11 @@ struct Rule * glyph sequence--includes the first * glyph */ HBUINT16 lookupCount; /* Number of LookupRecords */ - HBUINT16 inputZ[VAR]; /* Array of match inputs--start with + UnsizedArrayOf<HBUINT16> + inputZ; /* Array of match inputs--start with * second glyph */ -/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in +/*UnsizedArrayOf<LookupRecord> + lookupRecordX;*/ /* Array of LookupRecords--in * design order */ public: DEFINE_SIZE_ARRAY (4, inputZ); @@ -1250,47 +1361,59 @@ struct Rule struct RuleSet { - inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const + bool intersects (const hb_set_t *glyphs, + ContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } + + void closure (hb_closure_context_t *c, + ContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).closure (c, lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const + void collect_glyphs (hb_collect_glyphs_context_t *c, + ContextCollectGlyphsLookupContext &lookup_context) const { - TRACE_COLLECT_GLYPHS (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + bool would_apply (hb_would_apply_context_t *c, + ContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { if ((this+rule[i]).would_apply (c, lookup_context)) - return_trace (true); + return_trace (true); } return_trace (false); } - inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + bool apply (hb_ot_apply_context_t *c, + ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { if ((this+rule[i]).apply (c, lookup_context)) - return_trace (true); + return_trace (true); } return_trace (false); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (rule.sanitize (c, this)); @@ -1307,28 +1430,44 @@ struct RuleSet struct ContextFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const { - TRACE_CLOSURE (this); + struct ContextClosureLookupContext lookup_context = { + {intersects_glyph}, + nullptr + }; - const Coverage &cov = (this+coverage); + unsigned int count = ruleSet.len; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + void closure (hb_closure_context_t *c) const + { struct ContextClosureLookupContext lookup_context = { {intersects_glyph}, nullptr }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const RuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); struct ContextCollectGlyphsLookupContext lookup_context = { @@ -1341,7 +1480,7 @@ struct ContextFormat1 (this+ruleSet[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); @@ -1353,12 +1492,9 @@ struct ContextFormat1 return_trace (rule_set.would_apply (c, lookup_context)); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -1373,7 +1509,14 @@ struct ContextFormat1 return_trace (rule_set.apply (c, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); @@ -1394,9 +1537,29 @@ struct ContextFormat1 struct ContextFormat2 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &class_def = this+classDef; + + struct ContextClosureLookupContext lookup_context = { + {intersects_class}, + &class_def + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); if (!(this+coverage).intersects (c->glyphs)) return; @@ -1415,9 +1578,8 @@ struct ContextFormat2 } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); const ClassDef &class_def = this+classDef; @@ -1431,7 +1593,7 @@ struct ContextFormat2 (this+ruleSet[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); @@ -1445,12 +1607,9 @@ struct ContextFormat2 return_trace (rule_set.would_apply (c, lookup_context)); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -1466,7 +1625,14 @@ struct ContextFormat2 return_trace (rule_set.apply (c, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); @@ -1490,82 +1656,98 @@ struct ContextFormat2 struct ContextFormat3 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverageZ[0]).intersects (glyphs)) + return false; + + struct ContextClosureLookupContext lookup_context = { + {intersects_coverage}, + this + }; + return context_intersects (glyphs, + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + lookup_context); + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); if (!(this+coverageZ[0]).intersects (c->glyphs)) return; - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextClosureLookupContext lookup_context = { {intersects_coverage}, this }; context_closure_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ + 1), + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); (this+coverageZ[0]).add_coverage (c->input); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextCollectGlyphsLookupContext lookup_context = { {collect_coverage}, this }; context_collect_glyphs_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ + 1), + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); } - inline const Coverage &get_coverage (void) const - { - return this+coverageZ[0]; - } + const Coverage &get_coverage () const { return this+coverageZ[0]; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); unsigned int count = glyphCount; if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */ - if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false); + if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) if (!coverageZ[i].sanitize (c, this)) return_trace (false); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count); - return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); + return_trace (c->check_array (lookupRecord, lookupCount)); } protected: @@ -1573,10 +1755,11 @@ struct ContextFormat3 HBUINT16 glyphCount; /* Number of glyphs in the input glyph * sequence */ HBUINT16 lookupCount; /* Number of LookupRecords */ - OffsetTo<Coverage> - coverageZ[VAR]; /* Array of offsets to Coverage + UnsizedArrayOf<OffsetTo<Coverage> > + coverageZ; /* Array of offsets to Coverage * table in glyph sequence order */ -/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in +/*UnsizedArrayOf<LookupRecord> + lookupRecordX;*/ /* Array of LookupRecords--in * design order */ public: DEFINE_SIZE_ARRAY (6, coverageZ); @@ -1585,7 +1768,7 @@ struct ContextFormat3 struct Context { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -1627,6 +1810,26 @@ struct ChainContextApplyLookupContext const void *match_data[3]; }; +static inline bool chain_context_intersects (const hb_set_t *glyphs, + unsigned int backtrackCount, + const HBUINT16 backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT16 lookahead[], + ChainContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + backtrackCount, backtrack, + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) + && intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) + && intersects_array (glyphs, + lookaheadCount, lookahead, + lookup_context.funcs.intersects, lookup_context.intersects_data[2]); +} + static inline void chain_context_closure_lookup (hb_closure_context_t *c, unsigned int backtrackCount, const HBUINT16 backtrack[], @@ -1638,29 +1841,25 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ChainContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - backtrackCount, backtrack, - lookup_context.funcs.intersects, lookup_context.intersects_data[0]) - && intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data[1]) - && intersects_array (c, - lookaheadCount, lookahead, - lookup_context.funcs.intersects, lookup_context.intersects_data[2])) + if (chain_context_intersects (c->glyphs, + backtrackCount, backtrack, + inputCount, input, + lookaheadCount, lookahead, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, - unsigned int backtrackCount, - const HBUINT16 backtrack[], - unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT16 input[], /* Array of input values--start with second glyph */ - unsigned int lookaheadCount, - const HBUINT16 lookahead[], - unsigned int lookupCount, - const LookupRecord lookupRecord[], - ChainContextCollectGlyphsLookupContext &lookup_context) + unsigned int backtrackCount, + const HBUINT16 backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT16 lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ChainContextCollectGlyphsLookupContext &lookup_context) { collect_array (c, c->before, backtrackCount, backtrack, @@ -1718,43 +1917,55 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, lookup_context.funcs.match, lookup_context.match_data[2], match_length, &end_index) && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index), - apply_lookup (c, - inputCount, match_positions, - lookupCount, lookupRecord, - match_length)); + apply_lookup (c, + inputCount, match_positions, + lookupCount, lookupRecord, + match_length)); } struct ChainRule { - inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const + bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); + const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); + return chain_context_intersects (glyphs, + backtrack.len, backtrack.arrayZ, + input.lenP1, input.arrayZ, + lookahead.len, lookahead.arrayZ, + lookup_context); + } + + void closure (hb_closure_context_t *c, + ChainContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (this); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); chain_context_closure_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const + void collect_glyphs (hb_collect_glyphs_context_t *c, + ChainContextCollectGlyphsLookupContext &lookup_context) const { - TRACE_COLLECT_GLYPHS (this); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); chain_context_collect_glyphs_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + bool would_apply (hb_would_apply_context_t *c, + ChainContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); @@ -1762,12 +1973,12 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); return_trace (chain_context_would_apply_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context)); } - inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); @@ -1775,12 +1986,12 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); return_trace (chain_context_apply_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!backtrack.sanitize (c)) return_trace (false); @@ -1812,45 +2023,51 @@ struct ChainRule struct ChainRuleSet { - inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const + bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } + void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).closure (c, lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const + void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const { - TRACE_COLLECT_GLYPHS (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).would_apply (c, lookup_context)) - return_trace (true); + return_trace (true); return_trace (false); } - inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).apply (c, lookup_context)) - return_trace (true); + return_trace (true); return_trace (false); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (rule.sanitize (c, this)); @@ -1866,27 +2083,44 @@ struct ChainRuleSet struct ChainContextFormat1 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const { - TRACE_CLOSURE (this); - const Coverage &cov = (this+coverage); + struct ChainContextClosureLookupContext lookup_context = { + {intersects_glyph}, + {nullptr, nullptr, nullptr} + }; + unsigned int count = ruleSet.len; + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + + void closure (hb_closure_context_t *c) const + { struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph}, {nullptr, nullptr, nullptr} }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const ChainRuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); struct ChainContextCollectGlyphsLookupContext lookup_context = { @@ -1899,7 +2133,7 @@ struct ChainContextFormat1 (this+ruleSet[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); @@ -1911,12 +2145,9 @@ struct ChainContextFormat1 return_trace (rule_set.would_apply (c, lookup_context)); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -1930,7 +2161,14 @@ struct ChainContextFormat1 return_trace (rule_set.apply (c, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); @@ -1950,9 +2188,32 @@ struct ChainContextFormat1 struct ChainContextFormat2 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + struct ChainContextClosureLookupContext lookup_context = { + {intersects_class}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (input_class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); if (!(this+coverage).intersects (c->glyphs)) return; @@ -1975,9 +2236,8 @@ struct ChainContextFormat2 } } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); const ClassDef &backtrack_class_def = this+backtrackClassDef; @@ -1996,7 +2256,7 @@ struct ChainContextFormat2 (this+ruleSet[i]).collect_glyphs (c, lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); @@ -2015,12 +2275,9 @@ struct ChainContextFormat2 return_trace (rule_set.would_apply (c, lookup_context)); } - inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + const Coverage &get_coverage () const { return this+coverage; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -2041,7 +2298,14 @@ struct ChainContextFormat2 return_trace (rule_set.apply (c, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (coverage.sanitize (c, this) && @@ -2077,9 +2341,27 @@ struct ChainContextFormat2 struct ChainContextFormat3 { - inline void closure (hb_closure_context_t *c) const + bool intersects (const hb_set_t *glyphs) const + { + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + if (!(this+input[0]).intersects (glyphs)) + return false; + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); + struct ChainContextClosureLookupContext lookup_context = { + {intersects_coverage}, + {this, this, this} + }; + return chain_context_intersects (glyphs, + backtrack.len, (const HBUINT16 *) backtrack.arrayZ, + input.len, (const HBUINT16 *) input.arrayZ + 1, + lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + lookup_context); + } + + void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); if (!(this+input[0]).intersects (c->glyphs)) @@ -2099,9 +2381,8 @@ struct ChainContextFormat3 lookup_context); } - inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - TRACE_COLLECT_GLYPHS (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); (this+input[0]).add_coverage (c->input); @@ -2120,7 +2401,7 @@ struct ChainContextFormat3 lookup_context); } - inline bool would_apply (hb_would_apply_context_t *c) const + bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); @@ -2138,13 +2419,13 @@ struct ChainContextFormat3 lookup.len, lookup.arrayZ, lookup_context)); } - inline const Coverage &get_coverage (void) const + const Coverage &get_coverage () const { const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); return this+input[0]; } - inline bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); @@ -2165,7 +2446,14 @@ struct ChainContextFormat3 lookup.len, lookup.arrayZ, lookup_context)); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!backtrack.sanitize (c, this)) return_trace (false); @@ -2202,7 +2490,7 @@ struct ChainContextFormat3 struct ChainContext { template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -2227,31 +2515,31 @@ struct ChainContext template <typename T> struct ExtensionFormat1 { - inline unsigned int get_type (void) const { return extensionLookupType; } + unsigned int get_type () const { return extensionLookupType; } template <typename X> - inline const X& get_subtable (void) const + const X& get_subtable () const { unsigned int offset = extensionOffset; - if (unlikely (!offset)) return Null(typename T::LookupSubTable); - return StructAtOffset<typename T::LookupSubTable> (this, offset); + if (unlikely (!offset)) return Null(typename T::SubTable); + return StructAtOffset<typename T::SubTable> (this, offset); } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, format); if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ()); - return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ())); + return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ())); } /* This is called from may_dispatch() above with hb_sanitize_context_t. */ - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && extensionOffset != 0 && - extensionLookupType != T::LookupSubTable::Extension); + extensionLookupType != T::SubTable::Extension); } protected: @@ -2268,7 +2556,7 @@ struct ExtensionFormat1 template <typename T> struct Extension { - inline unsigned int get_type (void) const + unsigned int get_type () const { switch (u.format) { case 1: return u.format1.get_type (); @@ -2276,16 +2564,16 @@ struct Extension } } template <typename X> - inline const X& get_subtable (void) const + const X& get_subtable () const { switch (u.format) { - case 1: return u.format1.template get_subtable<typename T::LookupSubTable> (); - default:return Null(typename T::LookupSubTable); + case 1: return u.format1.template get_subtable<typename T::SubTable> (); + default:return Null(typename T::SubTable); } } template <typename context_t> - inline typename context_t::return_t dispatch (context_t *c) const + typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); @@ -2307,45 +2595,76 @@ struct Extension * GSUB/GPOS Common */ +struct hb_ot_layout_lookup_accelerator_t +{ + template <typename TLookup> + void init (const TLookup &lookup) + { + digest.init (); + lookup.add_coverage (&digest); + + subtables.init (); + OT::hb_get_subtables_context_t c_get_subtables (subtables); + lookup.dispatch (&c_get_subtables); + } + void fini () { subtables.fini (); } + + bool may_have (hb_codepoint_t g) const + { return digest.may_have (g); } + + bool apply (hb_ot_apply_context_t *c) const + { + for (unsigned int i = 0; i < subtables.length; i++) + if (subtables[i].apply (c)) + return true; + return false; + } + + private: + hb_set_digest_t digest; + hb_get_subtables_context_t::array_t subtables; +}; + struct GSUBGPOS { - inline unsigned int get_script_count (void) const + bool has_data () const { return version.to_int (); } + unsigned int get_script_count () const { return (this+scriptList).len; } - inline const Tag& get_script_tag (unsigned int i) const + const Tag& get_script_tag (unsigned int i) const { return (this+scriptList).get_tag (i); } - inline unsigned int get_script_tags (unsigned int start_offset, - unsigned int *script_count /* IN/OUT */, - hb_tag_t *script_tags /* OUT */) const + unsigned int get_script_tags (unsigned int start_offset, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */) const { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } - inline const Script& get_script (unsigned int i) const + const Script& get_script (unsigned int i) const { return (this+scriptList)[i]; } - inline bool find_script_index (hb_tag_t tag, unsigned int *index) const + bool find_script_index (hb_tag_t tag, unsigned int *index) const { return (this+scriptList).find_index (tag, index); } - inline unsigned int get_feature_count (void) const + unsigned int get_feature_count () const { return (this+featureList).len; } - inline hb_tag_t get_feature_tag (unsigned int i) const + hb_tag_t get_feature_tag (unsigned int i) const { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); } - inline unsigned int get_feature_tags (unsigned int start_offset, - unsigned int *feature_count /* IN/OUT */, - hb_tag_t *feature_tags /* OUT */) const + unsigned int get_feature_tags (unsigned int start_offset, + unsigned int *feature_count /* IN/OUT */, + hb_tag_t *feature_tags /* OUT */) const { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } - inline const Feature& get_feature (unsigned int i) const + const Feature& get_feature (unsigned int i) const { return (this+featureList)[i]; } - inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const + bool find_feature_index (hb_tag_t tag, unsigned int *index) const { return (this+featureList).find_index (tag, index); } - inline unsigned int get_lookup_count (void) const + unsigned int get_lookup_count () const { return (this+lookupList).len; } - inline const Lookup& get_lookup (unsigned int i) const + const Lookup& get_lookup (unsigned int i) const { return (this+lookupList)[i]; } - inline bool find_variations_index (const int *coords, unsigned int num_coords, - unsigned int *index) const + bool find_variations_index (const int *coords, unsigned int num_coords, + unsigned int *index) const { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations)) .find_index (coords, num_coords, index); } - inline const Feature& get_feature_variation (unsigned int feature_index, - unsigned int variations_index) const + const Feature& get_feature_variation (unsigned int feature_index, + unsigned int variations_index) const { if (FeatureVariations::NOT_FOUND_INDEX != variations_index && version.to_int () >= 0x00010001u) @@ -2353,22 +2672,88 @@ struct GSUBGPOS const Feature *feature = (this+featureVars).find_substitute (variations_index, feature_index); if (feature) - return *feature; + return *feature; } return get_feature (feature_index); } - inline bool sanitize (hb_sanitize_context_t *c) const + template <typename TLookup> + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct GSUBGPOS *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + out->scriptList.serialize_subset (c, this+scriptList, out); + out->featureList.serialize_subset (c, this+featureList, out); + + typedef OffsetListOf<TLookup> TLookupList; + /* TODO Use intersects() to count how many subtables survive? */ + CastR<OffsetTo<TLookupList> > (out->lookupList) + .serialize_subset (c, + this+CastR<const OffsetTo<TLookupList> > (lookupList), + out); + + if (version.to_int () >= 0x00010001u) + out->featureVars.serialize_subset (c, this+featureVars, out); + + return_trace (true); + } + + unsigned int get_size () const + { + return min_size + + (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); + } + + template <typename TLookup> + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + typedef OffsetListOf<TLookup> TLookupList; return_trace (version.sanitize (c) && likely (version.major == 1) && scriptList.sanitize (c, this) && featureList.sanitize (c, this) && - lookupList.sanitize (c, this) && + CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) && (version.to_int () < 0x00010001u || featureVars.sanitize (c, this))); } + template <typename T> + struct accelerator_t + { + void init (hb_face_t *face) + { + this->table = hb_sanitize_context_t().reference_table<T> (face); + if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) + { + hb_blob_destroy (this->table.get_blob ()); + this->table = hb_blob_get_empty (); + } + + this->lookup_count = table->get_lookup_count (); + + this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t)); + if (unlikely (!this->accels)) + this->lookup_count = 0; + + for (unsigned int i = 0; i < this->lookup_count; i++) + this->accels[i].init (table->get_lookup (i)); + } + + void fini () + { + for (unsigned int i = 0; i < this->lookup_count; i++) + this->accels[i].fini (); + free (this->accels); + this->table.destroy (); + } + + hb_blob_ptr_t<T> table; + unsigned int lookup_count; + hb_ot_layout_lookup_accelerator_t *accels; + }; + protected: FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set * to 0x00010000u */ @@ -2391,4 +2776,4 @@ struct GSUBGPOS } /* namespace OT */ -#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */ diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh index 7fabdeb..1dd31d5 100644 --- a/src/hb-ot-layout-jstf-table.hh +++ b/src/hb-ot-layout-jstf-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_LAYOUT_JSTF_TABLE_HH #define HB_OT_LAYOUT_JSTF_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-layout-gpos-table.hh" @@ -54,7 +54,7 @@ typedef OffsetListOf<PosLookup> JstfMax; struct JstfPriority { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -123,8 +123,8 @@ struct JstfPriority struct JstfLangSys : OffsetListOf<JstfPriority> { - inline bool sanitize (hb_sanitize_context_t *c, - const Record<JstfLangSys>::sanitize_closure_t * = nullptr) const + bool sanitize (hb_sanitize_context_t *c, + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (OffsetListOf<JstfPriority>::sanitize (c)); @@ -145,27 +145,27 @@ typedef SortedArrayOf<GlyphID> ExtenderGlyphs; struct JstfScript { - inline unsigned int get_lang_sys_count (void) const + unsigned int get_lang_sys_count () const { return langSys.len; } - inline const Tag& get_lang_sys_tag (unsigned int i) const + const Tag& get_lang_sys_tag (unsigned int i) const { return langSys.get_tag (i); } - inline unsigned int get_lang_sys_tags (unsigned int start_offset, - unsigned int *lang_sys_count /* IN/OUT */, - hb_tag_t *lang_sys_tags /* OUT */) const + unsigned int get_lang_sys_tags (unsigned int start_offset, + unsigned int *lang_sys_count /* IN/OUT */, + hb_tag_t *lang_sys_tags /* OUT */) const { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } - inline const JstfLangSys& get_lang_sys (unsigned int i) const + const JstfLangSys& get_lang_sys (unsigned int i) const { if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); return this+langSys[i].offset; } - inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const + bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const { return langSys.find_index (tag, index); } - inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } - inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } + bool has_default_lang_sys () const { return defaultLangSys != 0; } + const JstfLangSys& get_default_lang_sys () const { return this+defaultLangSys; } - inline bool sanitize (hb_sanitize_context_t *c, - const Record<JstfScript>::sanitize_closure_t * = nullptr) const + bool sanitize (hb_sanitize_context_t *c, + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (extenderGlyphs.sanitize (c, this) && @@ -195,22 +195,22 @@ struct JstfScript struct JSTF { - static const hb_tag_t tableTag = HB_OT_TAG_JSTF; + static constexpr hb_tag_t tableTag = HB_OT_TAG_JSTF; - inline unsigned int get_script_count (void) const + unsigned int get_script_count () const { return scriptList.len; } - inline const Tag& get_script_tag (unsigned int i) const + const Tag& get_script_tag (unsigned int i) const { return scriptList.get_tag (i); } - inline unsigned int get_script_tags (unsigned int start_offset, - unsigned int *script_count /* IN/OUT */, - hb_tag_t *script_tags /* OUT */) const + unsigned int get_script_tags (unsigned int start_offset, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */) const { return scriptList.get_tags (start_offset, script_count, script_tags); } - inline const JstfScript& get_script (unsigned int i) const + const JstfScript& get_script (unsigned int i) const { return this+scriptList[i].offset; } - inline bool find_script_index (hb_tag_t tag, unsigned int *index) const + bool find_script_index (hb_tag_t tag, unsigned int *index) const { return scriptList.find_index (tag, index); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 655c36c..d32be04 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -28,232 +28,201 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" -#include "hb-ot-layout-private.hh" -#include "hb-ot-map-private.hh" - +#include "hb-open-type.hh" +#include "hb-ot-layout.hh" +#include "hb-ot-face.hh" +#include "hb-ot-map.hh" +#include "hb-map.hh" + +#include "hb-ot-kern-table.hh" +#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" - -// Just so we compile them; unused otherwise: -#include "hb-ot-layout-base-table.hh" -#include "hb-ot-layout-jstf-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-name-table.hh" -#include "hb-map-private.hh" - - -hb_ot_layout_t * -_hb_ot_layout_create (hb_face_t *face) -{ - hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); - if (unlikely (!layout)) - return nullptr; - - layout->gdef_blob = OT::Sanitizer<OT::GDEF>().sanitize (face->reference_table (HB_OT_TAG_GDEF)); - layout->gdef = layout->gdef_blob->as<OT::GDEF> (); +#include "hb-ot-os2-table.hh" - layout->gsub_blob = OT::Sanitizer<OT::GSUB>().sanitize (face->reference_table (HB_OT_TAG_GSUB)); - layout->gsub = layout->gsub_blob->as<OT::GSUB> (); +#include "hb-aat-layout-lcar-table.hh" +#include "hb-aat-layout-morx-table.hh" - layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS)); - layout->gpos = layout->gpos_blob->as<OT::GPOS> (); - layout->math.init (face); - layout->fvar.init (face); - layout->avar.init (face); - - { - /* - * The ugly business of blacklisting individual fonts' tables happen here! - * See this thread for why we finally had to bend in and do this: - * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html - */ - unsigned int gdef_len = layout->gdef_blob->length; - unsigned int gsub_len = layout->gsub_blob->length; - unsigned int gpos_len = layout->gpos_blob->length; - if (0 - /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */ - || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len) - /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */ - || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len) - /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */ - || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len) - /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */ - || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len) - /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */ - || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len) - /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */ - || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len) - ) - { - /* In certain versions of Times New Roman Italic and Bold Italic, - * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong - * glyph class 3 (mark) in GDEF. Nuke the GDEF to avoid zero-width - * double-quote. See: - * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html - */ - if (3 == layout->gdef->get_glyph_class (5)) - layout->gdef = &Null(OT::GDEF); - } - else if (0 - /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */ - || (898 == gdef_len && 46470 == gpos_len && 12554 == gsub_len) - /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */ - || (910 == gdef_len && 47732 == gpos_len && 12566 == gsub_len) - /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */ - || (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len) - /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */ - || (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len) - /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - || (964 == gdef_len && 60072 == gpos_len && 23836 == gsub_len) - /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - || (976 == gdef_len && 61456 == gpos_len && 23832 == gsub_len) - /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */ - || (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len) - /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */ - || (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len) - /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - || (1006 == gdef_len && 61346 == gpos_len && 24576 == gsub_len) - /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - || (1018 == gdef_len && 62828 == gpos_len && 24572 == gsub_len) - /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */ - || (1006 == gdef_len && 61352 == gpos_len && 24576 == gsub_len) - /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */ - || (1018 == gdef_len && 62834 == gpos_len && 24572 == gsub_len) - /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */ - || (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len) - /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */ - || (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len) - /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */ - || (180 == gdef_len && 7254 == gpos_len && 13054 == gsub_len) - /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */ - || (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len) - /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */ - || (192 == gdef_len && 7254 == gpos_len && 12690 == gsub_len) - /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */ - /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */ - || (188 == gdef_len && 3852 == gpos_len && 248 == gsub_len) - /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */ - /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */ - || (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len) - /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */ - || (1058 == gdef_len && 11818 == gpos_len && 47032 == gsub_len) - /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/ - || (1046 == gdef_len && 12600 == gpos_len && 47030 == gsub_len) - /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */ - || (1058 == gdef_len && 16770 == gpos_len && 71796 == gsub_len) - /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */ - || (1046 == gdef_len && 17862 == gpos_len && 71790 == gsub_len) - /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */ - || (1046 == gdef_len && 17112 == gpos_len && 71788 == gsub_len) - /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */ - || (1058 == gdef_len && 17514 == gpos_len && 71794 == gsub_len) - /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */ - || (1330 == gdef_len && 57938 == gpos_len && 109904 == gsub_len) - /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */ - || (1330 == gdef_len && 58972 == gpos_len && 109904 == gsub_len) - /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf - * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */ - || (1004 == gdef_len && 14836 == gpos_len && 59092 == gsub_len) - ) - { - /* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks - * such as certain IPA symbols as glyph class 3. So do older versions of Microsoft Himalaya, - * and the version of Cantarell shipped by Ubuntu 16.04. - * Nuke the GDEF tables of these fonts to avoid unwanted width-zeroing. - * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 - * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693 - * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875 - */ - layout->gdef = &Null(OT::GDEF); - } - } +/** + * SECTION:hb-ot-layout + * @title: hb-ot-layout + * @short_description: OpenType Layout + * @include: hb-ot.h + * + * Functions for querying OpenType Layout features in the font face. + **/ - layout->gsub_lookup_count = layout->gsub->get_lookup_count (); - layout->gpos_lookup_count = layout->gpos->get_lookup_count (); - layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); - layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); +/* + * kern + */ - if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) || - (layout->gpos_lookup_count && !layout->gpos_accels))) - { - _hb_ot_layout_destroy (layout); - return nullptr; - } +bool +hb_ot_layout_has_kerning (hb_face_t *face) +{ + return face->table.kern->has_data (); +} - for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) - layout->gsub_accels[i].init (layout->gsub->get_lookup (i)); - for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) - layout->gpos_accels[i].init (layout->gpos->get_lookup (i)); +bool +hb_ot_layout_has_machine_kerning (hb_face_t *face) +{ + return face->table.kern->has_state_machine (); +} - return layout; +bool +hb_ot_layout_has_cross_kerning (hb_face_t *face) +{ + return face->table.kern->has_cross_stream (); } void -_hb_ot_layout_destroy (hb_ot_layout_t *layout) +hb_ot_layout_kern (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - if (layout->gsub_accels) - for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) - layout->gsub_accels[i].fini (); - if (layout->gpos_accels) - for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) - layout->gpos_accels[i].fini (); - - free (layout->gsub_accels); - free (layout->gpos_accels); + hb_blob_t *blob = font->face->table.kern.get_blob (); + const AAT::kern& kern = *blob->as<AAT::kern> (); - hb_blob_destroy (layout->gdef_blob); - hb_blob_destroy (layout->gsub_blob); - hb_blob_destroy (layout->gpos_blob); + AAT::hb_aat_apply_context_t c (plan, font, buffer, blob); - layout->math.fini (); - layout->fvar.fini (); - layout->avar.fini (); - - free (layout); + kern.apply (&c); } -// static inline const OT::BASE& -// _get_base (hb_face_t *face) -// { -// if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE); -// hb_ot_layout_t * layout = hb_ot_layout_from_face (face); -// return *(layout->base.get ()); -// } -static inline const OT::GDEF& -_get_gdef (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF); - return *hb_ot_layout_from_face (face)->gdef; -} -static inline const OT::GSUB& -_get_gsub (hb_face_t *face) +/* + * GDEF + */ + +bool +OT::GDEF::is_blacklisted (hb_blob_t *blob, + hb_face_t *face) const { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB); - return *hb_ot_layout_from_face (face)->gsub; + /* The ugly business of blacklisting individual fonts' tables happen here! + * See this thread for why we finally had to bend in and do this: + * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html + * + * In certain versions of Times New Roman Italic and Bold Italic, + * ASCII double quotation mark U+0022 has wrong glyph class 3 (mark) + * in GDEF. Many versions of Tahoma have bad GDEF tables that + * incorrectly classify some spacing marks such as certain IPA + * symbols as glyph class 3. So do older versions of Microsoft + * Himalaya, and the version of Cantarell shipped by Ubuntu 16.04. + * + * Nuke the GDEF tables of to avoid unwanted width-zeroing. + * + * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 + * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693 + * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875 + */ +#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z)) + switch ENCODE(blob->length, + face->table.GSUB->table.get_length (), + face->table.GPOS->table.get_length ()) + { + /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */ + case ENCODE (442, 2874, 42038): + /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */ + case ENCODE (430, 2874, 40662): + /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */ + case ENCODE (442, 2874, 39116): + /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */ + case ENCODE (430, 2874, 39374): + /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */ + case ENCODE (490, 3046, 41638): + /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */ + case ENCODE (478, 3046, 41902): + /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */ + case ENCODE (898, 12554, 46470): + /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */ + case ENCODE (910, 12566, 47732): + /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */ + case ENCODE (928, 23298, 59332): + /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */ + case ENCODE (940, 23310, 60732): + /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ + case ENCODE (964, 23836, 60072): + /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ + case ENCODE (976, 23832, 61456): + /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */ + case ENCODE (994, 24474, 60336): + /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */ + case ENCODE (1006, 24470, 61740): + /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ + case ENCODE (1006, 24576, 61346): + /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ + case ENCODE (1018, 24572, 62828): + /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */ + case ENCODE (1006, 24576, 61352): + /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */ + case ENCODE (1018, 24572, 62834): + /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */ + case ENCODE (832, 7324, 47162): + /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */ + case ENCODE (844, 7302, 45474): + /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */ + case ENCODE (180, 13054, 7254): + /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */ + case ENCODE (192, 12638, 7254): + /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */ + case ENCODE (192, 12690, 7254): + /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */ + /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */ + case ENCODE (188, 248, 3852): + /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */ + /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */ + case ENCODE (188, 264, 3426): + /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */ + case ENCODE (1058, 47032, 11818): + /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/ + case ENCODE (1046, 47030, 12600): + /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */ + case ENCODE (1058, 71796, 16770): + /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */ + case ENCODE (1046, 71790, 17862): + /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */ + case ENCODE (1046, 71788, 17112): + /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */ + case ENCODE (1058, 71794, 17514): + /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */ + case ENCODE (1330, 109904, 57938): + /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */ + case ENCODE (1330, 109904, 58972): + /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf + * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */ + case ENCODE (1004, 59092, 14836): + return true; +#undef ENCODE + } + return false; } -static inline const OT::GPOS& -_get_gpos (hb_face_t *face) + +static void +_hb_ot_layout_set_glyph_props (hb_font_t *font, + hb_buffer_t *buffer) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS); - return *hb_ot_layout_from_face (face)->gpos; + _hb_buffer_assert_gsubgpos_vars (buffer); + + const OT::GDEF &gdef = *font->face->table.GDEF->table; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + { + _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); + _hb_glyph_info_clear_lig_props (&buffer->info[i]); + buffer->info[i].syllable() = 0; + } } -/* - * GDEF - */ +/* Public API */ hb_bool_t hb_ot_layout_has_glyph_classes (hb_face_t *face) { - return _get_gdef (face).has_glyph_classes (); + return face->table.GDEF->table->has_glyph_classes (); } /** @@ -265,7 +234,7 @@ hb_ot_layout_glyph_class_t hb_ot_layout_get_glyph_class (hb_face_t *face, hb_codepoint_t glyph) { - return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); + return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph); } /** @@ -278,7 +247,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, hb_ot_layout_glyph_class_t klass, hb_set_t *glyphs /* OUT */) { - return _get_gdef (face).get_glyphs_in_class (klass, glyphs); + return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs); } unsigned int @@ -288,7 +257,10 @@ hb_ot_layout_get_attach_points (hb_face_t *face, unsigned int *point_count /* IN/OUT */, unsigned int *point_array /* OUT */) { - return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); + return face->table.GDEF->table->get_attach_points (glyph, + start_offset, + point_count, + point_array); } unsigned int @@ -299,7 +271,15 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font, unsigned int *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) { - return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); + unsigned int result_caret_count = 0; + unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array); + if (result) + { + if (caret_count) *caret_count = result_caret_count; + } + else + result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); + return result; } @@ -307,13 +287,45 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font, * GSUB/GPOS */ +bool +OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED, + hb_face_t *face) const +{ + /* Mac OS X prefers morx over GSUB. It also ships with various Indic fonts, + * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken + * GSUB/GPOS tables. Some have GSUB with zero scripts, those are ignored by + * our morx/GSUB preference code. But if GSUB has non-zero scripts, we tend + * to prefer it over morx because we want to be consistent with other OpenType + * shapers. + * + * To work around broken Indic Mac system fonts, we ignore GSUB table if + * OS/2 VendorId is 'MUTF' and font has morx table as well. + * + * https://github.com/harfbuzz/harfbuzz/issues/1410 + * https://github.com/harfbuzz/harfbuzz/issues/1348 + * https://github.com/harfbuzz/harfbuzz/issues/1391 + */ + if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') && + face->table.morx->has_data ())) + return true; + + return false; +} + +bool +OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED, + hb_face_t *face HB_UNUSED) const +{ + return false; +} + static const OT::GSUBGPOS& get_gsubgpos_table (hb_face_t *face, hb_tag_t table_tag) { switch (table_tag) { - case HB_OT_TAG_GSUB: return _get_gsub (face); - case HB_OT_TAG_GPOS: return _get_gpos (face); + case HB_OT_TAG_GSUB: return *face->table.GSUB->table; + case HB_OT_TAG_GPOS: return *face->table.GPOS->table; default: return Null(OT::GSUBGPOS); } } @@ -324,7 +336,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face, hb_tag_t table_tag, unsigned int start_offset, unsigned int *script_count /* IN/OUT */, - hb_tag_t *script_tags /* OUT */) + hb_tag_t *script_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -370,17 +382,36 @@ hb_ot_layout_table_choose_script (hb_face_t *face, unsigned int *script_index, hb_tag_t *chosen_script) { + const hb_tag_t *t; + for (t = script_tags; *t; t++); + return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script); +} + +/** + * hb_ot_layout_table_select_script: + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_table_select_script (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_count, + const hb_tag_t *script_tags, + unsigned int *script_index /* OUT */, + hb_tag_t *chosen_script /* OUT */) +{ static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), ""); const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + unsigned int i; - while (*script_tags) + for (i = 0; i < script_count; i++) { - if (g.find_script_index (*script_tags, script_index)) { + if (g.find_script_index (script_tags[i], script_index)) + { if (chosen_script) - *chosen_script = *script_tags; + *chosen_script = script_tags[i]; return true; } - script_tags++; } /* try finding 'DFLT' */ @@ -416,14 +447,14 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face, hb_tag_t table_tag, unsigned int start_offset, unsigned int *feature_count /* IN/OUT */, - hb_tag_t *feature_tags /* OUT */) + hb_tag_t *feature_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); return g.get_feature_tags (start_offset, feature_count, feature_tags); } -hb_bool_t +bool hb_ot_layout_table_find_feature (hb_face_t *face, hb_tag_t table_tag, hb_tag_t feature_tag, @@ -452,7 +483,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face, unsigned int script_index, unsigned int start_offset, unsigned int *language_count /* IN/OUT */, - hb_tag_t *language_tags /* OUT */) + hb_tag_t *language_tags /* OUT */) { const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); @@ -466,13 +497,38 @@ hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t language_tag, unsigned int *language_index) { + return hb_ot_layout_script_select_language (face, + table_tag, + script_index, + 1, + &language_tag, + language_index); +} + +/** + * hb_ot_layout_script_select_language: + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_script_select_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_count, + const hb_tag_t *language_tags, + unsigned int *language_index /* OUT */) +{ static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), ""); const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); + unsigned int i; - if (s.find_lang_sys_index (language_tag, language_index)) - return true; + for (i = 0; i < language_count; i++) + { + if (s.find_lang_sys_index (language_tags[i], language_index)) + return true; + } - /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ + /* try finding 'dflt' */ if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) return false; @@ -524,7 +580,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, unsigned int script_index, unsigned int language_index, unsigned int start_offset, - unsigned int *feature_count /* IN/OUT */, + unsigned int *feature_count /* IN/OUT */, unsigned int *feature_indexes /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -540,7 +596,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face, unsigned int language_index, unsigned int start_offset, unsigned int *feature_count /* IN/OUT */, - hb_tag_t *feature_tags /* OUT */) + hb_tag_t *feature_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); @@ -594,7 +650,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face, hb_tag_t table_tag, unsigned int feature_index, unsigned int start_offset, - unsigned int *lookup_count /* IN/OUT */, + unsigned int *lookup_count /* IN/OUT */, unsigned int *lookup_indexes /* OUT */) { return hb_ot_layout_feature_with_variations_get_lookups (face, @@ -615,207 +671,202 @@ unsigned int hb_ot_layout_table_get_lookup_count (hb_face_t *face, hb_tag_t table_tag) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return 0; - switch (table_tag) - { - case HB_OT_TAG_GSUB: - { - return hb_ot_layout_from_face (face)->gsub_lookup_count; - } - case HB_OT_TAG_GPOS: - { - return hb_ot_layout_from_face (face)->gpos_lookup_count; - } - } - return 0; + return get_gsubgpos_table (face, table_tag).get_lookup_count (); } -static void -_hb_ot_layout_collect_lookups_lookups (hb_face_t *face, - hb_tag_t table_tag, - unsigned int feature_index, - hb_set_t *lookup_indexes /* OUT */) + +struct hb_collect_features_context_t { - unsigned int lookup_indices[32]; - unsigned int offset, len; - - offset = 0; - do { - len = ARRAY_LENGTH (lookup_indices); - hb_ot_layout_feature_get_lookups (face, - table_tag, - feature_index, - offset, &len, - lookup_indices); - - for (unsigned int i = 0; i < len; i++) - lookup_indexes->add (lookup_indices[i]); - - offset += len; - } while (len == ARRAY_LENGTH (lookup_indices)); -} + hb_collect_features_context_t (hb_face_t *face, + hb_tag_t table_tag, + hb_set_t *feature_indexes_) + : g (get_gsubgpos_table (face, table_tag)), + feature_indexes (feature_indexes_), + script_count(0),langsys_count(0) {} + + bool visited (const OT::Script &s) + { + /* We might have Null() object here. Don't want to involve + * that in the memoize. So, detect empty objects and return. */ + if (unlikely (!s.has_default_lang_sys () && + !s.get_lang_sys_count ())) + return true; + + if (script_count++ > HB_MAX_SCRIPTS) + return true; + + return visited (s, visited_script); + } + bool visited (const OT::LangSys &l) + { + /* We might have Null() object here. Don't want to involve + * that in the memoize. So, detect empty objects and return. */ + if (unlikely (!l.has_required_feature () && + !l.get_feature_count ())) + return true; + + if (langsys_count++ > HB_MAX_LANGSYS) + return true; + + return visited (l, visited_langsys); + } + + private: + template <typename T> + bool visited (const T &p, hb_set_t &visited_set) + { + hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g); + if (visited_set.has (delta)) + return true; + + visited_set.add (delta); + return false; + } + + public: + const OT::GSUBGPOS &g; + hb_set_t *feature_indexes; + + private: + hb_set_t visited_script; + hb_set_t visited_langsys; + unsigned int script_count; + unsigned int langsys_count; +}; static void -_hb_ot_layout_collect_lookups_features (hb_face_t *face, - hb_tag_t table_tag, - unsigned int script_index, - unsigned int language_index, - const hb_tag_t *features, - hb_set_t *lookup_indexes /* OUT */) +langsys_collect_features (hb_collect_features_context_t *c, + const OT::LangSys &l, + const hb_tag_t *features) { + if (c->visited (l)) return; + if (!features) { - unsigned int required_feature_index; - if (hb_ot_layout_language_get_required_feature (face, - table_tag, - script_index, - language_index, - &required_feature_index, - nullptr)) - _hb_ot_layout_collect_lookups_lookups (face, - table_tag, - required_feature_index, - lookup_indexes); - - /* All features */ - unsigned int feature_indices[32]; - unsigned int offset, len; - - offset = 0; - do { - len = ARRAY_LENGTH (feature_indices); - hb_ot_layout_language_get_feature_indexes (face, - table_tag, - script_index, - language_index, - offset, &len, - feature_indices); - - for (unsigned int i = 0; i < len; i++) - _hb_ot_layout_collect_lookups_lookups (face, - table_tag, - feature_indices[i], - lookup_indexes); - - offset += len; - } while (len == ARRAY_LENGTH (feature_indices)); + /* All features. */ + if (l.has_required_feature ()) + c->feature_indexes->add (l.get_required_feature_index ()); + + l.add_feature_indexes_to (c->feature_indexes); } else { + /* Ugh. Any faster way? */ for (; *features; features++) { - unsigned int feature_index; - if (hb_ot_layout_language_find_feature (face, - table_tag, - script_index, - language_index, - *features, - &feature_index)) - _hb_ot_layout_collect_lookups_lookups (face, - table_tag, - feature_index, - lookup_indexes); + hb_tag_t feature_tag = *features; + unsigned int num_features = l.get_feature_count (); + for (unsigned int i = 0; i < num_features; i++) + { + unsigned int feature_index = l.get_feature_index (i); + + if (feature_tag == c->g.get_feature_tag (feature_index)) + { + c->feature_indexes->add (feature_index); + break; + } + } } } } static void -_hb_ot_layout_collect_lookups_languages (hb_face_t *face, - hb_tag_t table_tag, - unsigned int script_index, - const hb_tag_t *languages, - const hb_tag_t *features, - hb_set_t *lookup_indexes /* OUT */) +script_collect_features (hb_collect_features_context_t *c, + const OT::Script &s, + const hb_tag_t *languages, + const hb_tag_t *features) { - _hb_ot_layout_collect_lookups_features (face, - table_tag, - script_index, - HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, - features, - lookup_indexes); + if (c->visited (s)) return; if (!languages) { - /* All languages */ - unsigned int count = hb_ot_layout_script_get_language_tags (face, - table_tag, - script_index, - 0, nullptr, nullptr); + /* All languages. */ + if (s.has_default_lang_sys ()) + langsys_collect_features (c, + s.get_default_lang_sys (), + features); + + unsigned int count = s.get_lang_sys_count (); for (unsigned int language_index = 0; language_index < count; language_index++) - _hb_ot_layout_collect_lookups_features (face, - table_tag, - script_index, - language_index, - features, - lookup_indexes); + langsys_collect_features (c, + s.get_lang_sys (language_index), + features); } else { for (; *languages; languages++) { unsigned int language_index; - if (hb_ot_layout_script_find_language (face, - table_tag, - script_index, - *languages, - &language_index)) - _hb_ot_layout_collect_lookups_features (face, - table_tag, - script_index, - language_index, - features, - lookup_indexes); + if (s.find_lang_sys_index (*languages, &language_index)) + langsys_collect_features (c, + s.get_lang_sys (language_index), + features); } } } /** - * hb_ot_layout_collect_lookups: + * hb_ot_layout_collect_features: * - * Since: 0.9.8 + * Since: 1.8.5 **/ void -hb_ot_layout_collect_lookups (hb_face_t *face, - hb_tag_t table_tag, - const hb_tag_t *scripts, - const hb_tag_t *languages, - const hb_tag_t *features, - hb_set_t *lookup_indexes /* OUT */) +hb_ot_layout_collect_features (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *feature_indexes /* OUT */) { + hb_collect_features_context_t c (face, table_tag, feature_indexes); if (!scripts) { - /* All scripts */ - unsigned int count = hb_ot_layout_table_get_script_tags (face, - table_tag, - 0, nullptr, nullptr); + /* All scripts. */ + unsigned int count = c.g.get_script_count (); for (unsigned int script_index = 0; script_index < count; script_index++) - _hb_ot_layout_collect_lookups_languages (face, - table_tag, - script_index, - languages, - features, - lookup_indexes); + script_collect_features (&c, + c.g.get_script (script_index), + languages, + features); } else { for (; *scripts; scripts++) { unsigned int script_index; - if (hb_ot_layout_table_find_script (face, - table_tag, - *scripts, - &script_index)) - _hb_ot_layout_collect_lookups_languages (face, - table_tag, - script_index, - languages, - features, - lookup_indexes); + if (c.g.find_script_index (*scripts, &script_index)) + script_collect_features (&c, + c.g.get_script (script_index), + languages, + features); } } } /** + * hb_ot_layout_collect_lookups: + * + * Since: 0.9.8 + **/ +void +hb_ot_layout_collect_lookups (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + + hb_set_t feature_indexes; + hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes); + + for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; + hb_set_next (&feature_indexes, &feature_index);) + g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); +} + +/** * hb_ot_layout_lookup_collect_glyphs: * * Since: 0.9.7 @@ -824,13 +875,11 @@ void hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_tag_t table_tag, unsigned int lookup_index, - hb_set_t *glyphs_before, /* OUT. May be nullptr */ - hb_set_t *glyphs_input, /* OUT. May be nullptr */ - hb_set_t *glyphs_after, /* OUT. May be nullptr */ - hb_set_t *glyphs_output /* OUT. May be nullptr */) + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; - OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, @@ -841,13 +890,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, { case HB_OT_TAG_GSUB: { - const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); + const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); l.collect_glyphs (&c); return; } case HB_OT_TAG_GPOS: { - const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); + const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index); l.collect_glyphs (&c); return; } @@ -894,7 +943,7 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face) { - return &_get_gsub (face) != &Null(OT::GSUB); + return face->table.GSUB->table->has_data (); } /** @@ -909,29 +958,82 @@ hb_ot_layout_lookup_would_substitute (hb_face_t *face, unsigned int glyphs_length, hb_bool_t zero_context) { - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false; - return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context); + return hb_ot_layout_lookup_would_substitute_fast (face, + lookup_index, + glyphs, glyphs_length, + zero_context); } -hb_bool_t +bool hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, - hb_bool_t zero_context) + bool zero_context) { - if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; + if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false; OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); - const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); + const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); - return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]); + return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]); } void -hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) +hb_ot_layout_substitute_start (hb_font_t *font, + hb_buffer_t *buffer) { - OT::GSUB::substitute_start (font, buffer); +_hb_ot_layout_set_glyph_props (font, buffer); +} + +void +hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer, + bool (*filter) (const hb_glyph_info_t *info)) +{ + /* Merge clusters and delete filtered glyphs. + * NOTE! We can't use out-buffer as we have positioning data. */ + unsigned int j = 0; + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + for (unsigned int i = 0; i < count; i++) + { + if (filter (&info[i])) + { + /* Merge clusters. + * Same logic as buffer->delete_glyph(), but for in-place removal. */ + + unsigned int cluster = info[i].cluster; + if (i + 1 < count && cluster == info[i + 1].cluster) + continue; /* Cluster survives; do nothing. */ + + if (j) + { + /* Merge cluster backward. */ + if (cluster < info[j - 1].cluster) + { + unsigned int mask = info[i].mask; + unsigned int old_cluster = info[j - 1].cluster; + for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) + buffer->set_cluster (info[k - 1], cluster, mask); + } + continue; + } + + if (i + 1 < count) + buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */ + + continue; + } + + if (j != i) + { + info[j] = info[i]; + pos[j] = pos[i]; + } + j++; + } + buffer->len = j; } /** @@ -944,10 +1046,10 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs) { - hb_auto_t<hb_map_t> done_lookups; + hb_map_t done_lookups; OT::hb_closure_context_t c (face, glyphs, &done_lookups); - const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index); + const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); l.closure (&c, lookup_index); } @@ -965,10 +1067,11 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, const hb_set_t *lookups, hb_set_t *glyphs) { - hb_auto_t<hb_map_t> done_lookups; + hb_map_t done_lookups; OT::hb_closure_context_t c (face, glyphs, &done_lookups); - const OT::GSUB& gsub = _get_gsub (face); + const OT::GSUB& gsub = *face->table.GSUB->table; + unsigned int iteration_count = 0; unsigned int glyphs_length; do { @@ -983,7 +1086,8 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, for (unsigned int i = 0; i < gsub.get_lookup_count (); i++) gsub.get_lookup (i).closure (&c, i); } - } while (glyphs_length != glyphs->get_population ()); + } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && + glyphs_length != glyphs->get_population ()); } /* @@ -993,7 +1097,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face) { - return &_get_gpos (face) != &Null(OT::GPOS); + return face->table.GPOS->table->has_data (); } void @@ -1020,14 +1124,14 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) * Since: 0.9.10 **/ hb_bool_t -hb_ot_layout_get_size_params (hb_face_t *face, - unsigned int *design_size, /* OUT. May be nullptr */ - unsigned int *subfamily_id, /* OUT. May be nullptr */ - unsigned int *subfamily_name_id, /* OUT. May be nullptr */ - unsigned int *range_start, /* OUT. May be nullptr */ - unsigned int *range_end /* OUT. May be nullptr */) +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */) { - const OT::GPOS &gpos = _get_gpos (face); + const OT::GPOS &gpos = *face->table.GPOS->table; const hb_tag_t tag = HB_TAG ('s','i','z','e'); unsigned int num_features = gpos.get_feature_count (); @@ -1040,30 +1144,152 @@ hb_ot_layout_get_size_params (hb_face_t *face, if (params.designSize) { -#define PARAM(a, A) if (a) *a = params.A - PARAM (design_size, designSize); - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); -#undef PARAM + if (design_size) *design_size = params.designSize; + if (subfamily_id) *subfamily_id = params.subfamilyID; + if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID; + if (range_start) *range_start = params.rangeStart; + if (range_end) *range_end = params.rangeEnd; return true; } } } -#define PARAM(a, A) if (a) *a = 0 - PARAM (design_size, designSize); - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); -#undef PARAM + if (design_size) *design_size = 0; + if (subfamily_id) *subfamily_id = 0; + if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID; + if (range_start) *range_start = 0; + if (range_end) *range_end = 0; return false; } +/** + * hb_ot_layout_feature_get_name_ids: + * @face: #hb_face_t to work upon + * @table_tag: table tag to query, "GSUB" or "GPOS". + * @feature_index: index of feature to query. + * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string + * for a user-interface label for this feature. (May be NULL.) + * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string + * that an application can use for tooltip text for this + * feature. (May be NULL.) + * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text + * that illustrates the effect of this feature. (May be NULL.) + * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.) + * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify + * strings for user-interface labels for the feature + * parameters. (Must be zero if numParameters is zero.) + * + * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or + * "Character Variant" ('cvXX') features. + * + * Return value: true if data found, false otherwise + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_feature_get_name_ids (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + hb_ot_name_id_t *label_id, /* OUT. May be NULL */ + hb_ot_name_id_t *tooltip_id, /* OUT. May be NULL */ + hb_ot_name_id_t *sample_id, /* OUT. May be NULL */ + unsigned int *num_named_parameters, /* OUT. May be NULL */ + hb_ot_name_id_t *first_param_id /* OUT. May be NULL */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + + hb_tag_t feature_tag = g.get_feature_tag (feature_index); + const OT::Feature &f = g.get_feature (feature_index); + + const OT::FeatureParams &feature_params = f.get_feature_params (); + if (&feature_params != &Null (OT::FeatureParams)) + { + const OT::FeatureParamsStylisticSet& ss_params = + feature_params.get_stylistic_set_params (feature_tag); + if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */ + { + if (label_id) *label_id = ss_params.uiNameID; + // ssXX features don't have the rest + if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID; + if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID; + if (num_named_parameters) *num_named_parameters = 0; + if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID; + return true; + } + const OT::FeatureParamsCharacterVariants& cv_params = + feature_params.get_character_variants_params (feature_tag); + if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */ + { + if (label_id) *label_id = cv_params.featUILableNameID; + if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID; + if (sample_id) *sample_id = cv_params.sampleTextNameID; + if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters; + if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID; + return true; + } + } + + if (label_id) *label_id = HB_OT_NAME_ID_INVALID; + if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID; + if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID; + if (num_named_parameters) *num_named_parameters = 0; + if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID; + return false; +} + +/** + * hb_ot_layout_feature_get_characters: + * @face: #hb_face_t to work upon + * @table_tag: table tag to query, "GSUB" or "GPOS". + * @feature_index: index of feature to query. + * @start_offset: In case the resulting char_count was equal to its input value, there + * is a chance there were more characters on the tag so this API can be + * called with an offset till resulting char_count gets to a number + * lower than input buffer (or consider using just a bigger buffer for + * one shot copying). + * @char_count: (inout) (allow-none): The count of characters for which this feature + * provides glyph variants. (May be zero.) + * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. The Unicode codepoints + * of the characters for which this feature provides glyph variants. + * + * Fetches characters listed by designer under feature parameters for "Character + * Variant" ("cvXX") features. + * + * Return value: Number of total sample characters in the cvXX feature. + * + * Since: 2.0.0 + **/ +unsigned int +hb_ot_layout_feature_get_characters (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *char_count, /* IN/OUT. May be NULL */ + hb_codepoint_t *characters /* OUT. May be NULL */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + + hb_tag_t feature_tag = g.get_feature_tag (feature_index); + const OT::Feature &f = g.get_feature (feature_index); + + const OT::FeatureParams &feature_params = f.get_feature_params (); + + const OT::FeatureParamsCharacterVariants& cv_params = + feature_params.get_character_variants_params(feature_tag); + + unsigned int len = 0; + if (char_count && characters && start_offset < cv_params.characters.len) + { + len = MIN (cv_params.characters.len - start_offset, *char_count); + for (unsigned int i = 0; i < len; ++i) + characters[i] = cv_params.characters[start_offset + i]; + } + if (char_count) *char_count = len; + return cv_params.characters.len; +} + /* * Parts of different types are implemented here such that they have direct @@ -1073,86 +1299,36 @@ hb_ot_layout_get_size_params (hb_face_t *face, struct GSUBProxy { - static const unsigned int table_index = 0; - static const bool inplace = false; + static constexpr unsigned table_index = 0u; + static constexpr bool inplace = false; typedef OT::SubstLookup Lookup; GSUBProxy (hb_face_t *face) : - table (*hb_ot_layout_from_face (face)->gsub), - accels (hb_ot_layout_from_face (face)->gsub_accels) {} + table (*face->table.GSUB->table), + accels (face->table.GSUB->accels) {} const OT::GSUB &table; - const hb_ot_layout_lookup_accelerator_t *accels; + const OT::hb_ot_layout_lookup_accelerator_t *accels; }; struct GPOSProxy { - static const unsigned int table_index = 1; - static const bool inplace = true; + static constexpr unsigned table_index = 1u; + static constexpr bool inplace = true; typedef OT::PosLookup Lookup; GPOSProxy (hb_face_t *face) : - table (*hb_ot_layout_from_face (face)->gpos), - accels (hb_ot_layout_from_face (face)->gpos_accels) {} + table (*face->table.GPOS->table), + accels (face->table.GPOS->accels) {} const OT::GPOS &table; - const hb_ot_layout_lookup_accelerator_t *accels; + const OT::hb_ot_layout_lookup_accelerator_t *accels; }; -struct hb_get_subtables_context_t : - OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> -{ - template <typename Type> - static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) - { - const Type *typed_obj = (const Type *) obj; - return typed_obj->apply (c); - } - - typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); - - struct hb_applicable_t - { - inline void init (const void *obj_, hb_apply_func_t apply_func_) - { - obj = obj_; - apply_func = apply_func_; - } - - inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); } - - private: - const void *obj; - hb_apply_func_t apply_func; - }; - - typedef hb_auto_t<hb_vector_t<hb_applicable_t> > array_t; - - /* Dispatch interface. */ - inline const char *get_name (void) { return "GET_SUBTABLES"; } - template <typename T> - inline return_t dispatch (const T &obj) - { - hb_applicable_t *entry = array.push(); - entry->init (&obj, apply_to<T>); - return HB_VOID; - } - static return_t default_return_value (void) { return HB_VOID; } - bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - - hb_get_subtables_context_t (array_t &array_) : - array (array_), - debug_depth (0) {} - - array_t &array; - unsigned int debug_depth; -}; - static inline bool apply_forward (OT::hb_ot_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t &accel, - const hb_get_subtables_context_t::array_t &subtables) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1163,12 +1339,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) { - for (unsigned int i = 0; i < subtables.len; i++) - if (subtables[i].apply (c)) - { - applied = true; - break; - } + applied = accel.apply (c); } if (applied) @@ -1181,8 +1352,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, static inline bool apply_backward (OT::hb_ot_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t &accel, - const hb_get_subtables_context_t::array_t &subtables) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1191,14 +1361,8 @@ apply_backward (OT::hb_ot_apply_context_t *c, if (accel.may_have (buffer->cur().codepoint) && (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) - { - for (unsigned int i = 0; i < subtables.len; i++) - if (subtables[i].apply (c)) - { - ret = true; - break; - } - } + ret |= accel.apply (c); + /* The reverse lookup doesn't "advance" cursor (for good reason). */ buffer->idx--; @@ -1211,7 +1375,7 @@ template <typename Proxy> static inline void apply_string (OT::hb_ot_apply_context_t *c, const typename Proxy::Lookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { hb_buffer_t *buffer = c->buffer; @@ -1220,19 +1384,15 @@ apply_string (OT::hb_ot_apply_context_t *c, c->set_lookup_props (lookup.get_props ()); - hb_get_subtables_context_t::array_t subtables; - hb_get_subtables_context_t c_get_subtables (subtables); - lookup.dispatch (&c_get_subtables); - if (likely (!lookup.is_reverse ())) { /* in/out forward substitution/positioning */ - if (Proxy::table_index == 0) + if (Proxy::table_index == 0u) buffer->clear_output (); buffer->idx = 0; bool ret; - ret = apply_forward (c, accel, subtables); + ret = apply_forward (c, accel); if (ret) { if (!Proxy::inplace) @@ -1244,11 +1404,11 @@ apply_string (OT::hb_ot_apply_context_t *c, else { /* in-place backward substitution/positioning */ - if (Proxy::table_index == 0) + if (Proxy::table_index == 0u) buffer->remove_output (); buffer->idx = buffer->len - 1; - apply_backward (c, accel, subtables); + apply_backward (c, accel); } } @@ -1263,7 +1423,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, OT::hb_ot_apply_context_t c (table_index, font, buffer); c.set_recurse_func (Proxy::Lookup::apply_recurse_func); - for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { + for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) { const stage_map_t *stage = &stages[table_index][stage_index]; for (; i < stage->last_lookup; i++) { @@ -1273,6 +1433,11 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, c.set_lookup_mask (lookups[table_index][i].mask); c.set_auto_zwj (lookups[table_index][i].auto_zwj); c.set_auto_zwnj (lookups[table_index][i].auto_zwnj); + if (lookups[table_index][i].random) + { + c.set_random (true); + buffer->unsafe_to_break_all (); + } apply_string<Proxy> (&c, proxy.table.get_lookup (lookup_index), proxy.accels[lookup_index]); @@ -1302,31 +1467,65 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_ void hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, const OT::SubstLookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { apply_string<GSUBProxy> (c, lookup, accel); } +#if 0 +static const OT::BASE& _get_base (hb_face_t *face) +{ + return *face->table.BASE; +} +hb_bool_t +hb_ot_layout_get_baseline (hb_font_t *font, + hb_ot_layout_baseline_t baseline, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT. May be NULL. */) +{ + const OT::BASE &base = _get_base (font->face); + bool result = base.get_baseline (font, baseline, direction, script_tag, + language_tag, coord); + /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */ + if (!result && coord) *coord = 0; + if (coord) *coord = font->em_scale_dir (*coord, direction); + + return result; +} + +/* To be moved to public header */ /* - * OT::BASE + * BASE */ -// /** -// * hb_ot_base_has_data: -// * @face: #hb_face_t to test -// * -// * This function allows to verify the presence of an OpenType BASE table on the -// * face. -// * -// * Return value: true if face has a BASE table, false otherwise -// * -// * Since: XXX -// **/ -// hb_bool_t -// hb_ot_base_has_data (hb_face_t *face) -// { -// return &_get_base (face) != &Null(OT::BASE); -// } +/** + * hb_ot_layout_baseline_t: + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags + * + * Since: DONTREPLACEME + */ +typedef enum { + HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'), + HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'), + HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'), + HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'), + HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'), + HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'), + HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n') +} hb_ot_layout_baseline_t; + +HB_EXTERN hb_bool_t +hb_ot_layout_get_baseline (hb_font_t *font, + hb_ot_layout_baseline_t baseline, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT. May be NULL. */); + +#endif diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 0278796..e473954 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -33,7 +33,7 @@ #include "hb.h" -#include "hb-ot-tag.h" +#include "hb-ot-name.h" HB_BEGIN_DECLS @@ -46,6 +46,47 @@ HB_BEGIN_DECLS /* + * Script & Language tags. + */ + +#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T') +#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't') + +/** + * HB_OT_MAX_TAGS_PER_SCRIPT: + * + * Since: 2.0.0 + **/ +#define HB_OT_MAX_TAGS_PER_SCRIPT 3u +/** + * HB_OT_MAX_TAGS_PER_LANGUAGE: + * + * Since: 2.0.0 + **/ +#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u + +HB_EXTERN void +hb_ot_tags_from_script_and_language (hb_script_t script, + hb_language_t language, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */, + unsigned int *language_count /* IN/OUT */, + hb_tag_t *language_tags /* OUT */); + +HB_EXTERN hb_script_t +hb_ot_tag_to_script (hb_tag_t tag); + +HB_EXTERN hb_language_t +hb_ot_tag_to_language (hb_tag_t tag); + +HB_EXTERN void +hb_ot_tags_to_script_and_language (hb_tag_t script_tag, + hb_tag_t language_tag, + hb_script_t *script /* OUT */, + hb_language_t *language /* OUT */); + + +/* * GDEF */ @@ -111,13 +152,13 @@ hb_ot_layout_table_find_script (hb_face_t *face, hb_tag_t script_tag, unsigned int *script_index); -/* Like find_script, but takes zero-terminated array of scripts to test */ HB_EXTERN hb_bool_t -hb_ot_layout_table_choose_script (hb_face_t *face, +hb_ot_layout_table_select_script (hb_face_t *face, hb_tag_t table_tag, + unsigned int script_count, const hb_tag_t *script_tags, - unsigned int *script_index, - hb_tag_t *chosen_script); + unsigned int *script_index /* OUT */, + hb_tag_t *chosen_script /* OUT */); HB_EXTERN unsigned int hb_ot_layout_table_get_feature_tags (hb_face_t *face, @@ -135,11 +176,12 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face, hb_tag_t *language_tags /* OUT */); HB_EXTERN hb_bool_t -hb_ot_layout_script_find_language (hb_face_t *face, - hb_tag_t table_tag, - unsigned int script_index, - hb_tag_t language_tag, - unsigned int *language_index); +hb_ot_layout_script_select_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_count, + const hb_tag_t *language_tags, + unsigned int *language_index /* OUT */); HB_EXTERN hb_bool_t hb_ot_layout_language_get_required_feature_index (hb_face_t *face, @@ -194,6 +236,13 @@ HB_EXTERN unsigned int hb_ot_layout_table_get_lookup_count (hb_face_t *face, hb_tag_t table_tag); +HB_EXTERN void +hb_ot_layout_collect_features (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *feature_indexes /* OUT */); HB_EXTERN void hb_ot_layout_collect_lookups (hb_face_t *face, @@ -207,10 +256,10 @@ HB_EXTERN void hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_tag_t table_tag, unsigned int lookup_index, - hb_set_t *glyphs_before, /* OUT. May be NULL */ - hb_set_t *glyphs_input, /* OUT. May be NULL */ - hb_set_t *glyphs_after, /* OUT. May be NULL */ - hb_set_t *glyphs_output /* OUT. May be NULL */); + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */); #ifdef HB_NOT_IMPLEMENTED typedef struct @@ -315,29 +364,32 @@ Xhb_ot_layout_lookup_position (hb_font_t *font, /* Optical 'size' feature info. Returns true if found. * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ HB_EXTERN hb_bool_t -hb_ot_layout_get_size_params (hb_face_t *face, - unsigned int *design_size, /* OUT. May be NULL */ - unsigned int *subfamily_id, /* OUT. May be NULL */ - unsigned int *subfamily_name_id, /* OUT. May be NULL */ - unsigned int *range_start, /* OUT. May be NULL */ - unsigned int *range_end /* OUT. May be NULL */); - +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */); -/* - * BASE - */ -#if 0 -#define HB_OT_TAG_BASE_HANG HB_TAG('h','a','n','g') -#define HB_OT_TAG_BASE_ICFB HB_TAG('i','c','f','b') -#define HB_OT_TAG_BASE_ICFT HB_TAG('i','c','f','t') -#define HB_OT_TAG_BASE_IDEO HB_TAG('i','d','e','o') -#define HB_OT_TAG_BASE_IDTB HB_TAG('i','d','t','b') -#define HB_OT_TAG_BASE_MATH HB_TAG('m','a','t','h') -#define HB_OT_TAG_BASE_ROMN HB_TAG('r','o','m','n') +HB_EXTERN hb_bool_t +hb_ot_layout_feature_get_name_ids (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + hb_ot_name_id_t *label_id /* OUT. May be NULL */, + hb_ot_name_id_t *tooltip_id /* OUT. May be NULL */, + hb_ot_name_id_t *sample_id /* OUT. May be NULL */, + unsigned int *num_named_parameters /* OUT. May be NULL */, + hb_ot_name_id_t *first_param_id /* OUT. May be NULL */); -#endif +HB_EXTERN unsigned int +hb_ot_layout_feature_get_characters (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *char_count /* IN/OUT. May be NULL */, + hb_codepoint_t *characters /* OUT. May be NULL */); HB_END_DECLS diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout.hh index b2f974b..a00b940 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout.hh @@ -26,20 +26,43 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_PRIVATE_HH -#define HB_OT_LAYOUT_PRIVATE_HH +#ifndef HB_OT_LAYOUT_HH +#define HB_OT_LAYOUT_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" -#include "hb-set-digest-private.hh" -#include "hb-open-type-private.hh" +#include "hb-font.hh" +#include "hb-buffer.hh" +#include "hb-open-type.hh" +#include "hb-ot-shape.hh" +#include "hb-set-digest.hh" + + +struct hb_ot_shape_plan_t; + + +/* + * kern + */ + +HB_INTERNAL bool +hb_ot_layout_has_kerning (hb_face_t *face); + +HB_INTERNAL bool +hb_ot_layout_has_machine_kerning (hb_face_t *face); + +HB_INTERNAL bool +hb_ot_layout_has_cross_kerning (hb_face_t *face); + +HB_INTERNAL void +hb_ot_layout_kern (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); /* Private API corresponding to hb-ot-layout.h: */ -HB_INTERNAL hb_bool_t +HB_INTERNAL bool hb_ot_layout_table_find_feature (hb_face_t *face, hb_tag_t table_tag, hb_tag_t feature_tag, @@ -73,12 +96,12 @@ HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t); * GSUB/GPOS */ -HB_INTERNAL hb_bool_t +HB_INTERNAL bool hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, - hb_bool_t zero_context); + bool zero_context); /* Should be called before all the substitute_lookup's are done. */ @@ -86,18 +109,20 @@ HB_INTERNAL void hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer); - -struct hb_ot_layout_lookup_accelerator_t; +HB_INTERNAL void +hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer, + bool (*filter) (const hb_glyph_info_t *info)); namespace OT { struct hb_ot_apply_context_t; struct SubstLookup; + struct hb_ot_layout_lookup_accelerator_t; } HB_INTERNAL void hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, const OT::SubstLookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel); + const OT::hb_ot_layout_lookup_accelerator_t &accel); /* Should be called before all the position_lookup's are done. */ @@ -116,85 +141,6 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); - -/* - * hb_ot_layout_t - */ - -namespace OT { - struct BASE; - struct COLR; - struct CPAL; - struct GDEF; - struct GSUB; - struct GPOS; - struct MATH; - struct fvar; - struct avar; -} - -namespace AAT { - struct ankr; - struct kerx; - struct morx; - struct trak; -} - -struct hb_ot_layout_lookup_accelerator_t -{ - template <typename TLookup> - inline void init (const TLookup &lookup) - { - digest.init (); - lookup.add_coverage (&digest); - } - - inline void fini (void) - { - } - - inline bool may_have (hb_codepoint_t g) const { - return digest.may_have (g); - } - - private: - hb_set_digest_t digest; -}; - -struct hb_ot_layout_t -{ - hb_blob_t *gdef_blob; - hb_blob_t *gsub_blob; - hb_blob_t *gpos_blob; - - const struct OT::GDEF *gdef; - const struct OT::GSUB *gsub; - const struct OT::GPOS *gpos; - - /* TODO Move the following out of this struct. */ - OT::hb_table_lazy_loader_t<struct OT::BASE> base; - OT::hb_table_lazy_loader_t<struct OT::MATH> math; - OT::hb_table_lazy_loader_t<struct OT::fvar> fvar; - OT::hb_table_lazy_loader_t<struct OT::avar> avar; - - unsigned int gsub_lookup_count; - unsigned int gpos_lookup_count; - - hb_ot_layout_lookup_accelerator_t *gsub_accels; - hb_ot_layout_lookup_accelerator_t *gpos_accels; -}; - - -HB_INTERNAL hb_ot_layout_t * -_hb_ot_layout_create (hb_face_t *face); - -HB_INTERNAL void -_hb_ot_layout_destroy (hb_ot_layout_t *layout); - - -#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot) - - /* * Buffer var routines. */ @@ -212,12 +158,12 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout); #define foreach_syllable(buffer, start, end) \ for (unsigned int \ _count = buffer->len, \ - start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \ + start = 0, end = _count ? _hb_next_syllable (buffer, 0) : 0; \ start < _count; \ - start = end, end = _next_syllable (buffer, start)) + start = end, end = _hb_next_syllable (buffer, start)) static inline unsigned int -_next_syllable (hb_buffer_t *buffer, unsigned int start) +_hb_next_syllable (hb_buffer_t *buffer, unsigned int start) { hb_glyph_info_t *info = buffer->info; unsigned int count = buffer->len; @@ -240,7 +186,7 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start) * * Whether it's one of the three Mongolian Free Variation Selectors, * CGJ, or other characters that are hidden but should not be ignored * like most other Default_Ignorable()s do during matching. - * * One free bit right now. + * * Whether it's a grapheme continuation. * * The high-byte has different meanings, switched by the Gen-Cat: * - For Mn,Mc,Me: the modified Combining_Class. @@ -252,8 +198,8 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start) enum hb_unicode_props_flags_t { UPROPS_MASK_GEN_CAT = 0x001Fu, UPROPS_MASK_IGNORABLE = 0x0020u, - UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, - * or TAG characters */ + UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */ + UPROPS_MASK_CONTINUATION=0x0080u, /* If GEN_CAT=FORMAT, top byte masks: */ UPROPS_MASK_Cf_ZWJ = 0x0100u, @@ -272,6 +218,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) if (u >= 0x80) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII; + if (unlikely (unicode->is_default_ignorable (u))) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES; @@ -297,35 +244,11 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) props |= UPROPS_MASK_HIDDEN; } } - else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat))) + + if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat))) { - /* The above check is just an optimization to let in only things we need further - * processing on. */ - - /* Only Mn and Mc can have non-zero ccc: - * https://unicode.org/policies/stability_policy.html#Property_Value - * """ - * Canonical_Combining_Class, General_Category - * All characters other than those with General_Category property values - * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class - * property value 0. - * 1.1.5+ - * """ - * - * Also, all Mn's that are Default_Ignorable, have ccc=0, hence - * the "else if". - */ - props |= unicode->modified_combining_class (info->codepoint)<<8; - - /* Recategorize emoji skin-tone modifiers as Unicode mark, so they - * behave correctly in non-native directionality. They originally - * are MODIFIER_SYMBOL. Fixes: - * https://github.com/harfbuzz/harfbuzz/issues/169 - */ - if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu))) - { - props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK; - } + props |= UPROPS_MASK_CONTINUATION; + props |= unicode->modified_combining_class (u)<<8; } } @@ -364,29 +287,6 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0; } - - -/* Loop over grapheme. Based on foreach_cluster(). */ -#define foreach_grapheme(buffer, start, end) \ - for (unsigned int \ - _count = buffer->len, \ - start = 0, end = _count ? _next_grapheme (buffer, 0) : 0; \ - start < _count; \ - start = end, end = _next_grapheme (buffer, start)) - -static inline unsigned int -_next_grapheme (hb_buffer_t *buffer, unsigned int start) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - - while (++start < count && _hb_glyph_info_is_unicode_mark (&info[start])) - ; - - return start; -} - - #define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info))) static inline bool @@ -412,13 +312,13 @@ _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info) static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info); -static inline hb_bool_t +static inline bool _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info) { return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated (info); } -static inline hb_bool_t +static inline bool _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info) { return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN)) @@ -431,23 +331,58 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info) info->unicode_props() &= ~ UPROPS_MASK_HIDDEN; } +static inline void +_hb_glyph_info_set_continuation (hb_glyph_info_t *info) +{ + info->unicode_props() |= UPROPS_MASK_CONTINUATION; +} +static inline void +_hb_glyph_info_reset_continuation (hb_glyph_info_t *info) +{ + info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION; +} +static inline bool +_hb_glyph_info_is_continuation (const hb_glyph_info_t *info) +{ + return info->unicode_props() & UPROPS_MASK_CONTINUATION; +} +/* Loop over grapheme. Based on foreach_cluster(). */ +#define foreach_grapheme(buffer, start, end) \ + for (unsigned int \ + _count = buffer->len, \ + start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \ + start < _count; \ + start = end, end = _hb_next_grapheme (buffer, start)) + +static inline unsigned int +_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + + while (++start < count && _hb_glyph_info_is_continuation (&info[start])) + ; + + return start; +} + static inline bool _hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info) { return _hb_glyph_info_get_general_category (info) == HB_UNICODE_GENERAL_CATEGORY_FORMAT; } -static inline hb_bool_t +static inline bool _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ); } -static inline hb_bool_t +static inline bool _hb_glyph_info_is_zwj (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ); } -static inline hb_bool_t +static inline bool _hb_glyph_info_is_joiner (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ)); @@ -674,4 +609,4 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer) #undef lig_props #undef glyph_props -#endif /* HB_OT_LAYOUT_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_HH */ diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index 46bf2db..ef0bcc7 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -26,14 +26,14 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-map-private.hh" - -#include "hb-ot-layout-private.hh" +#include "hb-ot-map.hh" +#include "hb-ot-shape.hh" +#include "hb-ot-layout.hh" void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { - for (unsigned int i = 0; i < lookups[table_index].len; i++) + for (unsigned int i = 0; i < lookups[table_index].length; i++) hb_set_add (lookups_out, lookups[table_index][i].index); } @@ -54,33 +54,35 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_, /* Fetch script/language indices for GSUB/GPOS. We need these later to skip * features not available in either table and not waste precious bits for them. */ - hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE}; - hb_tag_t language_tag; + unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT; + unsigned int language_count = HB_OT_MAX_TAGS_PER_LANGUAGE; + hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT]; + hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; - hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]); - language_tag = hb_ot_tag_from_language (props.language); + hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags); for (unsigned int table_index = 0; table_index < 2; table_index++) { hb_tag_t table_tag = table_tags[table_index]; - found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]); - hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); + found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]); + hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]); } } -hb_ot_map_builder_t::~hb_ot_map_builder_t (void) +hb_ot_map_builder_t::~hb_ot_map_builder_t () { feature_infos.fini (); for (unsigned int table_index = 0; table_index < 2; table_index++) stages[table_index].fini (); } -void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, - hb_ot_map_feature_flags_t flags) +void hb_ot_map_builder_t::add_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags, + unsigned int value) { - feature_info_t *info = feature_infos.push(); if (unlikely (!tag)) return; + feature_info_t *info = feature_infos.push(); info->tag = tag; - info->seq = feature_infos.len; + info->seq = feature_infos.length; info->max_value = value; info->flags = flags; info->default_value = (flags & F_GLOBAL) ? value : 0; @@ -95,7 +97,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, unsigned int variations_index, hb_mask_t mask, bool auto_zwnj, - bool auto_zwj) + bool auto_zwj, + bool random) { unsigned int lookup_indices[32]; unsigned int offset, len; @@ -122,6 +125,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, lookup->index = lookup_indices[i]; lookup->auto_zwnj = auto_zwnj; lookup->auto_zwj = auto_zwj; + lookup->random = random; } offset += len; @@ -139,13 +143,12 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus } void -hb_ot_map_builder_t::compile (hb_ot_map_t &m, - const int *coords, - unsigned int num_coords) +hb_ot_map_builder_t::compile (hb_ot_map_t &m, + const hb_ot_shape_plan_key_t &key) { static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), ""); unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1; - unsigned int global_bit_shift = _hb_popcount (HB_GLYPH_FLAG_DEFINED); + unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED); m.global_mask = global_bit_mask; @@ -171,10 +174,11 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, } /* Sort features and merge duplicates */ + if (feature_infos.length) { feature_infos.qsort (); unsigned int j = 0; - for (unsigned int i = 1; i < feature_infos.len; i++) + for (unsigned int i = 1; i < feature_infos.length; i++) if (feature_infos[i].tag != feature_infos[j].tag) feature_infos[++j] = feature_infos[i]; else { @@ -198,7 +202,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, /* Allocate bits now */ unsigned int next_bit = global_bit_shift + 1; - for (unsigned int i = 0; i < feature_infos.len; i++) + for (unsigned int i = 0; i < feature_infos.length; i++) { const feature_info_t *info = &feature_infos[i]; @@ -208,8 +212,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, /* Uses the global bit */ bits_needed = 0; else - /* Limit to 8 bits per feature. */ - bits_needed = MIN(8u, _hb_bit_storage (info->max_value)); + /* Limit bits per feature. */ + bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value)); if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) continue; /* Feature disabled, or not enough bits. */ @@ -252,6 +256,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, map->stage[1] = info->stage[1]; map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ); map->auto_zwj = !(info->flags & F_MANUAL_ZWJ); + map->random = !!(info->flags & F_RANDOM); if ((info->flags & F_GLOBAL) && info->max_value == 1) { /* Uses the global bit */ map->shift = global_bit_shift; @@ -276,13 +281,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, { /* Collect lookup indices for features */ - unsigned int variations_index; - hb_ot_layout_table_find_feature_variations (face, - table_tags[table_index], - coords, - num_coords, - &variations_index); - unsigned int stage_index = 0; unsigned int last_num_lookups = 0; for (unsigned stage = 0; stage < current_stage[table_index]; stage++) @@ -291,25 +289,26 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, required_feature_stage[table_index] == stage) add_lookups (m, table_index, required_feature_index[table_index], - variations_index, + key.variations_index[table_index], global_bit_mask); - for (unsigned i = 0; i < m.features.len; i++) + for (unsigned i = 0; i < m.features.length; i++) if (m.features[i].stage[table_index] == stage) add_lookups (m, table_index, m.features[i].index[table_index], - variations_index, + key.variations_index[table_index], m.features[i].mask, m.features[i].auto_zwnj, - m.features[i].auto_zwj); + m.features[i].auto_zwj, + m.features[i].random); /* Sort lookups and merge duplicates */ - if (last_num_lookups < m.lookups[table_index].len) + if (last_num_lookups < m.lookups[table_index].length) { - m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len); + m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].length); unsigned int j = last_num_lookups; - for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++) + for (unsigned int i = j + 1; i < m.lookups[table_index].length; i++) if (m.lookups[table_index][i].index != m.lookups[table_index][j].index) m.lookups[table_index][++j] = m.lookups[table_index][i]; else @@ -321,9 +320,9 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, m.lookups[table_index].shrink (j + 1); } - last_num_lookups = m.lookups[table_index].len; + last_num_lookups = m.lookups[table_index].length; - if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) { + if (stage_index < stages[table_index].length && stages[table_index][stage_index].index == stage) { hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push (); stage_map->last_lookup = last_num_lookups; stage_map->pause_func = stages[table_index][stage_index].pause_func; diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map.hh index 4aaf328..28407c2 100644 --- a/src/hb-ot-map-private.hh +++ b/src/hb-ot-map.hh @@ -26,12 +26,15 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_MAP_PRIVATE_HH -#define HB_OT_MAP_PRIVATE_HH +#ifndef HB_OT_MAP_HH +#define HB_OT_MAP_HH -#include "hb-buffer-private.hh" +#include "hb-buffer.hh" +#define HB_OT_MAP_MAX_BITS 8u +#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u) + struct hb_ot_shape_plan_t; static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS}; @@ -52,15 +55,17 @@ struct hb_ot_map_t unsigned int needs_fallback : 1; unsigned int auto_zwnj : 1; unsigned int auto_zwj : 1; + unsigned int random : 1; - inline int cmp (const hb_tag_t *tag_) const - { return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; } + int cmp (const hb_tag_t tag_) const + { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; } }; struct lookup_map_t { unsigned short index; unsigned short auto_zwnj : 1; unsigned short auto_zwj : 1; + unsigned short random : 1; hb_mask_t mask; static int cmp (const void *pa, const void *pb) @@ -78,7 +83,7 @@ struct hb_ot_map_t pause_func_t pause_func; }; - inline void init (void) + void init () { memset (this, 0, sizeof (*this)); @@ -89,7 +94,7 @@ struct hb_ot_map_t stages[table_index].init (); } } - inline void fini (void) + void fini () { features.fini (); for (unsigned int table_index = 0; table_index < 2; table_index++) @@ -99,44 +104,50 @@ struct hb_ot_map_t } } - inline hb_mask_t get_global_mask (void) const { return global_mask; } + hb_mask_t get_global_mask () const { return global_mask; } - inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const { + hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const + { const feature_map_t *map = features.bsearch (feature_tag); if (shift) *shift = map ? map->shift : 0; return map ? map->mask : 0; } - inline bool needs_fallback (hb_tag_t feature_tag) const { + bool needs_fallback (hb_tag_t feature_tag) const + { const feature_map_t *map = features.bsearch (feature_tag); return map ? map->needs_fallback : false; } - inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const { + hb_mask_t get_1_mask (hb_tag_t feature_tag) const + { const feature_map_t *map = features.bsearch (feature_tag); return map ? map->_1_mask : 0; } - inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const { + unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const + { const feature_map_t *map = features.bsearch (feature_tag); return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX; } - inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const { + unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const + { const feature_map_t *map = features.bsearch (feature_tag); return map ? map->stage[table_index] : (unsigned int) -1; } - inline void get_stage_lookups (unsigned int table_index, unsigned int stage, - const struct lookup_map_t **plookups, unsigned int *lookup_count) const { + void get_stage_lookups (unsigned int table_index, unsigned int stage, + const struct lookup_map_t **plookups, unsigned int *lookup_count) const + { if (unlikely (stage == (unsigned int) -1)) { *plookups = nullptr; *lookup_count = 0; return; } - assert (stage <= stages[table_index].len); + assert (stage <= stages[table_index].length); unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0; - unsigned int end = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len; + unsigned int end = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length; *plookups = end == start ? nullptr : &lookups[table_index][start]; *lookup_count = end - start; } @@ -156,24 +167,35 @@ struct hb_ot_map_t hb_mask_t global_mask; - hb_vector_t<feature_map_t, 8> features; - hb_vector_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */ - hb_vector_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */ + hb_vector_t<feature_map_t> features; + hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */ + hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */ }; -enum hb_ot_map_feature_flags_t { +enum hb_ot_map_feature_flags_t +{ F_NONE = 0x0000u, F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */ F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */ F_MANUAL_ZWNJ = 0x0004u, /* Don't skip over ZWNJ when matching **context**. */ F_MANUAL_ZWJ = 0x0008u, /* Don't skip over ZWJ when matching **input**. */ - F_GLOBAL_SEARCH = 0x0010u /* If feature not found in LangSys, look for it in global feature list and pick one. */ + F_MANUAL_JOINERS = F_MANUAL_ZWNJ | F_MANUAL_ZWJ, + F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS, + F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK, + F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */ + F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */ }; HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t); -/* Macro version for where const is desired. */ -#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r))) +struct hb_ot_map_feature_t +{ + hb_tag_t tag; + hb_ot_map_feature_flags_t flags; +}; + +struct hb_ot_shape_plan_key_t; + struct hb_ot_map_builder_t { public: @@ -181,22 +203,30 @@ struct hb_ot_map_builder_t HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_, const hb_segment_properties_t *props_); - HB_INTERNAL ~hb_ot_map_builder_t (void); + HB_INTERNAL ~hb_ot_map_builder_t (); + + HB_INTERNAL void add_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags=F_NONE, + unsigned int value=1); + + void add_feature (const hb_ot_map_feature_t &feat) + { add_feature (feat.tag, feat.flags); } - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, - hb_ot_map_feature_flags_t flags); + void enable_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags=F_NONE, + unsigned int value=1) + { add_feature (tag, F_GLOBAL | flags, value); } - inline void add_global_bool_feature (hb_tag_t tag) - { add_feature (tag, 1, F_GLOBAL); } + void disable_feature (hb_tag_t tag) + { add_feature (tag, F_GLOBAL, 0); } - inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func) + void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (0, pause_func); } - inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func) + void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (1, pause_func); } - HB_INTERNAL void compile (hb_ot_map_t &m, - const int *coords, - unsigned int num_coords); + HB_INTERNAL void compile (hb_ot_map_t &m, + const hb_ot_shape_plan_key_t &key); private: @@ -206,7 +236,8 @@ struct hb_ot_map_builder_t unsigned int variations_index, hb_mask_t mask, bool auto_zwnj = true, - bool auto_zwj = true); + bool auto_zwj = true, + bool random = false); struct feature_info_t { hb_tag_t tag; @@ -244,10 +275,10 @@ struct hb_ot_map_builder_t private: unsigned int current_stage[2]; /* GSUB/GPOS */ - hb_vector_t<feature_info_t, 32> feature_infos; - hb_vector_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */ + hb_vector_t<feature_info_t> feature_infos; + hb_vector_t<stage_info_t> stages[2]; /* GSUB/GPOS */ }; -#endif /* HB_OT_MAP_PRIVATE_HH */ +#endif /* HB_OT_MAP_HH */ diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh index 5fef2d2..62bf072 100644 --- a/src/hb-ot-math-table.hh +++ b/src/hb-ot-math-table.hh @@ -27,8 +27,8 @@ #ifndef HB_OT_MATH_TABLE_HH #define HB_OT_MATH_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" #include "hb-ot-math.h" namespace OT { @@ -36,12 +36,12 @@ namespace OT { struct MathValueRecord { - inline hb_position_t get_x_value (hb_font_t *font, const void *base) const + hb_position_t get_x_value (hb_font_t *font, const void *base) const { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } - inline hb_position_t get_y_value (hb_font_t *font, const void *base) const + hb_position_t get_y_value (hb_font_t *font, const void *base) const { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); @@ -50,7 +50,7 @@ struct MathValueRecord protected: HBINT16 value; /* The X or Y value in design units */ OffsetTo<Device> deviceTable; /* Offset to the device table - from the - * beginning of parent table. May be nullptr. + * beginning of parent table. May be NULL. * Suggested format for device table is 1. */ public: @@ -59,7 +59,7 @@ struct MathValueRecord struct MathConstants { - inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const + bool sanitize_math_value_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -71,13 +71,13 @@ struct MathConstants return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && sanitize_math_value_records(c)); + return_trace (c->check_struct (this) && sanitize_math_value_records (c)); } - inline hb_position_t get_value (hb_ot_math_constant_t constant, + hb_position_t get_value (hb_ot_math_constant_t constant, hb_font_t *font) const { switch (constant) { @@ -94,7 +94,7 @@ struct MathConstants case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: - return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this); + return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: @@ -143,7 +143,7 @@ struct MathConstants case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: - return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this); + return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: return radicalDegreeBottomRaisePercent; @@ -165,7 +165,7 @@ struct MathConstants struct MathItalicsCorrectionInfo { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -173,8 +173,8 @@ struct MathItalicsCorrectionInfo italicsCorrection.sanitize (c, this)); } - inline hb_position_t get_value (hb_codepoint_t glyph, - hb_font_t *font) const + hb_position_t get_value (hb_codepoint_t glyph, + hb_font_t *font) const { unsigned int index = (this+coverage).get_coverage (glyph); return italicsCorrection[index].get_x_value (font, this); @@ -196,7 +196,7 @@ struct MathItalicsCorrectionInfo struct MathTopAccentAttachment { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -204,13 +204,13 @@ struct MathTopAccentAttachment topAccentAttachment.sanitize (c, this)); } - inline hb_position_t get_value (hb_codepoint_t glyph, - hb_font_t *font) const + hb_position_t get_value (hb_codepoint_t glyph, + hb_font_t *font) const { unsigned int index = (this+topAccentCoverage).get_coverage (glyph); if (index == NOT_COVERED) return font->get_glyph_h_advance (glyph) / 2; - return topAccentAttachment[index].get_x_value(font, this); + return topAccentAttachment[index].get_x_value (font, this); } protected: @@ -229,29 +229,27 @@ struct MathTopAccentAttachment struct MathKern { - inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const + bool sanitize_math_value_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); unsigned int count = 2 * heightCount + 1; for (unsigned int i = 0; i < count; i++) - if (!mathValueRecords[i].sanitize (c, this)) return_trace (false); + if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (mathValueRecords, - mathValueRecords[0].static_size, - 2 * heightCount + 1) && + c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && sanitize_math_value_records (c)); } - inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const + hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const { - const MathValueRecord* correctionHeight = mathValueRecords; - const MathValueRecord* kernValue = mathValueRecords + heightCount; + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; int sign = font->y_scale < 0 ? -1 : +1; /* The description of the MathKern table is a ambiguous, but interpreting @@ -267,7 +265,7 @@ struct MathKern while (count > 0) { unsigned int half = count / 2; - hb_position_t height = correctionHeight[i + half].get_y_value(font, this); + hb_position_t height = correctionHeight[i + half].get_y_value (font, this); if (sign * height < sign * correction_height) { i += half + 1; @@ -275,27 +273,28 @@ struct MathKern } else count = half; } - return kernValue[i].get_x_value(font, this); + return kernValue[i].get_x_value (font, this); } protected: - HBUINT16 heightCount; - MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at - * which the kern value changes. - * Sorted by the height value in - * design units (heightCount entries), - * Followed by: - * Array of kern values corresponding - * to heights. (heightCount+1 entries). - */ + HBUINT16 heightCount; + UnsizedArrayOf<MathValueRecord> + mathValueRecordsZ; /* Array of correction heights at + * which the kern value changes. + * Sorted by the height value in + * design units (heightCount entries), + * Followed by: + * Array of kern values corresponding + * to heights. (heightCount+1 entries). + */ public: - DEFINE_SIZE_ARRAY (2, mathValueRecords); + DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); }; struct MathKernInfoRecord { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -307,10 +306,10 @@ struct MathKernInfoRecord return_trace (true); } - inline hb_position_t get_kerning (hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font, - const void *base) const + hb_position_t get_kerning (hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font, + const void *base) const { unsigned int idx = kern; if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; @@ -319,7 +318,7 @@ struct MathKernInfoRecord protected: /* Offset to MathKern table for each corner - - * from the beginning of MathKernInfo table. May be nullptr. */ + * from the beginning of MathKernInfo table. May be NULL. */ OffsetTo<MathKern> mathKern[4]; public: @@ -328,7 +327,7 @@ struct MathKernInfoRecord struct MathKernInfo { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -336,10 +335,10 @@ struct MathKernInfo mathKernInfoRecords.sanitize (c, this)); } - inline hb_position_t get_kerning (hb_codepoint_t glyph, - hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font) const + hb_position_t get_kerning (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font) const { unsigned int index = (this+mathKernCoverage).get_coverage (glyph); return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); @@ -362,31 +361,31 @@ struct MathKernInfo struct MathGlyphInfo { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && mathItalicsCorrectionInfo.sanitize (c, this) && mathTopAccentAttachment.sanitize (c, this) && extendedShapeCoverage.sanitize (c, this) && - mathKernInfo.sanitize(c, this)); + mathKernInfo.sanitize (c, this)); } - inline hb_position_t + hb_position_t get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } - inline hb_position_t + hb_position_t get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const { return (this+mathTopAccentAttachment).get_value (glyph, font); } - inline bool is_extended_shape (hb_codepoint_t glyph) const + bool is_extended_shape (hb_codepoint_t glyph) const { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } - inline hb_position_t get_kerning (hb_codepoint_t glyph, - hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font) const + hb_position_t get_kerning (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font) const { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } protected: @@ -402,7 +401,7 @@ struct MathGlyphInfo * from the beginning of MathGlyphInfo table. When the left or right glyph of * a box is an extended shape variant, the (ink) box (and not the default * position defined by values in MathConstants table) should be used for - * vertical positioning purposes. May be nullptr.. */ + * vertical positioning purposes. May be NULL.. */ OffsetTo<Coverage> extendedShapeCoverage; /* Offset to MathKernInfo table - @@ -417,7 +416,7 @@ struct MathGlyphVariantRecord { friend struct MathGlyphConstruction; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -426,8 +425,8 @@ struct MathGlyphVariantRecord protected: GlyphID variantGlyph; /* Glyph ID for the variant. */ HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the - * variant, in the direction of requested - * glyph extension. */ + * variant, in the direction of requested + * glyph extension. */ public: DEFINE_SIZE_STATIC (4); @@ -447,15 +446,15 @@ struct PartFlags : HBUINT16 struct MathGlyphPartRecord { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - inline void extract (hb_ot_math_glyph_part_t &out, - int scale, - hb_font_t *font) const + void extract (hb_ot_math_glyph_part_t &out, + int scale, + hb_font_t *font) const { out.glyph = glyph; @@ -492,27 +491,26 @@ struct MathGlyphPartRecord struct MathGlyphAssembly { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - italicsCorrection.sanitize(c, this) && - partRecords.sanitize(c)); + italicsCorrection.sanitize (c, this) && + partRecords.sanitize (c)); } - inline unsigned int get_parts (hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *parts_count, /* IN/OUT */ - hb_ot_math_glyph_part_t *parts /* OUT */, - hb_position_t *italics_correction /* OUT */) const + unsigned int get_parts (hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *parts_count, /* IN/OUT */ + hb_ot_math_glyph_part_t *parts /* OUT */, + hb_position_t *italics_correction /* OUT */) const { if (parts_count) { int scale = font->dir_scale (direction); - const MathGlyphPartRecord *arr = - partRecords.sub_array (start_offset, parts_count); - unsigned int count = *parts_count; + hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count); + unsigned int count = arr.length; for (unsigned int i = 0; i < count; i++) arr[i].extract (parts[i], scale, font); } @@ -537,29 +535,27 @@ struct MathGlyphAssembly struct MathGlyphConstruction { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - glyphAssembly.sanitize(c, this) && - mathGlyphVariantRecord.sanitize(c)); + glyphAssembly.sanitize (c, this) && + mathGlyphVariantRecord.sanitize (c)); } - inline const MathGlyphAssembly &get_assembly (void) const - { return this+glyphAssembly; } + const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } - inline unsigned int get_variants (hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *variants_count, /* IN/OUT */ - hb_ot_math_glyph_variant_t *variants /* OUT */) const + unsigned int get_variants (hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *variants_count, /* IN/OUT */ + hb_ot_math_glyph_variant_t *variants /* OUT */) const { if (variants_count) { int scale = font->dir_scale (direction); - const MathGlyphVariantRecord *arr = - mathGlyphVariantRecord.sub_array (start_offset, variants_count); - unsigned int count = *variants_count; + hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); + unsigned int count = arr.length; for (unsigned int i = 0; i < count; i++) { variants[i].glyph = arr[i].variantGlyph; @@ -571,7 +567,7 @@ struct MathGlyphConstruction protected: /* Offset to MathGlyphAssembly table for this shape - from the beginning of - MathGlyphConstruction table. May be nullptr. */ + MathGlyphConstruction table. May be NULL. */ OffsetTo<MathGlyphAssembly> glyphAssembly; /* MathGlyphVariantRecords for alternative variants of the glyphs. */ @@ -583,41 +579,39 @@ struct MathGlyphConstruction struct MathVariants { - inline bool sanitize_offsets (hb_sanitize_context_t *c) const + bool sanitize_offsets (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); unsigned int count = vertGlyphCount + horizGlyphCount; for (unsigned int i = 0; i < count; i++) - if (!glyphConstruction[i].sanitize (c, this)) return_trace (false); + if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && vertGlyphCoverage.sanitize (c, this) && horizGlyphCoverage.sanitize (c, this) && - c->check_array (glyphConstruction, - glyphConstruction[0].static_size, - vertGlyphCount + horizGlyphCount) && + c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && sanitize_offsets (c)); } - inline hb_position_t get_min_connector_overlap (hb_direction_t direction, + hb_position_t get_min_connector_overlap (hb_direction_t direction, hb_font_t *font) const { return font->em_scale_dir (minConnectorOverlap, direction); } - inline unsigned int get_glyph_variants (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *variants_count, /* IN/OUT */ - hb_ot_math_glyph_variant_t *variants /* OUT */) const + unsigned int get_glyph_variants (hb_codepoint_t glyph, + hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *variants_count, /* IN/OUT */ + hb_ot_math_glyph_variant_t *variants /* OUT */) const { return get_glyph_construction (glyph, direction, font) .get_variants (direction, font, start_offset, variants_count, variants); } - inline unsigned int get_glyph_parts (hb_codepoint_t glyph, + unsigned int get_glyph_parts (hb_codepoint_t glyph, hb_direction_t direction, hb_font_t *font, unsigned int start_offset, @@ -631,10 +625,10 @@ struct MathVariants italics_correction); } private: - inline const MathGlyphConstruction & - get_glyph_construction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font) const + const MathGlyphConstruction & + get_glyph_construction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_font_t *font HB_UNUSED) const { bool vertical = HB_DIRECTION_IS_VERTICAL (direction); unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; @@ -642,7 +636,7 @@ struct MathVariants : horizGlyphCoverage; unsigned int index = (this+coverage).get_coverage (glyph); - if (unlikely (index >= count)) return Null(MathGlyphConstruction); + if (unlikely (index >= count)) return Null (MathGlyphConstruction); if (!vertical) index += vertGlyphCount; @@ -670,7 +664,8 @@ struct MathVariants /* Array of offsets to MathGlyphConstruction tables - from the beginning of the MathVariants table, for shapes growing in vertical/horizontal direction. */ - OffsetTo<MathGlyphConstruction> glyphConstruction[VAR]; + UnsizedArrayOf<OffsetTo<MathGlyphConstruction> > + glyphConstruction; public: DEFINE_SIZE_ARRAY (10, glyphConstruction); @@ -684,9 +679,11 @@ struct MathVariants struct MATH { - static const hb_tag_t tableTag = HB_OT_TAG_MATH; + static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; + + bool has_data () const { return version.to_int (); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && @@ -696,15 +693,13 @@ struct MATH mathVariants.sanitize (c, this)); } - inline hb_position_t get_constant (hb_ot_math_constant_t constant, + hb_position_t get_constant (hb_ot_math_constant_t constant, hb_font_t *font) const { return (this+mathConstants).get_value (constant, font); } - inline const MathGlyphInfo &get_math_glyph_info (void) const - { return this+mathGlyphInfo; } + const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } - inline const MathVariants &get_math_variants (void) const - { return this+mathVariants; } + const MathVariants &get_variants () const { return this+mathVariants; } protected: FixedVersion<>version; /* Version of the MATH table diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc index 1667a7d..bd31bf5 100644 --- a/src/hb-ot-math.cc +++ b/src/hb-ot-math.cc @@ -24,18 +24,21 @@ * Igalia Author(s): Frédéric Wang */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-face.hh" #include "hb-ot-math-table.hh" -static inline const OT::MATH& -_get_math (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::MATH); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->math.get ()); -} + +/** + * SECTION:hb-ot-math + * @title: hb-ot-math + * @short_description: OpenType Math information + * @include: hb-ot.h + * + * Functions for fetching mathematics layout data from OpenType fonts. + **/ + /* * OT::MATH @@ -55,7 +58,7 @@ _get_math (hb_face_t *face) hb_bool_t hb_ot_math_has_data (hb_face_t *face) { - return &_get_math (face) != &Null(OT::MATH); + return face->table.MATH->has_data (); } /** @@ -77,8 +80,7 @@ hb_position_t hb_ot_math_get_constant (hb_font_t *font, hb_ot_math_constant_t constant) { - const OT::MATH &math = _get_math (font->face); - return math.get_constant(constant, font); + return font->face->table.MATH->get_constant(constant, font); } /** @@ -94,8 +96,7 @@ hb_position_t hb_ot_math_get_glyph_italics_correction (hb_font_t *font, hb_codepoint_t glyph) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_glyph_info().get_italics_correction (glyph, font); + return font->face->table.MATH->get_glyph_info().get_italics_correction (glyph, font); } /** @@ -111,8 +112,7 @@ hb_position_t hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font, hb_codepoint_t glyph) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_glyph_info().get_top_accent_attachment (glyph, font); + return font->face->table.MATH->get_glyph_info().get_top_accent_attachment (glyph, font); } /** @@ -128,8 +128,7 @@ hb_bool_t hb_ot_math_is_glyph_extended_shape (hb_face_t *face, hb_codepoint_t glyph) { - const OT::MATH &math = _get_math (face); - return math.get_math_glyph_info().is_extended_shape (glyph); + return face->table.MATH->get_glyph_info().is_extended_shape (glyph); } /** @@ -155,8 +154,10 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, hb_ot_math_kern_t kern, hb_position_t correction_height) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font); + return font->face->table.MATH->get_glyph_info().get_kerning (glyph, + kern, + correction_height, + font); } /** @@ -186,11 +187,10 @@ hb_ot_math_get_glyph_variants (hb_font_t *font, unsigned int *variants_count, /* IN/OUT */ hb_ot_math_glyph_variant_t *variants /* OUT */) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_variants().get_glyph_variants (glyph, direction, font, - start_offset, - variants_count, - variants); + return font->face->table.MATH->get_variants().get_glyph_variants (glyph, direction, font, + start_offset, + variants_count, + variants); } /** @@ -211,8 +211,7 @@ hb_position_t hb_ot_math_get_min_connector_overlap (hb_font_t *font, hb_direction_t direction) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_variants().get_min_connector_overlap (direction, font); + return font->face->table.MATH->get_variants().get_min_connector_overlap (direction, font); } /** @@ -244,10 +243,11 @@ hb_ot_math_get_glyph_assembly (hb_font_t *font, hb_ot_math_glyph_part_t *parts, /* OUT */ hb_position_t *italics_correction /* OUT */) { - const OT::MATH &math = _get_math (font->face); - return math.get_math_variants().get_glyph_parts (glyph, direction, font, - start_offset, - parts_count, - parts, - italics_correction); + return font->face->table.MATH->get_variants().get_glyph_parts (glyph, + direction, + font, + start_offset, + parts_count, + parts, + italics_correction); } diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index 390b60d..e4b67ab 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -27,8 +27,7 @@ #ifndef HB_OT_MAXP_TABLE_HH #define HB_OT_MAXP_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" namespace OT { @@ -42,7 +41,7 @@ namespace OT { struct maxpV1Tail { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -72,19 +71,16 @@ struct maxpV1Tail struct maxp { - static const hb_tag_t tableTag = HB_OT_TAG_maxp; + static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp; - inline unsigned int get_num_glyphs (void) const - { - return numGlyphs; - } + unsigned int get_num_glyphs () const { return numGlyphs; } - inline void set_num_glyphs (unsigned int count) + void set_num_glyphs (unsigned int count) { numGlyphs.set (count); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) @@ -93,23 +89,23 @@ struct maxp if (version.major == 1) { const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this); - return v1.sanitize (c); + return_trace (v1.sanitize (c)); } return_trace (likely (version.major == 0 && version.minor == 0x5000u)); } - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { - hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_maxp)); + hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table<maxp> (plan->source); hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob); hb_blob_destroy (maxp_blob); if (unlikely (!maxp_prime_blob)) { return false; } - OT::maxp *maxp_prime = (OT::maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); + maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); - maxp_prime->set_num_glyphs (plan->glyphs.len); + maxp_prime->set_num_glyphs (plan->glyphs.length); if (plan->drop_hints) drop_hint_fields (plan, maxp_prime); @@ -118,7 +114,7 @@ struct maxp return result; } - static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime) + static void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime) { if (maxp_prime->version.major == 1) { @@ -137,7 +133,7 @@ struct maxp FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0), * 0x00005000u or 0x00010000u. */ HBUINT16 numGlyphs; /* The number of glyphs in the font. */ -/*maxpV1Tail v1Tail[VAR]; */ +/*maxpV1Tail v1Tail[VAR]; */ public: DEFINE_SIZE_STATIC (6); }; diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language.cc new file mode 100644 index 0000000..0e37e0a --- /dev/null +++ b/src/hb-ot-name-language.cc @@ -0,0 +1,457 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#include "hb-ot-name-language.hh" + +/* Following two tables were generated by joining FreeType, FontConfig, + * and OpenType specification language lists, then filled in missing + * entries using: + * https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings + */ + +struct hb_ot_language_map_t +{ + static int cmp (const void *key, const void *item) + { + unsigned int a = * (unsigned int *) key; + unsigned int b = ((const hb_ot_language_map_t *) item)->code; + return a < b ? -1 : a > b ? +1 : 0; + } + + uint16_t code; + char lang[6]; +}; + +static const hb_ot_language_map_t +hb_ms_language_map[] = +{ + {0x0001, "ar"}, /* ??? */ + {0x0004, "zh"}, /* ??? */ + {0x0009, "en"}, /* ??? */ + {0x0401, "ar"}, /* Arabic (Saudi Arabia) */ + {0x0402, "bg"}, /* Bulgarian (Bulgaria) */ + {0x0403, "ca"}, /* Catalan (Catalan) */ + {0x0404, "zh-tw"}, /* Chinese (Taiwan) */ + {0x0405, "cs"}, /* Czech (Czech Republic) */ + {0x0406, "da"}, /* Danish (Denmark) */ + {0x0407, "de"}, /* German (Germany) */ + {0x0408, "el"}, /* Greek (Greece) */ + {0x0409, "en"}, /* English (United States) */ + {0x040A, "es"}, /* Spanish (Traditional Sort) (Spain) */ + {0x040B, "fi"}, /* Finnish (Finland) */ + {0x040C, "fr"}, /* French (France) */ + {0x040D, "he"}, /* Hebrew (Israel) */ + {0x040E, "hu"}, /* Hungarian (Hungary) */ + {0x040F, "is"}, /* Icelandic (Iceland) */ + {0x0410, "it"}, /* Italian (Italy) */ + {0x0411, "ja"}, /* Japanese (Japan) */ + {0x0412, "ko"}, /* Korean (Korea) */ + {0x0413, "nl"}, /* Dutch (Netherlands) */ + {0x0414, "no"}, /* Norwegian (Bokmal) (Norway) */ + {0x0415, "pl"}, /* Polish (Poland) */ + {0x0416, "pt"}, /* Portuguese (Brazil) */ + {0x0417, "rm"}, /* Romansh (Switzerland) */ + {0x0418, "ro"}, /* Romanian (Romania) */ + {0x0419, "ru"}, /* Russian (Russia) */ + {0x041A, "hr"}, /* Croatian (Croatia) */ + {0x041B, "sk"}, /* Slovak (Slovakia) */ + {0x041C, "sq"}, /* Albanian (Albania) */ + {0x041D, "sv"}, /* Swedish (Sweden) */ + {0x041E, "th"}, /* Thai (Thailand) */ + {0x041F, "tr"}, /* Turkish (Turkey) */ + {0x0420, "ur"}, /* Urdu (Islamic Republic of Pakistan) */ + {0x0421, "id"}, /* Indonesian (Indonesia) */ + {0x0422, "uk"}, /* Ukrainian (Ukraine) */ + {0x0423, "be"}, /* Belarusian (Belarus) */ + {0x0424, "sl"}, /* Slovenian (Slovenia) */ + {0x0425, "et"}, /* Estonian (Estonia) */ + {0x0426, "lv"}, /* Latvian (Latvia) */ + {0x0427, "lt"}, /* Lithuanian (Lithuania) */ + {0x0428, "tg"}, /* Tajik (Cyrillic) (Tajikistan) */ + {0x0429, "fa"}, /* Persian (Iran) */ + {0x042A, "vi"}, /* Vietnamese (Vietnam) */ + {0x042B, "hy"}, /* Armenian (Armenia) */ + {0x042C, "az"}, /* Azeri (Latin) (Azerbaijan) */ + {0x042D, "eu"}, /* Basque (Basque) */ + {0x042E, "hsb"}, /* Upper Sorbian (Germany) */ + {0x042F, "mk"}, /* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */ + {0x0430, "st"}, /* ??? */ + {0x0431, "ts"}, /* ??? */ + {0x0432, "tn"}, /* Setswana (South Africa) */ + {0x0433, "ven"}, /* ??? */ + {0x0434, "xh"}, /* isiXhosa (South Africa) */ + {0x0435, "zu"}, /* isiZulu (South Africa) */ + {0x0436, "af"}, /* Afrikaans (South Africa) */ + {0x0437, "ka"}, /* Georgian (Georgia) */ + {0x0438, "fo"}, /* Faroese (Faroe Islands) */ + {0x0439, "hi"}, /* Hindi (India) */ + {0x043A, "mt"}, /* Maltese (Malta) */ + {0x043B, "se"}, /* Sami (Northern) (Norway) */ + {0x043C, "ga"}, /* ??? */ + {0x043D, "yi"}, /* ??? */ + {0x043E, "ms"}, /* Malay (Malaysia) */ + {0x043F, "kk"}, /* Kazakh (Kazakhstan) */ + {0x0440, "ky"}, /* Kyrgyz (Kyrgyzstan) */ + {0x0441, "sw"}, /* Kiswahili (Kenya) */ + {0x0442, "tk"}, /* Turkmen (Turkmenistan) */ + {0x0443, "uz"}, /* Uzbek (Latin) (Uzbekistan) */ + {0x0444, "tt"}, /* Tatar (Russia) */ + {0x0445, "bn"}, /* Bengali (India) */ + {0x0446, "pa"}, /* Punjabi (India) */ + {0x0447, "gu"}, /* Gujarati (India) */ + {0x0448, "or"}, /* Odia (formerly Oriya) (India) */ + {0x0449, "ta"}, /* Tamil (India) */ + {0x044A, "te"}, /* Telugu (India) */ + {0x044B, "kn"}, /* Kannada (India) */ + {0x044C, "ml"}, /* Malayalam (India) */ + {0x044D, "as"}, /* Assamese (India) */ + {0x044E, "mr"}, /* Marathi (India) */ + {0x044F, "sa"}, /* Sanskrit (India) */ + {0x0450, "mn"}, /* Mongolian (Cyrillic) (Mongolia) */ + {0x0451, "bo"}, /* Tibetan (PRC) */ + {0x0452, "cy"}, /* Welsh (United Kingdom) */ + {0x0453, "km"}, /* Khmer (Cambodia) */ + {0x0454, "lo"}, /* Lao (Lao P.D.R.) */ + {0x0455, "my"}, /* ??? */ + {0x0456, "gl"}, /* Galician (Galician) */ + {0x0457, "kok"}, /* Konkani (India) */ + {0x0458, "mni"}, /* ??? */ + {0x0459, "sd"}, /* ??? */ + {0x045A, "syr"}, /* Syriac (Syria) */ + {0x045B, "si"}, /* Sinhala (Sri Lanka) */ + {0x045C, "chr"}, /* ??? */ + {0x045D, "iu"}, /* Inuktitut (Canada) */ + {0x045E, "am"}, /* Amharic (Ethiopia) */ + {0x0460, "ks"}, /* ??? */ + {0x0461, "ne"}, /* Nepali (Nepal) */ + {0x0462, "fy"}, /* Frisian (Netherlands) */ + {0x0463, "ps"}, /* Pashto (Afghanistan) */ + {0x0464, "phi"}, /* Filipino (Philippines) */ + {0x0465, "div"}, /* Divehi (Maldives) */ + {0x0468, "ha"}, /* Hausa (Latin) (Nigeria) */ + {0x046A, "yo"}, /* Yoruba (Nigeria) */ + {0x046B, "quz"}, /* Quechua (Bolivia) */ + {0x046C, "nso"}, /* Sesotho sa Leboa (South Africa) */ + {0x046D, "ba"}, /* Bashkir (Russia) */ + {0x046E, "lb"}, /* Luxembourgish (Luxembourg) */ + {0x046F, "kl"}, /* Greenlandic (Greenland) */ + {0x0470, "ibo"}, /* Igbo (Nigeria) */ + {0x0471, "kau"}, /* ??? */ + {0x0472, "om"}, /* ??? */ + {0x0473, "ti"}, /* ??? */ + {0x0474, "gn"}, /* ??? */ + {0x0475, "haw"}, /* ??? */ + {0x0476, "la"}, /* ??? */ + {0x0477, "so"}, /* ??? */ + {0x0478, "ii"}, /* Yi (PRC) */ + {0x0479, "pap"}, /* ??? */ + {0x047A, "arn"}, /* Mapudungun (Chile) */ + {0x047C, "moh"}, /* Mohawk (Mohawk) */ + {0x047E, "br"}, /* Breton (France) */ + {0x0480, "ug"}, /* Uighur (PRC) */ + {0x0481, "mi"}, /* Maori (New Zealand) */ + {0x0482, "oc"}, /* Occitan (France) */ + {0x0483, "co"}, /* Corsican (France) */ + {0x0484, "gsw"}, /* Alsatian (France) */ + {0x0485, "sah"}, /* Yakut (Russia) */ + {0x0486, "qut"}, /* K'iche (Guatemala) */ + {0x0487, "rw"}, /* Kinyarwanda (Rwanda) */ + {0x0488, "wo"}, /* Wolof (Senegal) */ + {0x048C, "fa"}, /* Dari (Afghanistan) */ + {0x0801, "ar"}, /* Arabic (Iraq) */ + {0x0804, "zh-cn"}, /* Chinese (People’s Republic of China) */ + {0x0807, "de"}, /* German (Switzerland) */ + {0x0809, "en"}, /* English (United Kingdom) */ + {0x080A, "es"}, /* Spanish (Mexico) */ + {0x080C, "fr"}, /* French (Belgium) */ + {0x0810, "it"}, /* Italian (Switzerland) */ + {0x0812, "ko"}, /* ??? */ + {0x0813, "nl"}, /* Dutch (Belgium) */ + {0x0814, "nn"}, /* Norwegian (Nynorsk) (Norway) */ + {0x0816, "pt"}, /* Portuguese (Portugal) */ + {0x0818, "mo"}, /* ??? */ + {0x0819, "ru"}, /* ??? */ + {0x081A, "sr"}, /* Serbian (Latin) (Serbia) */ + {0x081D, "sv"}, /* Sweden (Finland) */ + {0x0820, "ur"}, /* ??? */ + {0x0827, "lt"}, /* ??? */ + {0x082C, "az"}, /* Azeri (Cyrillic) (Azerbaijan) */ + {0x082E, "dsb"}, /* Lower Sorbian (Germany) */ +//{0x083B, ""}, /* Sami (Northern) (Sweden) */ + {0x083C, "gd"}, /* Irish (Ireland) */ + {0x083E, "ms"}, /* Malay (Brunei Darussalam) */ + {0x0843, "uz"}, /* Uzbek (Cyrillic) (Uzbekistan) */ + {0x0845, "bn"}, /* Bengali (Bangladesh) */ + {0x0846, "ar"}, /* ??? */ + {0x0850, "mn"}, /* Mongolian (Traditional) (People’s Republic of China) */ + {0x0851, "dz"}, /* ??? */ + {0x085D, "iu"}, /* Inuktitut (Latin) (Canada) */ + {0x085F, "tzm"}, /* Tamazight (Latin) (Algeria) */ + {0x0861, "ne"}, /* ??? */ +//{0x086B, ""}, /* Quechua (Ecuador) */ + {0x0873, "ti"}, /* ??? */ + {0x0C01, "ar"}, /* Arabic (Egypt) */ + {0x0C04, "zh-hk"}, /* Chinese (Hong Kong S.A.R.) */ + {0x0C07, "de"}, /* German (Austria) */ + {0x0C09, "en"}, /* English (Australia) */ + {0x0C0A, "es"}, /* Spanish (Modern Sort) (Spain) */ + {0x0C0C, "fr"}, /* French (Canada) */ + {0x0C1A, "sr"}, /* Serbian (Cyrillic) (Serbia) */ + {0x0C3B, "se"}, /* Sami (Northern) (Finland) */ +//{0x0C6B, ""}, /* Quechua (Peru) */ + {0x1001, "ar"}, /* Arabic (Libya) */ + {0x1004, "zh-sg"}, /* Chinese (Singapore) */ + {0x1007, "de"}, /* German (Luxembourg) */ + {0x1009, "en"}, /* English (Canada) */ + {0x100A, "es"}, /* Spanish (Guatemala) */ + {0x100C, "fr"}, /* French (Switzerland) */ + {0x101A, "hr"}, /* Croatian (Latin) (Bosnia and Herzegovina) */ + {0x103B, "smj"}, /* Sami (Lule) (Norway) */ + {0x1401, "ar"}, /* Arabic (Algeria) */ +//{0x1404, ""}, /* Chinese (Macao S.A.R.) */ + {0x1407, "de"}, /* German (Liechtenstein) */ + {0x1409, "en"}, /* English (New Zealand) */ + {0x140A, "es"}, /* Spanish (Costa Rica) */ + {0x140C, "fr"}, /* French (Luxembourg) */ + {0x141A, "bs"}, /* Bosnian (Latin) (Bosnia and Herzegovina) */ +//{0x143B, ""}, /* Sami (Lule) (Sweden) */ + {0x1801, "ar"}, /* Arabic (Morocco) */ + {0x1809, "en"}, /* English (Ireland) */ + {0x180A, "es"}, /* Spanish (Panama) */ + {0x180C, "fr"}, /* French (Principality of Monaco) */ +//{0x181A, ""}, /* Serbian (Latin) (Bosnia and Herzegovina) */ + {0x183B, "sma"}, /* Sami (Southern) (Norway) */ + {0x1C01, "ar"}, /* Arabic (Tunisia) */ + {0x1C09, "en"}, /* English (South Africa) */ + {0x1C0A, "es"}, /* Spanish (Dominican Republic) */ + {0x1C0C, "fr"}, /* ??? */ +//{0x1C1A, ""}, /* Serbian (Cyrillic) (Bosnia and Herzegovina) */ +//{0x1C3B, ""}, /* Sami (Southern) (Sweden) */ + {0x2001, "ar"}, /* Arabic (Oman) */ + {0x2009, "en"}, /* English (Jamaica) */ + {0x200A, "es"}, /* Spanish (Venezuela) */ + {0x200C, "fr"}, /* ??? */ + {0x201A, "bs"}, /* Bosnian (Cyrillic) (Bosnia and Herzegovina) */ + {0x203B, "sms"}, /* Sami (Skolt) (Finland) */ + {0x2401, "ar"}, /* Arabic (Yemen) */ + {0x2409, "en"}, /* English (Caribbean) */ + {0x240A, "es"}, /* Spanish (Colombia) */ + {0x240C, "fr"}, /* ??? */ + {0x243B, "smn"}, /* Sami (Inari) (Finland) */ + {0x2801, "ar"}, /* Arabic (Syria) */ + {0x2809, "en"}, /* English (Belize) */ + {0x280A, "es"}, /* Spanish (Peru) */ + {0x280C, "fr"}, /* ??? */ + {0x2C01, "ar"}, /* Arabic (Jordan) */ + {0x2C09, "en"}, /* English (Trinidad and Tobago) */ + {0x2C0A, "es"}, /* Spanish (Argentina) */ + {0x2C0C, "fr"}, /* ??? */ + {0x3001, "ar"}, /* Arabic (Lebanon) */ + {0x3009, "en"}, /* English (Zimbabwe) */ + {0x300A, "es"}, /* Spanish (Ecuador) */ + {0x300C, "fr"}, /* ??? */ + {0x3401, "ar"}, /* Arabic (Kuwait) */ + {0x3409, "en"}, /* English (Republic of the Philippines) */ + {0x340A, "es"}, /* Spanish (Chile) */ + {0x340C, "fr"}, /* ??? */ + {0x3801, "ar"}, /* Arabic (U.A.E.) */ + {0x380A, "es"}, /* Spanish (Uruguay) */ + {0x380C, "fr"}, /* ??? */ + {0x3C01, "ar"}, /* Arabic (Bahrain) */ + {0x3C09, "en"}, /* ??? */ + {0x3C0A, "es"}, /* Spanish (Paraguay) */ + {0x3C0C, "fr"}, /* ??? */ + {0x4001, "ar"}, /* Arabic (Qatar) */ + {0x4009, "en"}, /* English (India) */ + {0x400A, "es"}, /* Spanish (Bolivia) */ + {0x4409, "en"}, /* English (Malaysia) */ + {0x440A, "es"}, /* Spanish (El Salvador) */ + {0x4809, "en"}, /* English (Singapore) */ + {0x480A, "es"}, /* Spanish (Honduras) */ + {0x4C0A, "es"}, /* Spanish (Nicaragua) */ + {0x500A, "es"}, /* Spanish (Puerto Rico) */ + {0x540A, "es"}, /* Spanish (United States) */ + {0xE40A, "es"}, /* ??? */ + {0xE40C, "fr"}, /* ??? */ +}; + +static const hb_ot_language_map_t +hb_mac_language_map[] = +{ + { 0, "en"}, /* English */ + { 1, "fr"}, /* French */ + { 2, "de"}, /* German */ + { 3, "it"}, /* Italian */ + { 4, "nl"}, /* Dutch */ + { 5, "sv"}, /* Swedish */ + { 6, "es"}, /* Spanish */ + { 7, "da"}, /* Danish */ + { 8, "pt"}, /* Portuguese */ + { 9, "no"}, /* Norwegian */ + { 10, "he"}, /* Hebrew */ + { 11, "ja"}, /* Japanese */ + { 12, "ar"}, /* Arabic */ + { 13, "fi"}, /* Finnish */ + { 14, "el"}, /* Greek */ + { 15, "is"}, /* Icelandic */ + { 16, "mt"}, /* Maltese */ + { 17, "tr"}, /* Turkish */ + { 18, "hr"}, /* Croatian */ + { 19, "zh-tw"}, /* Chinese (Traditional) */ + { 20, "ur"}, /* Urdu */ + { 21, "hi"}, /* Hindi */ + { 22, "th"}, /* Thai */ + { 23, "ko"}, /* Korean */ + { 24, "lt"}, /* Lithuanian */ + { 25, "pl"}, /* Polish */ + { 26, "hu"}, /* Hungarian */ + { 27, "et"}, /* Estonian */ + { 28, "lv"}, /* Latvian */ +//{ 29, ""}, /* Sami */ + { 30, "fo"}, /* Faroese */ + { 31, "fa"}, /* Farsi/Persian */ + { 32, "ru"}, /* Russian */ + { 33, "zh-cn"}, /* Chinese (Simplified) */ + { 34, "nl"}, /* Flemish */ + { 35, "ga"}, /* Irish Gaelic */ + { 36, "sq"}, /* Albanian */ + { 37, "ro"}, /* Romanian */ + { 38, "cs"}, /* Czech */ + { 39, "sk"}, /* Slovak */ + { 40, "sl"}, /* Slovenian */ + { 41, "yi"}, /* Yiddish */ + { 42, "sr"}, /* Serbian */ + { 43, "mk"}, /* Macedonian */ + { 44, "bg"}, /* Bulgarian */ + { 45, "uk"}, /* Ukrainian */ + { 46, "be"}, /* Byelorussian */ + { 47, "uz"}, /* Uzbek */ + { 48, "kk"}, /* Kazakh */ + { 49, "az"}, /* Azerbaijani (Cyrillic script) */ + { 50, "az"}, /* Azerbaijani (Arabic script) */ + { 51, "hy"}, /* Armenian */ + { 52, "ka"}, /* Georgian */ + { 53, "mo"}, /* Moldavian */ + { 54, "ky"}, /* Kirghiz */ + { 55, "tg"}, /* Tajiki */ + { 56, "tk"}, /* Turkmen */ + { 57, "mn"}, /* Mongolian (Mongolian script) */ + { 58, "mn"}, /* Mongolian (Cyrillic script) */ + { 59, "ps"}, /* Pashto */ + { 60, "ku"}, /* Kurdish */ + { 61, "ks"}, /* Kashmiri */ + { 62, "sd"}, /* Sindhi */ + { 63, "bo"}, /* Tibetan */ + { 64, "ne"}, /* Nepali */ + { 65, "sa"}, /* Sanskrit */ + { 66, "mr"}, /* Marathi */ + { 67, "bn"}, /* Bengali */ + { 68, "as"}, /* Assamese */ + { 69, "gu"}, /* Gujarati */ + { 70, "pa"}, /* Punjabi */ + { 71, "or"}, /* Oriya */ + { 72, "ml"}, /* Malayalam */ + { 73, "kn"}, /* Kannada */ + { 74, "ta"}, /* Tamil */ + { 75, "te"}, /* Telugu */ + { 76, "si"}, /* Sinhalese */ + { 77, "my"}, /* Burmese */ + { 78, "km"}, /* Khmer */ + { 79, "lo"}, /* Lao */ + { 80, "vi"}, /* Vietnamese */ + { 81, "id"}, /* Indonesian */ + { 82, "tl"}, /* Tagalog */ + { 83, "ms"}, /* Malay (Roman script) */ + { 84, "ms"}, /* Malay (Arabic script) */ + { 85, "am"}, /* Amharic */ + { 86, "ti"}, /* Tigrinya */ + { 87, "om"}, /* Galla */ + { 88, "so"}, /* Somali */ + { 89, "sw"}, /* Swahili */ + { 90, "rw"}, /* Kinyarwanda/Ruanda */ + { 91, "rn"}, /* Rundi */ + { 92, "ny"}, /* Nyanja/Chewa */ + { 93, "mg"}, /* Malagasy */ + { 94, "eo"}, /* Esperanto */ + {128, "cy"}, /* Welsh */ + {129, "eu"}, /* Basque */ + {130, "ca"}, /* Catalan */ + {131, "la"}, /* Latin */ + {132, "qu"}, /* Quechua */ + {133, "gn"}, /* Guarani */ + {134, "ay"}, /* Aymara */ + {135, "tt"}, /* Tatar */ + {136, "ug"}, /* Uighur */ + {137, "dz"}, /* Dzongkha */ + {138, "jw"}, /* Javanese (Roman script) */ + {139, "su"}, /* Sundanese (Roman script) */ + {140, "gl"}, /* Galician */ + {141, "af"}, /* Afrikaans */ + {142, "br"}, /* Breton */ + {143, "iu"}, /* Inuktitut */ + {144, "gd"}, /* Scottish Gaelic */ + {145, "gv"}, /* Manx Gaelic */ + {146, "ga"}, /* Irish Gaelic (with dot above) */ + {147, "to"}, /* Tongan */ + {148, "el"}, /* Greek (polytonic) */ + {149, "ik"}, /* Greenlandic */ + {150, "az"}, /* Azerbaijani (Roman script) */ +}; + + +static hb_language_t +_hb_ot_name_language_for (unsigned int code, + const hb_ot_language_map_t *array, + unsigned int len) +{ + const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *) + hb_bsearch (&code, + array, + len, + sizeof (array[0]), + hb_ot_language_map_t::cmp); + + if (entry) + return hb_language_from_string (entry->lang, -1); + + return HB_LANGUAGE_INVALID; +} + +hb_language_t +_hb_ot_name_language_for_ms_code (unsigned int code) +{ + return _hb_ot_name_language_for (code, + hb_ms_language_map, + ARRAY_LENGTH (hb_ms_language_map)); +} + +hb_language_t +_hb_ot_name_language_for_mac_code (unsigned int code) +{ + return _hb_ot_name_language_for (code, + hb_mac_language_map, + ARRAY_LENGTH (hb_mac_language_map)); +} diff --git a/src/hb-ot-name-language.hh b/src/hb-ot-name-language.hh new file mode 100644 index 0000000..903076c --- /dev/null +++ b/src/hb-ot-name-language.hh @@ -0,0 +1,40 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_OT_NAME_LANGUAGE_HH +#define HB_OT_NAME_LANGUAGE_HH + +#include "hb.hh" + + +HB_INTERNAL hb_language_t +_hb_ot_name_language_for_ms_code (unsigned int code); + +HB_INTERNAL hb_language_t +_hb_ot_name_language_for_mac_code (unsigned int code); + + +#endif /* HB_OT_NAME_LANGUAGE_HH */ diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index bff85df..c8ababd 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -27,38 +27,73 @@ #ifndef HB_OT_NAME_TABLE_HH #define HB_OT_NAME_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-name-language.hh" +#include "hb-aat-layout.hh" namespace OT { +#define entry_score var.u16[0] +#define entry_index var.u16[1] + + /* * name -- Naming * https://docs.microsoft.com/en-us/typography/opentype/spec/name */ #define HB_OT_TAG_name HB_TAG('n','a','m','e') +#define UNSUPPORTED 42 struct NameRecord { - static int cmp (const void *pa, const void *pb) + hb_language_t language (hb_face_t *face) const { - const NameRecord *a = (const NameRecord *) pa; - const NameRecord *b = (const NameRecord *) pb; - int ret; - ret = b->platformID.cmp (a->platformID); - if (ret) return ret; - ret = b->encodingID.cmp (a->encodingID); - if (ret) return ret; - ret = b->languageID.cmp (a->languageID); - if (ret) return ret; - ret = b->nameID.cmp (a->nameID); - if (ret) return ret; - return 0; + unsigned int p = platformID; + unsigned int l = languageID; + + if (p == 3) + return _hb_ot_name_language_for_ms_code (l); + + if (p == 1) + return _hb_ot_name_language_for_mac_code (l); + + if (p == 0) + return _hb_aat_language_get (face, l); + + return HB_LANGUAGE_INVALID; } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + uint16_t score () const + { + /* Same order as in cmap::find_best_subtable(). */ + unsigned int p = platformID; + unsigned int e = encodingID; + + /* 32-bit. */ + if (p == 3 && e == 10) return 0; + if (p == 0 && e == 6) return 1; + if (p == 0 && e == 4) return 2; + + /* 16-bit. */ + if (p == 3 && e == 1) return 3; + if (p == 0 && e == 3) return 4; + if (p == 0 && e == 2) return 5; + if (p == 0 && e == 1) return 6; + if (p == 0 && e == 0) return 7; + + /* Symbol. */ + if (p == 3 && e == 0) return 8; + + /* We treat all Mac Latin names as ASCII only. */ + if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ + + return UNSUPPORTED; + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); /* We can check from base all the way up to the end of string... */ @@ -75,62 +110,168 @@ struct NameRecord DEFINE_SIZE_STATIC (12); }; +static int +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb) +{ + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + /* Compare by name_id, then language. */ + + if (a->name_id != b->name_id) + return a->name_id < b->name_id ? -1 : +1; + + if (a->language == b->language) return 0; + if (!a->language) return -1; + if (!b->language) return +1; + return strcmp (hb_language_to_string (a->language), + hb_language_to_string (b->language)); +} + +static int +_hb_ot_name_entry_cmp (const void *pa, const void *pb) +{ + /* Compare by name_id, then language, then score, then index. */ + + int v = _hb_ot_name_entry_cmp_key (pa, pb); + if (v) + return v; + + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + if (a->entry_score != b->entry_score) + return a->entry_score < b->entry_score ? -1 : +1; + + if (a->entry_index != b->entry_index) + return a->entry_index < b->entry_index ? -1 : +1; + + return 0; +} + struct name { - static const hb_tag_t tableTag = HB_OT_TAG_name; - - inline unsigned int get_name (unsigned int platform_id, - unsigned int encoding_id, - unsigned int language_id, - unsigned int name_id, - void *buffer, - unsigned int buffer_length) const - { - NameRecord key; - key.platformID.set (platform_id); - key.encodingID.set (encoding_id); - key.languageID.set (language_id); - key.nameID.set (name_id); - NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp); - - if (!match) - return 0; - - unsigned int length = MIN (buffer_length, (unsigned int) match->length); - memcpy (buffer, (char *) this + stringOffset + match->offset, length); - return length; - } + static constexpr hb_tag_t tableTag = HB_OT_TAG_name; - inline unsigned int get_size (void) const - { return min_size + count * nameRecord[0].min_size; } + unsigned int get_size () const + { return min_size + count * nameRecordZ.item_size; } - inline bool sanitize_records (hb_sanitize_context_t *c) const { + bool sanitize_records (hb_sanitize_context_t *c) const + { TRACE_SANITIZE (this); - char *string_pool = (char *) this + stringOffset; + const void *string_pool = (this+stringOffset).arrayZ; unsigned int _count = count; + /* Move to run-time?! */ for (unsigned int i = 0; i < _count; i++) - if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false); + if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false); return_trace (true); } - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && likely (format == 0 || format == 1) && - c->check_array (nameRecord, nameRecord[0].static_size, count) && - sanitize_records (c)); + c->check_array (nameRecordZ.arrayZ, count) && + c->check_range (this, stringOffset)); } + struct accelerator_t + { + void init (hb_face_t *face) + { + this->table = hb_sanitize_context_t().reference_table<name> (face); + assert (this->table.get_length () >= this->table->stringOffset); + this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); + this->pool_len = this->table.get_length () - this->table->stringOffset; + const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ, + this->table->count); + + this->names.init (); + this->names.alloc (all_names.length); + + for (unsigned int i = 0; i < all_names.length; i++) + { + hb_ot_name_entry_t *entry = this->names.push (); + + entry->name_id = all_names[i].nameID; + entry->language = all_names[i].language (face); + entry->entry_score = all_names[i].score (); + entry->entry_index = i; + } + + this->names.qsort (_hb_ot_name_entry_cmp); + /* Walk and pick best only for each name_id,language pair, + * while dropping unsupported encodings. */ + unsigned int j = 0; + for (unsigned int i = 0; i < this->names.length; i++) + { + if (this->names[i].entry_score == UNSUPPORTED || + this->names[i].language == HB_LANGUAGE_INVALID) + continue; + if (i && + this->names[i - 1].name_id == this->names[i].name_id && + this->names[i - 1].language == this->names[i].language) + continue; + this->names[j++] = this->names[i]; + } + this->names.resize (j); + } + + void fini () + { + this->names.fini (); + this->table.destroy (); + } + + int get_index (hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *width=nullptr) const + { + const hb_ot_name_entry_t key = {name_id, {0}, language}; + const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *) + hb_bsearch (&key, + (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (key), + _hb_ot_name_entry_cmp_key); + if (!entry) + return -1; + + if (width) + *width = entry->entry_score < 10 ? 2 : 1; + + return entry->entry_index; + } + + hb_bytes_t get_name (unsigned int idx) const + { + const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count); + const NameRecord &record = all_names[idx]; + const hb_bytes_t string_pool (pool, pool_len); + return string_pool.sub_array (record.offset, record.length); + } + + private: + const char *pool; + unsigned int pool_len; + public: + hb_blob_ptr_t<name> table; + hb_vector_t<hb_ot_name_entry_t> names; + }; + /* We only implement format 0 for now. */ HBUINT16 format; /* Format selector (=0/1). */ HBUINT16 count; /* Number of name records. */ - Offset16 stringOffset; /* Offset to start of string storage (from start of table). */ - NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ + NNOffsetTo<UnsizedArrayOf<HBUINT8> > + stringOffset; /* Offset to start of string storage (from start of table). */ + UnsizedArrayOf<NameRecord> + nameRecordZ; /* The name records where count is the number of records. */ public: - DEFINE_SIZE_ARRAY (6, nameRecord); + DEFINE_SIZE_ARRAY (6, nameRecordZ); }; +struct name_accelerator_t : name::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc new file mode 100644 index 0000000..907ae6a --- /dev/null +++ b/src/hb-ot-name.cc @@ -0,0 +1,224 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#include "hb.hh" + +#include "hb-ot-name-table.hh" + +#include "hb-ot-face.hh" +#include "hb-utf.hh" + + +/** + * SECTION:hb-ot-name + * @title: hb-ot-name + * @short_description: OpenType font name information + * @include: hb-ot.h + * + * Functions for fetching name strings from OpenType fonts. + **/ + + +/** + * hb_ot_name_list_names: + * @face: font face. + * @num_entries: (out) (allow-none): number of returned entries. + * + * Enumerates all available name IDs and language combinations. Returned + * array is owned by the @face and should not be modified. It can be + * used as long as @face is alive. + * + * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries. + * Since: 2.1.0 + **/ +const hb_ot_name_entry_t * +hb_ot_name_list_names (hb_face_t *face, + unsigned int *num_entries /* OUT */) +{ + const OT::name_accelerator_t &name = *face->table.name; + if (num_entries) *num_entries = name.names.length; + return (const hb_ot_name_entry_t *) name.names; +} + + +template <typename in_utf_t, typename out_utf_t> +static inline unsigned int +hb_ot_name_convert_utf (hb_bytes_t bytes, + unsigned int *text_size /* IN/OUT */, + typename out_utf_t::codepoint_t *text /* OUT */) +{ + unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t); + const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ; + const typename in_utf_t::codepoint_t *src_end = src + src_len; + + typename out_utf_t::codepoint_t *dst = text; + + hb_codepoint_t unicode; + const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + + if (text_size && *text_size) + { + (*text_size)--; /* Same room for NUL-termination. */ + const typename out_utf_t::codepoint_t *dst_end = text + *text_size; + + while (src < src_end && dst < dst_end) + { + const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement); + typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode); + if (dst_next == dst) + break; /* Out-of-room. */ + + dst = dst_next; + src = src_next; + }; + + *text_size = dst - text; + *dst = 0; /* NUL-terminate. */ + } + + /* Accumulate length of rest. */ + unsigned int dst_len = dst - text; + while (src < src_end) + { + src = in_utf_t::next (src, src_end, &unicode, replacement); + dst_len += out_utf_t::encode_len (unicode); + }; + return dst_len; +} + +template <typename utf_t> +static inline unsigned int +hb_ot_name_get_utf (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + typename utf_t::codepoint_t *text /* OUT */) +{ + const OT::name_accelerator_t &name = *face->table.name; + + if (!language) + language = hb_language_from_string ("en", 2); + + unsigned int width; + int idx = name.get_index (name_id, language, &width); + if (idx != -1) + { + hb_bytes_t bytes = name.get_name (idx); + + if (width == 2) /* UTF16-BE */ + return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text); + + if (width == 1) /* ASCII */ + return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text); + } + + if (text_size) + { + if (*text_size) + *text = 0; + *text_size = 0; + } + return 0; +} + +/** + * hb_ot_name_get_utf8: + * @face: font face. + * @name_id: OpenType name identifier to fetch. + * @language: language to fetch the name for. + * @text_size: (inout) (allow-none): input size of @text buffer, and output size of + * text written to buffer. + * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into. + * + * Fetches a font name from the OpenType 'name' table. + * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed. + * Returns string in UTF-8 encoding. + * + * Returns: full length of the requested string, or 0 if not found. + * Since: 2.1.0 + **/ +unsigned int +hb_ot_name_get_utf8 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + char *text /* OUT */) +{ + return hb_ot_name_get_utf<hb_utf8_t> (face, name_id, language, text_size, + (hb_utf8_t::codepoint_t *) text); +} + +/** + * hb_ot_name_get_utf16: + * @face: font face. + * @name_id: OpenType name identifier to fetch. + * @language: language to fetch the name for. + * @text_size: (inout) (allow-none): input size of @text buffer, and output size of + * text written to buffer. + * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into. + * + * Fetches a font name from the OpenType 'name' table. + * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed. + * Returns string in UTF-16 encoding. + * + * Returns: full length of the requested string, or 0 if not found. + * Since: 2.1.0 + **/ +unsigned int +hb_ot_name_get_utf16 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + uint16_t *text /* OUT */) +{ + return hb_ot_name_get_utf<hb_utf16_t> (face, name_id, language, text_size, text); +} + +/** + * hb_ot_name_get_utf32: + * @face: font face. + * @name_id: OpenType name identifier to fetch. + * @language: language to fetch the name for. + * @text_size: (inout) (allow-none): input size of @text buffer, and output size of + * text written to buffer. + * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into. + * + * Fetches a font name from the OpenType 'name' table. + * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed. + * Returns string in UTF-32 encoding. + * + * Returns: full length of the requested string, or 0 if not found. + * Since: 2.1.0 + **/ +unsigned int +hb_ot_name_get_utf32 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + uint32_t *text /* OUT */) +{ + return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text); +} diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h new file mode 100644 index 0000000..3b4ad58 --- /dev/null +++ b/src/hb-ot-name.h @@ -0,0 +1,129 @@ +/* + * Copyright © 2018 Ebrahim Byagowi. + * + * 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. + */ + +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + +#ifndef HB_OT_NAME_H +#define HB_OT_NAME_H + +#include "hb.h" + +HB_BEGIN_DECLS + + +/** + * hb_ot_name_id_t: + * @HB_OT_NAME_ID_INVALID: Value to represent a nonexistent name ID. + * + * An integral type representing an OpenType 'name' table name identifier. + * There are predefined name IDs, as well as name IDs return from other + * API. These can be used to fetch name strings from a font face. + * + * Since: 2.0.0 + **/ +enum +{ + HB_OT_NAME_ID_COPYRIGHT = 0, + HB_OT_NAME_ID_FONT_FAMILY = 1, + HB_OT_NAME_ID_FONT_SUBFAMILY = 2, + HB_OT_NAME_ID_UNIQUE_ID = 3, + HB_OT_NAME_ID_FULL_NAME = 4, + HB_OT_NAME_ID_VERSION_STRING = 5, + HB_OT_NAME_ID_POSTSCRIPT_NAME = 6, + HB_OT_NAME_ID_TRADEMARK = 7, + HB_OT_NAME_ID_MANUFACTURER = 8, + HB_OT_NAME_ID_DESIGNER = 9, + HB_OT_NAME_ID_DESCRIPTION = 10, + HB_OT_NAME_ID_VENDOR_URL = 11, + HB_OT_NAME_ID_DESIGNER_URL = 12, + HB_OT_NAME_ID_LICENSE = 13, + HB_OT_NAME_ID_LICENSE_URL = 14, +/*HB_OT_NAME_ID_RESERVED = 15,*/ + HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY = 16, + HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY = 17, + HB_OT_NAME_ID_MAC_FULL_NAME = 18, + HB_OT_NAME_ID_SAMPLE_TEXT = 19, + HB_OT_NAME_ID_CID_FINDFONT_NAME = 20, + HB_OT_NAME_ID_WWS_FAMILY = 21, + HB_OT_NAME_ID_WWS_SUBFAMILY = 22, + HB_OT_NAME_ID_LIGHT_BACKGROUND = 23, + HB_OT_NAME_ID_DARK_BACKGROUND = 24, + HB_OT_NAME_ID_VARIATIONS_PS_PREFIX = 25, + + HB_OT_NAME_ID_INVALID = 0xFFFF +}; + +typedef unsigned int hb_ot_name_id_t; + + +/** + * hb_ot_name_entry_t: + * @name_id: name ID + * @language: language + * + * Structure representing a name ID in a particular language. + * + * Since: 2.1.0 + **/ +typedef struct hb_ot_name_entry_t +{ + hb_ot_name_id_t name_id; + /*< private >*/ + hb_var_int_t var; + /*< public >*/ + hb_language_t language; +} hb_ot_name_entry_t; + +HB_EXTERN const hb_ot_name_entry_t * +hb_ot_name_list_names (hb_face_t *face, + unsigned int *num_entries /* OUT */); + + +HB_EXTERN unsigned int +hb_ot_name_get_utf8 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + char *text /* OUT */); + +HB_EXTERN unsigned int +hb_ot_name_get_utf16 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + uint16_t *text /* OUT */); + +HB_EXTERN unsigned int +hb_ot_name_get_utf32 (hb_face_t *face, + hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *text_size /* IN/OUT */, + uint32_t *text /* OUT */); + + +HB_END_DECLS + +#endif /* HB_OT_NAME_H */ diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index c52b7eb..68dd63e 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2011,2012 Google, Inc. + * Copyright © 2018 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -27,36 +28,131 @@ #ifndef HB_OT_OS2_TABLE_HH #define HB_OT_OS2_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-os2-unicode-ranges.hh" -#include "hb-subset-plan.hh" -namespace OT { +#include "hb-set.hh" /* * OS/2 and Windows Metrics * https://docs.microsoft.com/en-us/typography/opentype/spec/os2 */ -#define HB_OT_TAG_os2 HB_TAG('O','S','/','2') +#define HB_OT_TAG_OS2 HB_TAG('O','S','/','2') + + +namespace OT { -struct os2 +struct OS2V1Tail { - static const hb_tag_t tableTag = HB_OT_TAG_os2; + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT32 ulCodePageRange1; + HBUINT32 ulCodePageRange2; + public: + DEFINE_SIZE_STATIC (8); +}; - inline bool sanitize (hb_sanitize_context_t *c) const +struct OS2V2Tail +{ + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - inline bool subset (hb_subset_plan_t *plan) const + public: + HBINT16 sxHeight; + HBINT16 sCapHeight; + HBUINT16 usDefaultChar; + HBUINT16 usBreakChar; + HBUINT16 usMaxContext; + public: + DEFINE_SIZE_STATIC (10); +}; + +struct OS2V5Tail +{ + bool sanitize (hb_sanitize_context_t *c) const { - hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_os2)); + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT16 usLowerOpticalPointSize; + HBUINT16 usUpperOpticalPointSize; + public: + DEFINE_SIZE_STATIC (4); +}; + +struct OS2 +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2; + + bool has_data () const { return this != &Null (OS2); } + + const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); } + const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); } + const OS2V5Tail &v5 () const { return version >= 5 ? v5X : Null (OS2V5Tail); } + + enum selection_flag_t { + ITALIC = 1u<<0, + UNDERSCORE = 1u<<1, + NEGATIVE = 1u<<2, + OUTLINED = 1u<<3, + STRIKEOUT = 1u<<4, + BOLD = 1u<<5, + REGULAR = 1u<<6, + USE_TYPO_METRICS = 1u<<7, + WWS = 1u<<8, + OBLIQUE = 1u<<9 + }; + + bool is_italic () const { return fsSelection & ITALIC; } + bool is_oblique () const { return fsSelection & OBLIQUE; } + bool is_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } + + enum width_class_t { + FWIDTH_ULTRA_CONDENSED = 1, /* 50% */ + FWIDTH_EXTRA_CONDENSED = 2, /* 62.5% */ + FWIDTH_CONDENSED = 3, /* 75% */ + FWIDTH_SEMI_CONDENSED = 4, /* 87.5% */ + FWIDTH_NORMAL = 5, /* 100% */ + FWIDTH_SEMI_EXPANDED = 6, /* 112.5% */ + FWIDTH_EXPANDED = 7, /* 125% */ + FWIDTH_EXTRA_EXPANDED = 8, /* 150% */ + FWIDTH_ULTRA_EXPANDED = 9 /* 200% */ + }; + + float get_width () const + { + switch (usWidthClass) { + case FWIDTH_ULTRA_CONDENSED:return 50.f; + case FWIDTH_EXTRA_CONDENSED:return 62.5f; + case FWIDTH_CONDENSED: return 75.f; + case FWIDTH_SEMI_CONDENSED: return 87.5f; + default: + case FWIDTH_NORMAL: return 100.f; + case FWIDTH_SEMI_EXPANDED: return 112.5f; + case FWIDTH_EXPANDED: return 125.f; + case FWIDTH_EXTRA_EXPANDED: return 150.f; + case FWIDTH_ULTRA_EXPANDED: return 200.f; + } + } + + bool subset (hb_subset_plan_t *plan) const + { + hb_blob_t *os2_blob = hb_sanitize_context_t ().reference_table<OS2> (plan->source); hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1); // TODO(grieger): move to hb_blob_copy_writable_or_fail hb_blob_destroy (os2_blob); - OT::os2 *os2_prime = (OT::os2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr); + OS2 *os2_prime = (OS2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr); if (unlikely (!os2_prime)) { hb_blob_destroy (os2_prime_blob); return false; @@ -68,41 +164,41 @@ struct os2 os2_prime->usLastCharIndex.set (max_cp); _update_unicode_ranges (plan->unicodes, os2_prime->ulUnicodeRange); - bool result = plan->add_table (HB_OT_TAG_os2, os2_prime_blob); + bool result = plan->add_table (HB_OT_TAG_OS2, os2_prime_blob); hb_blob_destroy (os2_prime_blob); return result; } - inline void _update_unicode_ranges (const hb_set_t *codepoints, - HBUINT32 ulUnicodeRange[4]) const + void _update_unicode_ranges (const hb_set_t *codepoints, + HBUINT32 ulUnicodeRange[4]) const { for (unsigned int i = 0; i < 4; i++) ulUnicodeRange[i].set (0); hb_codepoint_t cp = HB_SET_VALUE_INVALID; while (codepoints->next (&cp)) { - unsigned int bit = hb_get_unicode_range_bit (cp); + unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp); if (bit < 128) { - unsigned int block = bit / 32; - unsigned int bit_in_block = bit % 32; - unsigned int mask = 1 << bit_in_block; - ulUnicodeRange[block].set (ulUnicodeRange[block] | mask); + unsigned int block = bit / 32; + unsigned int bit_in_block = bit % 32; + unsigned int mask = 1 << bit_in_block; + ulUnicodeRange[block].set (ulUnicodeRange[block] | mask); } if (cp >= 0x10000 && cp <= 0x110000) { - /* the spec says that bit 57 ("Non Plane 0") implies that there's - at least one codepoint beyond the BMP; so I also include all - the non-BMP codepoints here */ - ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25)); + /* the spec says that bit 57 ("Non Plane 0") implies that there's + at least one codepoint beyond the BMP; so I also include all + the non-BMP codepoints here */ + ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25)); } } } - static inline void find_min_and_max_codepoint (const hb_set_t *codepoints, - uint16_t *min_cp, /* OUT */ - uint16_t *max_cp /* OUT */) + static void find_min_and_max_codepoint (const hb_set_t *codepoints, + uint16_t *min_cp, /* OUT */ + uint16_t *max_cp /* OUT */) { *min_cp = codepoints->get_min (); *max_cp = codepoints->get_max (); @@ -119,17 +215,21 @@ struct os2 }; // https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 - inline font_page_t get_font_page () const + font_page_t get_font_page () const + { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } + + bool sanitize (hb_sanitize_context_t *c) const { - if (version != 0) - return (font_page_t) 0; - return (font_page_t) (fsSelection & 0xFF00); + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false); + if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false); + if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false); + return_trace (true); } public: HBUINT16 version; - - /* Version 0 */ HBINT16 xAvgCharWidth; HBUINT16 usWeightClass; HBUINT16 usWidthClass; @@ -156,24 +256,11 @@ struct os2 HBINT16 sTypoLineGap; HBUINT16 usWinAscent; HBUINT16 usWinDescent; - - /* Version 1 */ - //HBUINT32 ulCodePageRange1; - //HBUINT32 ulCodePageRange2; - - /* Version 2 */ - //HBINT16 sxHeight; - //HBINT16 sCapHeight; - //HBUINT16 usDefaultChar; - //HBUINT16 usBreakChar; - //HBUINT16 usMaxContext; - - /* Version 5 */ - //HBUINT16 usLowerOpticalPointSize; - //HBUINT16 usUpperOpticalPointSize; - + OS2V1Tail v1X; + OS2V2Tail v2X; + OS2V5Tail v5X; public: - DEFINE_SIZE_STATIC (78); + DEFINE_SIZE_MIN (78); }; } /* namespace OT */ diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh index 9b32cfa..b0ccd00 100644 --- a/src/hb-ot-os2-unicode-ranges.hh +++ b/src/hb-ot-os2-unicode-ranges.hh @@ -27,19 +27,33 @@ #ifndef HB_OT_OS2_UNICODE_RANGES_HH #define HB_OT_OS2_UNICODE_RANGES_HH -#include "hb-private.hh" -#include "hb-dsalgs.hh" +#include "hb.hh" namespace OT { -struct Range { +struct OS2Range +{ + static int + cmp (const void *_key, const void *_item) + { + hb_codepoint_t cp = *((hb_codepoint_t *) _key); + const OS2Range *range = (OS2Range *) _item; + + if (cp < range->start) + return -1; + else if (cp <= range->end) + return 0; + else + return +1; + } + hb_codepoint_t start; hb_codepoint_t end; unsigned int bit; }; -/* Note: The contents of this array was generated using src/gen-unicode-ranges.py. */ -static Range os2UnicodeRangesSorted[] = +/* Note: The contents of this array was generated using gen-os2-unicode-ranges.py. */ +static const OS2Range _hb_os2_unicode_ranges[] = { { 0x0, 0x7F, 0}, // Basic Latin { 0x80, 0xFF, 1}, // Latin-1 Supplement @@ -212,31 +226,17 @@ static Range os2UnicodeRangesSorted[] = {0x100000, 0x10FFFD, 90}, // Private Use (plane 16) }; -static int -_compare_range (const void *_key, const void *_item, void *_arg) -{ - hb_codepoint_t cp = *((hb_codepoint_t *) _key); - const Range *range = (Range *) _item; - - if (cp < range->start) - return -1; - else if (cp <= range->end) - return 0; - else - return 1; -} - /** - * hb_get_unicode_range_bit: - * Returns the bit to be set in os/2 ulUnicodeRange for a given codepoint. + * _hb_ot_os2_get_unicode_range_bit: + * Returns the bit to be set in os/2 ulUnicodeOS2Range for a given codepoint. **/ static unsigned int -hb_get_unicode_range_bit (hb_codepoint_t cp) +_hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp) { - Range *range = (Range*) hb_bsearch_r (&cp, os2UnicodeRangesSorted, - sizeof (os2UnicodeRangesSorted) / sizeof(Range), - sizeof(Range), - _compare_range, nullptr); + OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges, + ARRAY_LENGTH (_hb_os2_unicode_ranges), + sizeof (OS2Range), + OS2Range::cmp); if (range != nullptr) return range->bit; return -1; diff --git a/src/hb-ot-post-macroman.hh b/src/hb-ot-post-macroman.hh index dbbb97e..b4df8aa 100644 --- a/src/hb-ot-post-macroman.hh +++ b/src/hb-ot-post-macroman.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_POST_MACROMAN_HH #if 0 /* Make checks happy. */ #define HB_OT_POST_MACROMAN_HH -#include "hb-private.hh" +#include "hb.hh" #endif diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 5f42751..43c1143 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh @@ -27,9 +27,7 @@ #ifndef HB_OT_POST_TABLE_HH #define HB_OT_POST_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-dsalgs.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" #define HB_STRING_ARRAY_NAME format1_names #define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh" @@ -51,47 +49,39 @@ namespace OT { struct postV2Tail { - inline bool sanitize (hb_sanitize_context_t *c) const + friend struct post; + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (glyphNameIndex.sanitize (c)); } - ArrayOf<HBUINT16>glyphNameIndex; /* This is not an offset, but is the + protected: + ArrayOf<HBUINT16> glyphNameIndex; /* This is not an offset, but is the * ordinal number of the glyph in 'post' * string tables. */ - HBUINT8 namesX[VAR]; /* Glyph names with length bytes [variable] +/*UnsizedArrayOf<HBUINT8> + namesX;*/ /* Glyph names with length bytes [variable] * (a Pascal string). */ - DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX); + public: + DEFINE_SIZE_ARRAY (2, glyphNameIndex); }; struct post { - static const hb_tag_t tableTag = HB_OT_TAG_post; - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) - return_trace (false); - if (version.to_int () == 0x00020000) - { - const postV2Tail &v2 = StructAfter<postV2Tail> (*this); - return_trace (v2.sanitize (c)); - } - return_trace (true); - } + static constexpr hb_tag_t tableTag = HB_OT_TAG_post; - inline bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_plan_t *plan) const { unsigned int post_prime_length; - hb_blob_t *post_blob = OT::Sanitizer<post>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_post)); - hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::static_size); + hb_blob_t *post_blob = hb_sanitize_context_t ().reference_table<post>(plan->source); + hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::min_size); post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length); hb_blob_destroy (post_blob); - if (unlikely (!post_prime || post_prime_length != post::static_size)) + if (unlikely (!post_prime || post_prime_length != post::min_size)) { hb_blob_destroy (post_prime_blob); DEBUG_MSG(SUBSET, nullptr, "Invalid source post table with length %d.", post_prime_length); @@ -107,63 +97,58 @@ struct post struct accelerator_t { - inline void init (hb_face_t *face) + void init (hb_face_t *face) { index_to_offset.init (); - blob = Sanitizer<post>().sanitize (face->reference_table (HB_OT_TAG_post)); - const post *table = blob->as<post> (); - unsigned int table_length = blob->length; + table = hb_sanitize_context_t ().reference_table<post> (face); + unsigned int table_length = table.get_length (); version = table->version.to_int (); - if (version != 0x00020000) - return; + if (version != 0x00020000) return; - const postV2Tail &v2 = StructAfter<postV2Tail> (*table); + const postV2Tail &v2 = table->v2X; glyphNameIndex = &v2.glyphNameIndex; pool = &StructAfter<uint8_t> (v2.glyphNameIndex); - const uint8_t *end = (uint8_t *) table + table_length; - for (const uint8_t *data = pool; data < end && data + *data <= end; data += 1 + *data) + const uint8_t *end = (const uint8_t *) (const void *) table + table_length; + for (const uint8_t *data = pool; + index_to_offset.length < 65535 && data < end && data + *data < end; + data += 1 + *data) index_to_offset.push (data - pool); } - inline void fini (void) + void fini () { index_to_offset.fini (); - free (gids_sorted_by_name); + free (gids_sorted_by_name.get ()); + table.destroy (); } - inline bool get_glyph_name (hb_codepoint_t glyph, - char *buf, unsigned int buf_len) const + bool get_glyph_name (hb_codepoint_t glyph, + char *buf, unsigned int buf_len) const { hb_bytes_t s = find_glyph_name (glyph); - if (!s.len) - return false; - if (!buf_len) - return true; - if (buf_len <= s.len) /* What to do with truncation? Returning false for now. */ - return false; - strncpy (buf, s.bytes, s.len); - buf[s.len] = '\0'; + if (!s.length) return false; + if (!buf_len) return true; + unsigned int len = MIN (buf_len - 1, s.length); + strncpy (buf, s.arrayZ, len); + buf[len] = '\0'; return true; } - inline bool get_glyph_from_name (const char *name, int len, - hb_codepoint_t *glyph) const + bool get_glyph_from_name (const char *name, int len, + hb_codepoint_t *glyph) const { unsigned int count = get_glyph_count (); - if (unlikely (!count)) - return false; + if (unlikely (!count)) return false; - if (len < 0) - len = strlen (name); + if (len < 0) len = strlen (name); - if (unlikely (!len)) - return false; + if (unlikely (!len)) return false; retry: - uint16_t *gids = (uint16_t *) hb_atomic_ptr_get (&gids_sorted_by_name); + uint16_t *gids = gids_sorted_by_name.get (); if (unlikely (!gids)) { @@ -175,14 +160,16 @@ struct post gids[i] = i; hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); - if (!hb_atomic_ptr_cmpexch (&gids_sorted_by_name, nullptr, gids)) { + if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) + { free (gids); goto retry; } } hb_bytes_t st (name, len); - const uint16_t *gid = (const uint16_t *) hb_bsearch_r (&st, gids, count, sizeof (gids[0]), cmp_key, (void *) this); + const uint16_t *gid = (const uint16_t *) hb_bsearch_r (hb_addressof (st), gids, count, + sizeof (gids[0]), cmp_key, (void *) this); if (gid) { *glyph = *gid; @@ -194,18 +181,18 @@ struct post protected: - inline unsigned int get_glyph_count (void) const + unsigned int get_glyph_count () const { if (version == 0x00010000) - return NUM_FORMAT1_NAMES; + return NUM_FORMAT1_NAMES; if (version == 0x00020000) - return glyphNameIndex->len; + return glyphNameIndex->len; return 0; } - static inline int cmp_gids (const void *pa, const void *pb, void *arg) + static int cmp_gids (const void *pa, const void *pb, void *arg) { const accelerator_t *thiz = (const accelerator_t *) arg; uint16_t a = * (const uint16_t *) pa; @@ -213,7 +200,7 @@ struct post return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a)); } - static inline int cmp_key (const void *pk, const void *po, void *arg) + static int cmp_key (const void *pk, const void *po, void *arg) { const accelerator_t *thiz = (const accelerator_t *) arg; const hb_bytes_t *key = (const hb_bytes_t *) pk; @@ -221,7 +208,7 @@ struct post return thiz->find_glyph_name (o).cmp (*key); } - inline hb_bytes_t find_glyph_name (hb_codepoint_t glyph) const + hb_bytes_t find_glyph_name (hb_codepoint_t glyph) const { if (version == 0x00010000) { @@ -239,9 +226,9 @@ struct post return format1_names (index); index -= NUM_FORMAT1_NAMES; - if (index >= index_to_offset.len) + if (index >= index_to_offset.length) return hb_bytes_t (); - unsigned int offset = index_to_offset.arrayZ[index]; + unsigned int offset = index_to_offset[index]; const uint8_t *data = pool + offset; unsigned int name_length = *data; @@ -251,14 +238,23 @@ struct post } private: - hb_blob_t *blob; + hb_blob_ptr_t<post> table; uint32_t version; const ArrayOf<HBUINT16> *glyphNameIndex; - hb_vector_t<uint32_t, 1> index_to_offset; + hb_vector_t<uint32_t> index_to_offset; const uint8_t *pool; - mutable uint16_t *gids_sorted_by_name; + hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name; }; + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (version.to_int () == 0x00010000 || + (version.to_int () == 0x00020000 && v2X.sanitize (c)) || + version.to_int () == 0x00030000))); + } + public: FixedVersion<>version; /* 0x00010000 for version 1.0 * 0x00020000 for version 2.0 @@ -291,10 +287,12 @@ struct post * is downloaded as a Type 1 font. */ HBUINT32 maxMemType1; /* Maximum memory usage when an OpenType font * is downloaded as a Type 1 font. */ -/*postV2Tail v2[VAR];*/ - DEFINE_SIZE_STATIC (32); + postV2Tail v2X; + DEFINE_SIZE_MIN (32); }; +struct post_accelerator_t : post::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index 5a257f0..2a1f2f8 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -27,9 +27,9 @@ #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH #define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape.hh" #include "hb-ot-layout-gsub-table.hh" @@ -79,18 +79,15 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS * May not be good-enough for presidential candidate interviews, but good-enough for us... */ hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]); - OT::Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs); - OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs); /* Each glyph takes four bytes max, and there's some overhead. */ char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128]; - OT::hb_serialize_context_t c (buf, sizeof (buf)); + hb_serialize_context_t c (buf, sizeof (buf)); OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); bool ret = lookup->serialize_single (&c, OT::LookupFlag::IgnoreMarks, - glyphs_supplier, - substitutes_supplier, - num_glyphs); + hb_array (glyphs, num_glyphs), + hb_array (substitutes, num_glyphs)); c.end_serialize (); /* TODO sanitize the results? */ @@ -155,25 +152,18 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN if (!num_ligatures) return nullptr; - OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs); - OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs); - OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures); - OT::Supplier<unsigned int > component_count_supplier (component_count_list, num_ligatures); - OT::Supplier<OT::GlyphID> component_supplier (component_list, num_ligatures); /* 16 bytes per ligature ought to be enough... */ char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128]; - OT::hb_serialize_context_t c (buf, sizeof (buf)); + hb_serialize_context_t c (buf, sizeof (buf)); OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); bool ret = lookup->serialize_ligature (&c, OT::LookupFlag::IgnoreMarks, - first_glyphs_supplier, - ligature_per_first_glyph_count_supplier, - num_first_glyphs, - ligatures_supplier, - component_count_supplier, - component_supplier); - + hb_array (first_glyphs, num_first_glyphs), + hb_array (ligature_per_first_glyph_count_list, num_first_glyphs), + hb_array (ligature_list, num_ligatures), + hb_array (component_count_list, num_ligatures), + hb_array (component_list, num_ligatures)); c.end_serialize (); /* TODO sanitize the results? */ @@ -195,19 +185,15 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan, struct arabic_fallback_plan_t { - ASSERT_POD (); - unsigned int num_lookups; bool free_lookups; hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS]; OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS]; - hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; + OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; }; -static const arabic_fallback_plan_t arabic_fallback_plan_nil = {}; - -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256) +#if defined(_WIN32) && !defined(HB_NO_WIN1256) #define HB_WITH_WIN1256 #endif @@ -215,16 +201,20 @@ static const arabic_fallback_plan_t arabic_fallback_plan_nil = {}; #include "hb-ot-shape-complex-arabic-win1256.hh" #endif -struct ManifestLookup { +struct ManifestLookup +{ + public: OT::Tag tag; OT::OffsetTo<OT::SubstLookup> lookupOffset; + public: + DEFINE_SIZE_STATIC (6); }; typedef OT::ArrayOf<ManifestLookup> Manifest; static bool -arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan, - const hb_ot_shape_plan_t *plan, - hb_font_t *font) +arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED, + const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED) { #ifdef HB_WITH_WIN1256 /* Does this font look like it's Windows-1256-encoded? */ @@ -299,7 +289,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, { arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t)); if (unlikely (!fallback_plan)) - return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil); + return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t)); fallback_plan->num_lookups = 0; fallback_plan->free_lookups = false; @@ -314,14 +304,15 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font)) return fallback_plan; + assert (fallback_plan->num_lookups == 0); free (fallback_plan); - return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil); + return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t)); } static void arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) { - if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil) + if (!fallback_plan || fallback_plan->num_lookups == 0) return; for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh index 54c6cdc..b15e145 100644 --- a/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/src/hb-ot-shape-complex-arabic-win1256.hh @@ -313,7 +313,7 @@ OT_TABLE_END * Include a second time to get the table data... */ #if 0 -#include "hb-private.hh" /* Make check-includes.sh happy. */ +#include "hb.hh" /* Make check-includes.sh happy. */ #endif #ifdef OT_MEASURE #include "hb-ot-shape-complex-arabic-win1256.hh" diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index 124a67f..50a5213 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -24,10 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-ot-shape-complex-arabic-private.hh" -#include "hb-ot-shape-private.hh" +#include "hb.hh" +#include "hb-ot-shape-complex-arabic.hh" +#include "hb-ot-shape.hh" /* buffer var allocations */ @@ -160,11 +159,6 @@ static const struct arabic_state_table_entry { static void -nuke_joiners (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); - -static void arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); @@ -201,32 +195,38 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) * work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505 */ - map->add_gsub_pause (nuke_joiners); - map->add_global_bool_feature (HB_TAG('s','t','c','h')); + map->enable_feature (HB_TAG('s','t','c','h')); map->add_gsub_pause (record_stch); - map->add_global_bool_feature (HB_TAG('c','c','m','p')); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('l','o','c','l')); map->add_gsub_pause (nullptr); for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]); - map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE); + map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE); map->add_gsub_pause (nullptr); } - map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); + /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script + * however, it says a ZWJ should also mean "don't ligate". So we run + * the main ligating features as MANUAL_ZWJ. */ + + map->enable_feature (HB_TAG('r','l','i','g'), F_MANUAL_ZWJ | F_HAS_FALLBACK); + if (plan->props.script == HB_SCRIPT_ARABIC) map->add_gsub_pause (arabic_fallback_shape); /* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */ - map->add_global_bool_feature (HB_TAG('r','c','l','t')); - map->add_global_bool_feature (HB_TAG('c','a','l','t')); + map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); + /* And undo here. */ + /* The spec includes 'cswh'. Earlier versions of Windows * used to enable this by default, but testing suggests * that Windows 8 and later do not enable it by default, @@ -235,23 +235,21 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) * Note that IranNastaliq uses this feature extensively * to fixup broken glyph sequences. Oh well... * Test case: U+0643,U+0640,U+0631. */ - //map->add_global_bool_feature (HB_TAG('c','s','w','h')); - map->add_global_bool_feature (HB_TAG('m','s','e','t')); + //map->enable_feature (HB_TAG('c','s','w','h')); + map->enable_feature (HB_TAG('m','s','e','t')); } #include "hb-ot-shape-complex-arabic-fallback.hh" struct arabic_shape_plan_t { - ASSERT_POD (); - /* The "+ 1" in the next array is to accommodate for the "NONE" command, * which is not an OpenType feature, but this simplifies the code by not * having to do a "if (... < NONE) ..." and just rely on the fact that * mask_array[NONE] == 0. */ hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1]; - arabic_fallback_plan_t *fallback_plan; + hb_atomic_ptr_t<arabic_fallback_plan_t> fallback_plan; unsigned int do_fallback : 1; unsigned int has_stch : 1; @@ -380,19 +378,6 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script); } - -static void -nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 0; i < count; i++) - if (_hb_glyph_info_is_zwj (&info[i])) - _hb_glyph_info_flip_joiners (&info[i]); -} - static void arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -404,12 +389,13 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan, return; retry: - arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan); + arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan; if (unlikely (!fallback_plan)) { /* This sucks. We need a font to build the fallback plan... */ fallback_plan = arabic_fallback_plan_create (plan, font); - if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, nullptr, fallback_plan))) { + if (unlikely (!arabic_plan->fallback_plan.cmpexch (nullptr, fallback_plan))) + { arabic_fallback_plan_destroy (fallback_plan); goto retry; } @@ -428,7 +414,7 @@ retry: static void record_stch (const hb_ot_shape_plan_t *plan, - hb_font_t *font, + hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; @@ -452,7 +438,7 @@ record_stch (const hb_ot_shape_plan_t *plan, } static void -apply_stch (const hb_ot_shape_plan_t *plan, +apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font) { @@ -470,9 +456,9 @@ apply_stch (const hb_ot_shape_plan_t *plan, int sign = font->x_scale < 0 ? -1 : +1; unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT - typedef enum { MEASURE, CUT } step_t; + enum { MEASURE, CUT } /* step_t */; - for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1)) + for (unsigned int step = MEASURE; step <= CUT; step = step + 1) { unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -611,7 +597,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } -/* https://unicode.org/reports/tr53/tr53-1.pdf */ +/* http://www.unicode.org/reports/tr53/ */ static hb_codepoint_t modifier_combining_marks[] = @@ -623,6 +609,7 @@ modifier_combining_marks[] = 0x06E3u, /* ARABIC SMALL LOW SEEN */ 0x06E7u, /* ARABIC SMALL HIGH YEH */ 0x06E8u, /* ARABIC SMALL HIGH NOON */ + 0x08D3u, /* ARABIC SMALL LOW WAW */ 0x08F3u, /* ARABIC SMALL HIGH WAW */ }; @@ -637,7 +624,7 @@ info_is_mcm (const hb_glyph_info_t &info) } static void -reorder_marks_arabic (const hb_ot_shape_plan_t *plan, +reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, unsigned int start, unsigned int end) @@ -714,7 +701,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = nullptr, /* decompose */ nullptr, /* compose */ setup_masks_arabic, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ reorder_marks_arabic, HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-arabic-private.hh b/src/hb-ot-shape-complex-arabic.hh index fcedc7d..5bf6ff6 100644 --- a/src/hb-ot-shape-complex-arabic-private.hh +++ b/src/hb-ot-shape-complex-arabic.hh @@ -26,12 +26,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH +#define HB_OT_SHAPE_COMPLEX_ARABIC_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" struct arabic_shape_plan_t; @@ -47,4 +47,4 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan, hb_buffer_t *buffer, hb_script_t script); -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_HH */ diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc index 68a62a1..97923ec 100644 --- a/src/hb-ot-shape-complex-default.cc +++ b/src/hb-ot-shape-complex-default.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = @@ -39,7 +39,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = nullptr, /* decompose */ nullptr, /* compose */ nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc index 7420c5d..e143867 100644 --- a/src/hb-ot-shape-complex-hangul.cc +++ b/src/hb-ot-shape-complex-hangul.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" /* Hangul shaper */ @@ -56,7 +56,7 @@ collect_features_hangul (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++) - map->add_feature (hangul_features[i], 1, F_NONE); + map->add_feature (hangul_features[i]); } static void @@ -65,13 +65,11 @@ override_features_hangul (hb_ot_shape_planner_t *plan) /* Uniscribe does not apply 'calt' for Hangul, and certain fonts * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups * in calt, which is not desirable. */ - plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('c','a','l','t')); } struct hangul_shape_plan_t { - ASSERT_POD (); - hb_mask_t mask_array[HANGUL_FEATURE_COUNT]; }; @@ -128,7 +126,7 @@ is_zero_width_char (hb_font_t *font, } static void -preprocess_text_hangul (const hb_ot_shape_plan_t *plan, +preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font) { @@ -345,13 +343,6 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, { unsigned int s_len = tindex ? 3 : 2; buffer->replace_glyphs (1, s_len, decomposed); - if (unlikely (!buffer->successful)) - return; - - /* We decomposed S: apply jamo features to the individual glyphs - * that are now in buffer->out_info. - */ - hb_glyph_info_t *info = buffer->out_info; /* If we decomposed an LV because of a non-combining T following, * we want to include this T in the syllable. @@ -361,6 +352,14 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, buffer->next_glyph (); s_len++; } + + if (unlikely (!buffer->successful)) + return; + + /* We decomposed S: apply jamo features to the individual glyphs + * that are now in buffer->out_info. + */ + hb_glyph_info_t *info = buffer->out_info; end = start + s_len; unsigned int i = start; @@ -368,6 +367,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, info[i++].hangul_shaping_feature() = VJMO; if (i < end) info[i++].hangul_shaping_feature() = TJMO; + if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) buffer->merge_out_clusters (start, end); continue; @@ -424,7 +424,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul = nullptr, /* decompose */ nullptr, /* compose */ setup_masks_hangul, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc index 34cf28b..90c36c0 100644 --- a/src/hb-ot-shape-complex-hebrew.cc +++ b/src/hb-ot-shape-complex-hebrew.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" static bool @@ -70,7 +70,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, bool found = (bool) c->unicode->compose (a, b, ab); - if (!found && !c->plan->has_mark) + if (!found && !c->plan->has_gpos_mark) { /* Special-case Hebrew presentation forms that are excluded from * standard normalization, but wanted for old fonts. */ @@ -154,18 +154,6 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, return found; } -static bool -disable_otl_hebrew (const hb_ot_shape_plan_t *plan) -{ - /* For Hebrew shaper, use fallback if GPOS does not have 'hebr' - * script. This matches Uniscribe better, and makes fonts like - * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work. - * See: - * https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 - */ - return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r'); -} - const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = { @@ -179,7 +167,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = nullptr, /* decompose */ compose_hebrew, nullptr, /* setup_masks */ - disable_otl_hebrew, + HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh index 73f9d58..e2ecfb8 100644 --- a/src/hb-ot-shape-complex-indic-machine.hh +++ b/src/hb-ot-shape-complex-indic-machine.hh @@ -29,892 +29,714 @@ #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { - 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, + 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, - 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, 5u, 8u, 5u, 8u, 5u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 8u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 8u, 8u, 1u, 19u, 3u, 17u, - 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, - 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, - 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, - 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, - 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, - 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, - 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, - 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, - 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, - 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, + 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, + 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, + 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, + 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, + 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, + 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, + 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u, + 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, + 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, + 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, + 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, + 5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, + 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, + 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, + 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, 3u, 17u, 4u, 8u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, - 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, + 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, + 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, + 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, + 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, + 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, + 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, + 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, + 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, + 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, + 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, + 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, + 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, + 3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, + 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, + 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, + 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 1u, 17u, 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, - 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, + 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, + 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u, + 1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0 }; static const char _indic_syllable_machine_key_spans[] = { - 1, 4, 3, 1, 4, 3, 1, 4, + 1, 5, 3, 1, 4, 3, 1, 4, 3, 1, 4, 3, 1, 5, 1, 1, 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 10, 5, 10, 5, 10, 5, - 10, 5, 10, 1, 4, 3, 1, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 1, 1, 5, 10, 5, 10, - 5, 10, 5, 10, 5, 10, 1, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 4, 3, 1, 5, 1, 1, 5, 1, + 1, 10, 5, 10, 5, 10, 5, 10, + 5, 10, 1, 5, 3, 1, 4, 3, + 1, 4, 3, 1, 4, 3, 1, 5, + 1, 1, 5, 1, 1, 5, 1, 1, + 5, 1, 1, 10, 5, 10, 5, 10, + 5, 10, 5, 10, 1, 5, 3, 1, + 4, 3, 1, 4, 3, 1, 4, 3, 1, 5, 1, 1, 5, 1, 1, 5, - 10, 5, 10, 5, 10, 5, 10, 5, + 1, 1, 5, 1, 1, 10, 5, 10, + 5, 10, 5, 10, 5, 1, 5, 3, 1, 4, 3, 1, 4, 3, 1, 4, - 3, 1, 4, 3, 1, 5, 1, 1, - 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 10, 5, 10, 5, 10, 5, - 10, 5, 10, 10, 4, 4, 3, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 1, 5, 1, 1, 5, 1, 1, 5, - 1, 1, 5, 1, 1, 1, 19, 15, - 15, 14, 16, 15, 15, 14, 16, 15, - 15, 14, 16, 15, 15, 14, 16, 15, - 15, 14, 6, 6, 6, 1, 1, 1, - 6, 8, 8, 7, 6, 8, 7, 6, - 8, 7, 6, 8, 7, 6, 8, 7, - 15, 15, 16, 16, 16, 16, 15, 15, - 16, 16, 16, 16, 15, 15, 16, 16, - 16, 16, 15, 15, 16, 16, 16, 16, - 15, 15, 15, 15, 14, 16, 15, 15, - 14, 16, 15, 15, 14, 16, 15, 15, - 14, 16, 15, 15, 14, 6, 6, 6, - 1, 1, 1, 6, 8, 8, 7, 6, - 8, 7, 6, 8, 7, 6, 8, 7, - 6, 8, 7, 15, 15, 16, 16, 16, - 16, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 15, 15, 16, - 16, 16, 16, 5, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 6, - 6, 6, 1, 1, 1, 6, 8, 8, + 3, 1, 5, 1, 1, 5, 1, 1, + 5, 1, 1, 5, 1, 1, 10, 5, + 10, 5, 10, 5, 10, 5, 10, 10, + 4, 1, 19, 11, 8, 7, 16, 11, + 8, 7, 16, 11, 8, 7, 16, 11, + 8, 7, 16, 11, 8, 7, 6, 6, + 6, 1, 1, 1, 6, 8, 6, 8, 7, 6, 8, 7, 6, 8, 7, 6, - 8, 7, 6, 8, 7, 15, 15, 16, - 16, 16, 16, 15, 15, 16, 16, 16, - 16, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 10, 15, 5, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 6, 6, 6, 1, 1, - 1, 6, 8, 8, 7, 6, 8, 7, + 8, 7, 8, 11, 16, 16, 16, 8, + 11, 16, 16, 16, 8, 11, 16, 16, + 16, 8, 11, 16, 16, 16, 8, 11, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 6, 6, 6, 1, 1, + 1, 6, 8, 6, 8, 7, 6, 8, + 7, 6, 8, 7, 6, 8, 7, 8, + 11, 16, 16, 16, 8, 11, 16, 16, + 16, 8, 11, 16, 16, 16, 8, 11, + 16, 16, 16, 5, 8, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 6, + 6, 6, 1, 1, 1, 6, 8, 6, + 8, 7, 6, 8, 7, 6, 8, 7, + 6, 8, 7, 8, 11, 16, 16, 16, + 8, 11, 16, 16, 16, 8, 11, 16, + 16, 16, 8, 11, 16, 16, 16, 10, + 8, 5, 11, 8, 7, 16, 11, 8, + 7, 16, 11, 8, 7, 16, 11, 8, + 7, 16, 11, 8, 7, 6, 6, 6, + 1, 1, 1, 6, 8, 6, 8, 7, 6, 8, 7, 6, 8, 7, 6, 8, - 7, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 15, 15, 16, - 16, 16, 16, 15, 15, 16, 16, 16, - 16, 15, 17, 15, 17, 10, 6, 1, - 1, 1, 6, 16, 8, 7, 6, 8, - 7, 6, 8, 7, 6, 8, 7, 6, + 7, 8, 11, 16, 16, 16, 8, 11, + 16, 16, 16, 8, 11, 16, 16, 16, + 8, 11, 16, 16, 16, 8, 16, 11, + 16, 10, 6, 1, 1, 1, 6, 16, 8, 6, 6, 1, 1, 1, 6, 16 }; static const short _indic_syllable_machine_index_offsets[] = { - 0, 2, 7, 11, 13, 18, 22, 24, - 29, 33, 35, 40, 44, 46, 52, 54, - 56, 62, 64, 66, 72, 74, 76, 82, - 84, 86, 92, 103, 109, 120, 126, 137, - 143, 154, 160, 171, 173, 178, 182, 184, - 189, 193, 195, 200, 204, 206, 211, 215, - 217, 223, 225, 227, 233, 235, 237, 243, - 245, 247, 253, 255, 257, 263, 274, 280, - 291, 297, 308, 314, 325, 331, 342, 344, - 349, 353, 355, 360, 364, 366, 371, 375, - 377, 382, 386, 388, 394, 396, 398, 404, - 406, 408, 414, 416, 418, 424, 426, 428, - 434, 445, 451, 462, 468, 479, 485, 496, - 502, 504, 509, 513, 515, 520, 524, 526, - 531, 535, 537, 542, 546, 548, 554, 556, - 558, 564, 566, 568, 574, 576, 578, 584, - 586, 588, 594, 605, 611, 622, 628, 639, - 645, 656, 662, 673, 684, 689, 694, 698, - 703, 707, 709, 714, 718, 720, 725, 729, - 731, 733, 739, 741, 743, 749, 751, 753, - 759, 761, 763, 769, 771, 773, 775, 795, - 811, 827, 842, 859, 875, 891, 906, 923, - 939, 955, 970, 987, 1003, 1019, 1034, 1051, - 1067, 1083, 1098, 1105, 1112, 1119, 1121, 1123, - 1125, 1132, 1141, 1150, 1158, 1165, 1174, 1182, - 1189, 1198, 1206, 1213, 1222, 1230, 1237, 1246, - 1254, 1270, 1286, 1303, 1320, 1337, 1354, 1370, - 1386, 1403, 1420, 1437, 1454, 1470, 1486, 1503, - 1520, 1537, 1554, 1570, 1586, 1603, 1620, 1637, - 1654, 1670, 1686, 1702, 1718, 1733, 1750, 1766, - 1782, 1797, 1814, 1830, 1846, 1861, 1878, 1894, - 1910, 1925, 1942, 1958, 1974, 1989, 1996, 2003, - 2010, 2012, 2014, 2016, 2023, 2032, 2041, 2049, - 2056, 2065, 2073, 2080, 2089, 2097, 2104, 2113, - 2121, 2128, 2137, 2145, 2161, 2177, 2194, 2211, - 2228, 2245, 2261, 2277, 2294, 2311, 2328, 2345, - 2361, 2377, 2394, 2411, 2428, 2445, 2461, 2477, - 2494, 2511, 2528, 2545, 2551, 2567, 2583, 2598, - 2615, 2631, 2647, 2662, 2679, 2695, 2711, 2726, - 2743, 2759, 2775, 2790, 2807, 2823, 2839, 2854, - 2861, 2868, 2875, 2877, 2879, 2881, 2888, 2897, - 2906, 2914, 2921, 2930, 2938, 2945, 2954, 2962, - 2969, 2978, 2986, 2993, 3002, 3010, 3026, 3042, - 3059, 3076, 3093, 3110, 3126, 3142, 3159, 3176, - 3193, 3210, 3226, 3242, 3259, 3276, 3293, 3310, - 3326, 3342, 3359, 3376, 3393, 3410, 3421, 3437, - 3443, 3459, 3475, 3490, 3507, 3523, 3539, 3554, - 3571, 3587, 3603, 3618, 3635, 3651, 3667, 3682, - 3699, 3715, 3731, 3746, 3753, 3760, 3767, 3769, - 3771, 3773, 3780, 3789, 3798, 3806, 3813, 3822, - 3830, 3837, 3846, 3854, 3861, 3870, 3878, 3885, - 3894, 3902, 3918, 3934, 3951, 3968, 3985, 4002, - 4018, 4034, 4051, 4068, 4085, 4102, 4118, 4134, - 4151, 4168, 4185, 4202, 4218, 4234, 4251, 4268, - 4285, 4302, 4318, 4336, 4352, 4370, 4381, 4388, - 4390, 4392, 4394, 4401, 4418, 4427, 4435, 4442, - 4451, 4459, 4466, 4475, 4483, 4490, 4499, 4507, - 4514, 4523, 4530, 4537, 4539, 4541, 4543, 4550 + 0, 2, 8, 12, 14, 19, 23, 25, + 30, 34, 36, 41, 45, 47, 53, 55, + 57, 63, 65, 67, 73, 75, 77, 83, + 85, 87, 98, 104, 115, 121, 132, 138, + 149, 155, 166, 168, 174, 178, 180, 185, + 189, 191, 196, 200, 202, 207, 211, 213, + 219, 221, 223, 229, 231, 233, 239, 241, + 243, 249, 251, 253, 264, 270, 281, 287, + 298, 304, 315, 321, 332, 334, 340, 344, + 346, 351, 355, 357, 362, 366, 368, 373, + 377, 379, 385, 387, 389, 395, 397, 399, + 405, 407, 409, 415, 417, 419, 430, 436, + 447, 453, 464, 470, 481, 487, 489, 495, + 499, 501, 506, 510, 512, 517, 521, 523, + 528, 532, 534, 540, 542, 544, 550, 552, + 554, 560, 562, 564, 570, 572, 574, 585, + 591, 602, 608, 619, 625, 636, 642, 653, + 664, 669, 671, 691, 703, 712, 720, 737, + 749, 758, 766, 783, 795, 804, 812, 829, + 841, 850, 858, 875, 887, 896, 904, 911, + 918, 925, 927, 929, 931, 938, 947, 954, + 963, 971, 978, 987, 995, 1002, 1011, 1019, + 1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115, + 1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225, + 1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340, + 1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427, + 1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519, + 1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588, + 1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639, + 1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704, + 1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814, + 1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929, + 1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024, + 2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116, + 2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208, + 2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251, + 2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315, + 2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402, + 2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512, + 2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635, + 2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719, + 2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811, + 2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888, + 2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933, + 2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996, + 3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094, + 3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212, + 3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327, + 3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387, + 3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440 }; static const short _indic_syllable_machine_indicies[] = { - 1, 0, 2, 2, 3, 1, 0, 4, - 4, 3, 0, 3, 0, 5, 5, 6, - 1, 0, 7, 7, 6, 0, 6, 0, - 8, 8, 9, 1, 0, 10, 10, 9, - 0, 9, 0, 11, 11, 12, 1, 0, - 13, 13, 12, 0, 12, 0, 14, 0, - 0, 0, 1, 0, 15, 0, 16, 0, - 17, 11, 11, 12, 1, 0, 18, 0, - 19, 0, 20, 8, 8, 9, 1, 0, - 21, 0, 22, 0, 23, 5, 5, 6, - 1, 0, 24, 0, 25, 0, 26, 2, - 2, 3, 1, 0, 26, 2, 2, 3, - 1, 0, 0, 0, 0, 27, 0, 28, - 2, 2, 3, 1, 0, 28, 2, 2, - 3, 1, 0, 0, 0, 0, 29, 0, - 30, 2, 2, 3, 1, 0, 30, 2, - 2, 3, 1, 0, 0, 0, 0, 31, - 0, 32, 2, 2, 3, 1, 0, 32, - 2, 2, 3, 1, 0, 0, 0, 0, - 33, 0, 34, 2, 2, 3, 1, 0, - 34, 2, 2, 3, 1, 0, 0, 0, - 0, 35, 0, 37, 36, 38, 38, 39, - 37, 36, 40, 40, 39, 36, 39, 36, - 41, 41, 42, 37, 36, 43, 43, 42, - 36, 42, 36, 44, 44, 45, 37, 36, - 46, 46, 45, 36, 45, 36, 47, 47, - 48, 37, 36, 49, 49, 48, 36, 48, - 36, 50, 36, 36, 36, 37, 36, 51, - 36, 52, 36, 53, 47, 47, 48, 37, - 36, 54, 36, 55, 36, 56, 44, 44, - 45, 37, 36, 57, 36, 58, 36, 59, - 41, 41, 42, 37, 36, 60, 36, 61, - 36, 62, 38, 38, 39, 37, 36, 62, - 38, 38, 39, 37, 36, 36, 36, 36, - 63, 36, 64, 38, 38, 39, 37, 36, - 64, 38, 38, 39, 37, 36, 36, 36, - 36, 65, 36, 66, 38, 38, 39, 37, - 36, 66, 38, 38, 39, 37, 36, 36, - 36, 36, 67, 36, 68, 38, 38, 39, - 37, 36, 68, 38, 38, 39, 37, 36, - 36, 36, 36, 69, 36, 70, 38, 38, - 39, 37, 36, 70, 38, 38, 39, 37, - 36, 36, 36, 36, 71, 36, 73, 72, - 74, 74, 75, 73, 72, 77, 77, 75, - 76, 75, 76, 78, 78, 79, 73, 72, - 80, 80, 79, 72, 79, 72, 81, 81, - 82, 73, 72, 83, 83, 82, 72, 82, - 72, 84, 84, 85, 73, 72, 86, 86, - 85, 72, 85, 72, 87, 72, 72, 72, - 73, 72, 88, 72, 89, 72, 90, 84, - 84, 85, 73, 72, 91, 72, 92, 72, - 93, 81, 81, 82, 73, 72, 94, 72, - 95, 72, 96, 78, 78, 79, 73, 72, - 97, 72, 98, 72, 99, 74, 74, 75, - 73, 72, 99, 74, 74, 75, 73, 72, - 72, 72, 72, 100, 72, 101, 74, 74, - 75, 73, 72, 101, 74, 74, 75, 73, - 72, 72, 72, 72, 102, 72, 103, 74, - 74, 75, 73, 72, 103, 74, 74, 75, - 73, 72, 72, 72, 72, 104, 72, 105, - 74, 74, 75, 73, 72, 105, 74, 74, - 75, 73, 72, 72, 72, 72, 106, 72, - 107, 74, 74, 75, 73, 72, 109, 108, - 110, 110, 111, 109, 108, 112, 112, 111, - 108, 111, 108, 113, 113, 114, 109, 108, - 115, 115, 114, 108, 114, 108, 116, 116, - 117, 109, 108, 118, 118, 117, 108, 117, - 108, 119, 119, 120, 109, 108, 121, 121, - 120, 108, 120, 108, 122, 108, 108, 108, - 109, 108, 123, 108, 124, 108, 125, 119, - 119, 120, 109, 108, 126, 108, 127, 108, - 128, 116, 116, 117, 109, 108, 129, 108, - 130, 108, 131, 113, 113, 114, 109, 108, - 132, 108, 133, 108, 134, 110, 110, 111, - 109, 108, 134, 110, 110, 111, 109, 108, - 108, 108, 108, 135, 108, 136, 110, 110, - 111, 109, 108, 136, 110, 110, 111, 109, - 108, 108, 108, 108, 137, 108, 138, 110, - 110, 111, 109, 108, 138, 110, 110, 111, - 109, 108, 108, 108, 108, 139, 108, 140, - 110, 110, 111, 109, 108, 140, 110, 110, - 111, 109, 108, 108, 108, 108, 141, 108, - 142, 110, 110, 111, 109, 108, 142, 110, - 110, 111, 109, 108, 108, 108, 108, 143, - 108, 107, 74, 74, 75, 73, 72, 72, - 72, 72, 144, 72, 77, 77, 75, 1, - 0, 145, 145, 146, 1, 0, 4, 4, - 146, 0, 147, 147, 148, 149, 0, 150, - 150, 148, 0, 148, 0, 151, 151, 152, - 149, 0, 153, 153, 152, 0, 152, 0, - 154, 154, 155, 149, 0, 156, 156, 155, - 0, 155, 0, 149, 0, 157, 0, 0, - 0, 149, 0, 158, 0, 159, 0, 160, - 154, 154, 155, 149, 0, 161, 0, 162, - 0, 163, 151, 151, 152, 149, 0, 164, - 0, 165, 0, 166, 147, 147, 148, 149, - 0, 167, 0, 168, 0, 170, 169, 172, - 173, 174, 175, 176, 177, 75, 73, 171, - 178, 179, 179, 144, 171, 180, 181, 182, - 183, 184, 171, 186, 187, 188, 189, 3, - 1, 185, 190, 185, 185, 35, 185, 185, - 185, 191, 185, 192, 187, 193, 193, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 187, 193, 193, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 194, 185, 185, 185, 16, 195, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 194, 185, 196, 197, 198, 199, 3, - 1, 185, 190, 185, 185, 33, 185, 185, - 185, 191, 185, 200, 197, 201, 201, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 197, 201, 201, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 202, 185, 185, 185, 16, 203, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 202, 185, 204, 205, 206, 207, 3, - 1, 185, 190, 185, 185, 31, 185, 185, - 185, 191, 185, 208, 205, 209, 209, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 205, 209, 209, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 210, 185, 185, 185, 16, 211, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 210, 185, 212, 213, 214, 215, 3, - 1, 185, 190, 185, 185, 29, 185, 185, - 185, 191, 185, 216, 213, 217, 217, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 213, 217, 217, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 218, 185, 185, 185, 16, 219, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 218, 185, 220, 221, 222, 223, 3, - 1, 185, 190, 185, 185, 27, 185, 185, - 185, 191, 185, 224, 221, 225, 225, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 221, 225, 225, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 16, 226, 185, 1, 185, 190, - 185, 227, 227, 185, 1, 185, 190, 185, - 228, 185, 185, 229, 185, 190, 185, 190, - 185, 230, 185, 231, 185, 228, 185, 185, - 185, 185, 190, 185, 16, 185, 232, 232, - 3, 1, 185, 190, 185, 233, 25, 234, - 235, 6, 1, 185, 190, 185, 25, 234, - 235, 6, 1, 185, 190, 185, 234, 234, - 6, 1, 185, 190, 185, 236, 22, 237, - 238, 9, 1, 185, 190, 185, 22, 237, - 238, 9, 1, 185, 190, 185, 237, 237, - 9, 1, 185, 190, 185, 239, 19, 240, - 241, 12, 1, 185, 190, 185, 19, 240, - 241, 12, 1, 185, 190, 185, 240, 240, - 12, 1, 185, 190, 185, 242, 16, 227, - 243, 185, 1, 185, 190, 185, 16, 227, - 243, 185, 1, 185, 190, 185, 227, 244, - 185, 1, 185, 190, 185, 16, 185, 227, - 227, 185, 1, 185, 190, 185, 221, 225, - 225, 3, 1, 185, 190, 185, 220, 221, - 225, 225, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 220, 221, - 222, 225, 3, 1, 185, 190, 185, 185, - 27, 185, 185, 185, 191, 185, 218, 185, - 245, 185, 232, 232, 3, 1, 185, 190, - 185, 185, 185, 185, 185, 218, 185, 218, - 185, 185, 185, 227, 227, 185, 1, 185, - 190, 185, 185, 185, 185, 185, 218, 185, - 218, 185, 185, 185, 227, 246, 185, 1, - 185, 190, 185, 185, 185, 185, 185, 218, - 185, 218, 185, 245, 185, 227, 227, 185, - 1, 185, 190, 185, 185, 185, 185, 185, - 218, 185, 212, 213, 217, 217, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 212, 213, 214, 217, 3, 1, - 185, 190, 185, 185, 29, 185, 185, 185, - 191, 185, 210, 185, 247, 185, 232, 232, - 3, 1, 185, 190, 185, 185, 185, 185, - 185, 210, 185, 210, 185, 185, 185, 227, - 227, 185, 1, 185, 190, 185, 185, 185, - 185, 185, 210, 185, 210, 185, 185, 185, - 227, 248, 185, 1, 185, 190, 185, 185, - 185, 185, 185, 210, 185, 210, 185, 247, - 185, 227, 227, 185, 1, 185, 190, 185, - 185, 185, 185, 185, 210, 185, 204, 205, - 209, 209, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 204, 205, - 206, 209, 3, 1, 185, 190, 185, 185, - 31, 185, 185, 185, 191, 185, 202, 185, - 249, 185, 232, 232, 3, 1, 185, 190, - 185, 185, 185, 185, 185, 202, 185, 202, - 185, 185, 185, 227, 227, 185, 1, 185, - 190, 185, 185, 185, 185, 185, 202, 185, - 202, 185, 185, 185, 227, 250, 185, 1, - 185, 190, 185, 185, 185, 185, 185, 202, - 185, 202, 185, 249, 185, 227, 227, 185, - 1, 185, 190, 185, 185, 185, 185, 185, - 202, 185, 196, 197, 201, 201, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 196, 197, 198, 201, 3, 1, - 185, 190, 185, 185, 33, 185, 185, 185, - 191, 185, 194, 185, 251, 185, 232, 232, - 3, 1, 185, 190, 185, 185, 185, 185, - 185, 194, 185, 194, 185, 185, 185, 227, - 227, 185, 1, 185, 190, 185, 185, 185, - 185, 185, 194, 185, 194, 185, 185, 185, - 227, 252, 185, 1, 185, 190, 185, 185, - 185, 185, 185, 194, 185, 194, 185, 251, - 185, 227, 227, 185, 1, 185, 190, 185, - 185, 185, 185, 185, 194, 185, 186, 187, - 193, 193, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 186, 187, - 188, 193, 3, 1, 185, 190, 185, 185, - 35, 185, 185, 185, 191, 185, 254, 255, - 256, 257, 39, 37, 253, 258, 253, 253, - 71, 253, 253, 253, 259, 253, 260, 255, - 261, 257, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 255, 261, - 257, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 262, 253, 253, - 253, 52, 263, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 262, 253, 264, 265, - 266, 267, 39, 37, 253, 258, 253, 253, - 69, 253, 253, 253, 259, 253, 268, 265, - 269, 269, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 265, 269, - 269, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 270, 253, 253, - 253, 52, 271, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 270, 253, 272, 273, - 274, 275, 39, 37, 253, 258, 253, 253, - 67, 253, 253, 253, 259, 253, 276, 273, - 277, 277, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 273, 277, - 277, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 278, 253, 253, - 253, 52, 279, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 278, 253, 280, 281, - 282, 283, 39, 37, 253, 258, 253, 253, - 65, 253, 253, 253, 259, 253, 284, 281, - 285, 285, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 281, 285, - 285, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 286, 253, 253, - 253, 52, 287, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 286, 253, 288, 289, - 290, 291, 39, 37, 253, 258, 253, 253, - 63, 253, 253, 253, 259, 253, 292, 289, - 293, 293, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 289, 293, - 293, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 52, 294, 253, - 37, 253, 258, 253, 295, 295, 253, 37, - 253, 258, 253, 296, 253, 253, 297, 253, - 258, 253, 258, 253, 298, 253, 299, 253, - 296, 253, 253, 253, 253, 258, 253, 52, - 253, 300, 300, 39, 37, 253, 258, 253, - 301, 61, 302, 303, 42, 37, 253, 258, - 253, 61, 302, 303, 42, 37, 253, 258, - 253, 302, 302, 42, 37, 253, 258, 253, - 304, 58, 305, 306, 45, 37, 253, 258, - 253, 58, 305, 306, 45, 37, 253, 258, - 253, 305, 305, 45, 37, 253, 258, 253, - 307, 55, 308, 309, 48, 37, 253, 258, - 253, 55, 308, 309, 48, 37, 253, 258, - 253, 308, 308, 48, 37, 253, 258, 253, - 310, 52, 295, 311, 253, 37, 253, 258, - 253, 52, 295, 311, 253, 37, 253, 258, - 253, 295, 312, 253, 37, 253, 258, 253, - 52, 253, 295, 295, 253, 37, 253, 258, - 253, 289, 293, 293, 39, 37, 253, 258, - 253, 288, 289, 293, 293, 39, 37, 253, - 258, 253, 253, 253, 253, 253, 253, 259, - 253, 288, 289, 290, 293, 39, 37, 253, - 258, 253, 253, 63, 253, 253, 253, 259, - 253, 286, 253, 313, 253, 300, 300, 39, - 37, 253, 258, 253, 253, 253, 253, 253, - 286, 253, 286, 253, 253, 253, 295, 295, - 253, 37, 253, 258, 253, 253, 253, 253, - 253, 286, 253, 286, 253, 253, 253, 295, - 314, 253, 37, 253, 258, 253, 253, 253, - 253, 253, 286, 253, 286, 253, 313, 253, - 295, 295, 253, 37, 253, 258, 253, 253, - 253, 253, 253, 286, 253, 280, 281, 285, - 285, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 280, 281, 282, - 285, 39, 37, 253, 258, 253, 253, 65, - 253, 253, 253, 259, 253, 278, 253, 315, - 253, 300, 300, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 278, 253, 278, 253, - 253, 253, 295, 295, 253, 37, 253, 258, - 253, 253, 253, 253, 253, 278, 253, 278, - 253, 253, 253, 295, 316, 253, 37, 253, - 258, 253, 253, 253, 253, 253, 278, 253, - 278, 253, 315, 253, 295, 295, 253, 37, - 253, 258, 253, 253, 253, 253, 253, 278, - 253, 272, 273, 277, 277, 39, 37, 253, - 258, 253, 253, 253, 253, 253, 253, 259, - 253, 272, 273, 274, 277, 39, 37, 253, - 258, 253, 253, 67, 253, 253, 253, 259, - 253, 270, 253, 317, 253, 300, 300, 39, - 37, 253, 258, 253, 253, 253, 253, 253, - 270, 253, 270, 253, 253, 253, 295, 295, - 253, 37, 253, 258, 253, 253, 253, 253, - 253, 270, 253, 270, 253, 253, 253, 295, - 318, 253, 37, 253, 258, 253, 253, 253, - 253, 253, 270, 253, 270, 253, 317, 253, - 295, 295, 253, 37, 253, 258, 253, 253, - 253, 253, 253, 270, 253, 264, 265, 269, - 269, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 264, 265, 266, - 269, 39, 37, 253, 258, 253, 253, 69, - 253, 253, 253, 259, 253, 262, 253, 319, - 253, 300, 300, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 262, 253, 262, 253, - 253, 253, 295, 295, 253, 37, 253, 258, - 253, 253, 253, 253, 253, 262, 253, 262, - 253, 253, 253, 295, 320, 253, 37, 253, - 258, 253, 253, 253, 253, 253, 262, 253, - 262, 253, 319, 253, 295, 295, 253, 37, - 253, 258, 253, 253, 253, 253, 253, 262, - 253, 70, 38, 38, 39, 37, 253, 254, - 255, 261, 257, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 253, 259, 253, 322, - 175, 323, 323, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 175, - 323, 323, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 324, 321, - 321, 321, 89, 325, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 324, 321, 326, - 327, 328, 329, 75, 73, 321, 178, 321, - 321, 106, 321, 321, 321, 182, 321, 330, - 327, 331, 331, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 327, - 331, 331, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 332, 321, - 321, 321, 89, 333, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 332, 321, 334, - 335, 336, 337, 75, 73, 321, 178, 321, - 321, 104, 321, 321, 321, 182, 321, 338, - 335, 339, 339, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 335, - 339, 339, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 340, 321, - 321, 321, 89, 341, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 340, 321, 342, - 343, 344, 345, 75, 73, 321, 178, 321, - 321, 102, 321, 321, 321, 182, 321, 346, - 343, 347, 347, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 343, - 347, 347, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 348, 321, - 321, 321, 89, 349, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 348, 321, 350, - 351, 352, 353, 75, 73, 321, 178, 321, - 321, 100, 321, 321, 321, 182, 321, 354, - 351, 355, 355, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 351, - 355, 355, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 89, 356, - 321, 73, 321, 178, 321, 357, 357, 321, - 73, 321, 178, 321, 358, 321, 321, 359, - 321, 178, 321, 178, 321, 360, 321, 361, - 321, 358, 321, 321, 321, 321, 178, 321, - 89, 321, 362, 362, 75, 73, 321, 178, - 321, 363, 98, 364, 365, 79, 73, 321, - 178, 321, 98, 364, 365, 79, 73, 321, - 178, 321, 364, 364, 79, 73, 321, 178, - 321, 366, 95, 367, 368, 82, 73, 321, - 178, 321, 95, 367, 368, 82, 73, 321, - 178, 321, 367, 367, 82, 73, 321, 178, - 321, 369, 92, 370, 371, 85, 73, 321, - 178, 321, 92, 370, 371, 85, 73, 321, - 178, 321, 370, 370, 85, 73, 321, 178, - 321, 372, 89, 357, 373, 321, 73, 321, - 178, 321, 89, 357, 373, 321, 73, 321, - 178, 321, 357, 374, 321, 73, 321, 178, - 321, 89, 321, 357, 357, 321, 73, 321, - 178, 321, 351, 355, 355, 75, 73, 321, - 178, 321, 350, 351, 355, 355, 75, 73, - 321, 178, 321, 321, 321, 321, 321, 321, - 182, 321, 350, 351, 352, 355, 75, 73, - 321, 178, 321, 321, 100, 321, 321, 321, - 182, 321, 348, 321, 375, 321, 362, 362, - 75, 73, 321, 178, 321, 321, 321, 321, - 321, 348, 321, 348, 321, 321, 321, 357, - 357, 321, 73, 321, 178, 321, 321, 321, - 321, 321, 348, 321, 348, 321, 321, 321, - 357, 376, 321, 73, 321, 178, 321, 321, - 321, 321, 321, 348, 321, 348, 321, 375, - 321, 357, 357, 321, 73, 321, 178, 321, - 321, 321, 321, 321, 348, 321, 342, 343, - 347, 347, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 342, 343, - 344, 347, 75, 73, 321, 178, 321, 321, - 102, 321, 321, 321, 182, 321, 340, 321, - 377, 321, 362, 362, 75, 73, 321, 178, - 321, 321, 321, 321, 321, 340, 321, 340, - 321, 321, 321, 357, 357, 321, 73, 321, - 178, 321, 321, 321, 321, 321, 340, 321, - 340, 321, 321, 321, 357, 378, 321, 73, - 321, 178, 321, 321, 321, 321, 321, 340, - 321, 340, 321, 377, 321, 357, 357, 321, - 73, 321, 178, 321, 321, 321, 321, 321, - 340, 321, 334, 335, 339, 339, 75, 73, - 321, 178, 321, 321, 321, 321, 321, 321, - 182, 321, 334, 335, 336, 339, 75, 73, - 321, 178, 321, 321, 104, 321, 321, 321, - 182, 321, 332, 321, 379, 321, 362, 362, - 75, 73, 321, 178, 321, 321, 321, 321, - 321, 332, 321, 332, 321, 321, 321, 357, - 357, 321, 73, 321, 178, 321, 321, 321, - 321, 321, 332, 321, 332, 321, 321, 321, - 357, 380, 321, 73, 321, 178, 321, 321, - 321, 321, 321, 332, 321, 332, 321, 379, - 321, 357, 357, 321, 73, 321, 178, 321, - 321, 321, 321, 321, 332, 321, 326, 327, - 331, 331, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 326, 327, - 328, 331, 75, 73, 321, 178, 321, 321, - 106, 321, 321, 321, 182, 321, 324, 321, - 381, 321, 362, 362, 75, 73, 321, 178, - 321, 321, 321, 321, 321, 324, 321, 324, - 321, 321, 321, 357, 357, 321, 73, 321, - 178, 321, 321, 321, 321, 321, 324, 321, - 324, 321, 321, 321, 357, 382, 321, 73, - 321, 178, 321, 321, 321, 321, 321, 324, - 321, 324, 321, 381, 321, 357, 357, 321, - 73, 321, 178, 321, 321, 321, 321, 321, - 324, 321, 107, 74, 74, 75, 73, 383, - 383, 383, 383, 144, 383, 174, 175, 323, - 323, 75, 73, 321, 178, 321, 321, 321, - 321, 321, 321, 182, 321, 107, 74, 74, - 75, 73, 383, 385, 386, 387, 388, 111, - 109, 384, 389, 384, 384, 143, 384, 384, - 384, 390, 384, 391, 386, 388, 388, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 386, 388, 388, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 392, 384, 384, 384, 124, 393, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 392, 384, 394, 395, 396, 397, 111, - 109, 384, 389, 384, 384, 141, 384, 384, - 384, 390, 384, 398, 395, 399, 399, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 395, 399, 399, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 400, 384, 384, 384, 124, 401, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 400, 384, 402, 403, 404, 405, 111, - 109, 384, 389, 384, 384, 139, 384, 384, - 384, 390, 384, 406, 403, 407, 407, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 403, 407, 407, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 408, 384, 384, 384, 124, 409, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 408, 384, 410, 411, 412, 413, 111, - 109, 384, 389, 384, 384, 137, 384, 384, - 384, 390, 384, 414, 411, 415, 415, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 411, 415, 415, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 416, 384, 384, 384, 124, 417, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 416, 384, 418, 419, 420, 421, 111, - 109, 384, 389, 384, 384, 135, 384, 384, - 384, 390, 384, 422, 419, 423, 423, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 419, 423, 423, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 124, 424, 384, 109, 384, 389, - 384, 425, 425, 384, 109, 384, 389, 384, - 426, 384, 384, 427, 384, 389, 384, 389, - 384, 428, 384, 429, 384, 426, 384, 384, - 384, 384, 389, 384, 124, 384, 430, 430, - 111, 109, 384, 389, 384, 431, 133, 432, - 433, 114, 109, 384, 389, 384, 133, 432, - 433, 114, 109, 384, 389, 384, 432, 432, - 114, 109, 384, 389, 384, 434, 130, 435, - 436, 117, 109, 384, 389, 384, 130, 435, - 436, 117, 109, 384, 389, 384, 435, 435, - 117, 109, 384, 389, 384, 437, 127, 438, - 439, 120, 109, 384, 389, 384, 127, 438, - 439, 120, 109, 384, 389, 384, 438, 438, - 120, 109, 384, 389, 384, 440, 124, 425, - 441, 384, 109, 384, 389, 384, 124, 425, - 441, 384, 109, 384, 389, 384, 425, 442, - 384, 109, 384, 389, 384, 124, 384, 425, - 425, 384, 109, 384, 389, 384, 419, 423, - 423, 111, 109, 384, 389, 384, 418, 419, - 423, 423, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 418, 419, - 420, 423, 111, 109, 384, 389, 384, 384, - 135, 384, 384, 384, 390, 384, 416, 384, - 443, 384, 430, 430, 111, 109, 384, 389, - 384, 384, 384, 384, 384, 416, 384, 416, - 384, 384, 384, 425, 425, 384, 109, 384, - 389, 384, 384, 384, 384, 384, 416, 384, - 416, 384, 384, 384, 425, 444, 384, 109, - 384, 389, 384, 384, 384, 384, 384, 416, - 384, 416, 384, 443, 384, 425, 425, 384, - 109, 384, 389, 384, 384, 384, 384, 384, - 416, 384, 410, 411, 415, 415, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 410, 411, 412, 415, 111, 109, - 384, 389, 384, 384, 137, 384, 384, 384, - 390, 384, 408, 384, 445, 384, 430, 430, - 111, 109, 384, 389, 384, 384, 384, 384, - 384, 408, 384, 408, 384, 384, 384, 425, - 425, 384, 109, 384, 389, 384, 384, 384, - 384, 384, 408, 384, 408, 384, 384, 384, - 425, 446, 384, 109, 384, 389, 384, 384, - 384, 384, 384, 408, 384, 408, 384, 445, - 384, 425, 425, 384, 109, 384, 389, 384, - 384, 384, 384, 384, 408, 384, 402, 403, - 407, 407, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 402, 403, - 404, 407, 111, 109, 384, 389, 384, 384, - 139, 384, 384, 384, 390, 384, 400, 384, - 447, 384, 430, 430, 111, 109, 384, 389, - 384, 384, 384, 384, 384, 400, 384, 400, - 384, 384, 384, 425, 425, 384, 109, 384, - 389, 384, 384, 384, 384, 384, 400, 384, - 400, 384, 384, 384, 425, 448, 384, 109, - 384, 389, 384, 384, 384, 384, 384, 400, - 384, 400, 384, 447, 384, 425, 425, 384, - 109, 384, 389, 384, 384, 384, 384, 384, - 400, 384, 394, 395, 399, 399, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 394, 395, 396, 399, 111, 109, - 384, 389, 384, 384, 141, 384, 384, 384, - 390, 384, 392, 384, 449, 384, 430, 430, - 111, 109, 384, 389, 384, 384, 384, 384, - 384, 392, 384, 392, 384, 384, 384, 425, - 425, 384, 109, 384, 389, 384, 384, 384, - 384, 384, 392, 384, 392, 384, 384, 384, - 425, 450, 384, 109, 384, 389, 384, 384, - 384, 384, 384, 392, 384, 392, 384, 449, - 384, 425, 425, 384, 109, 384, 389, 384, - 384, 384, 384, 384, 392, 384, 385, 386, - 388, 388, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 172, 173, - 174, 175, 451, 323, 75, 73, 321, 178, - 179, 179, 144, 321, 321, 172, 182, 321, - 186, 452, 188, 189, 3, 1, 185, 190, - 185, 185, 35, 185, 185, 185, 191, 185, - 194, 173, 174, 175, 453, 454, 75, 149, - 185, 455, 185, 179, 144, 185, 185, 194, - 182, 185, 107, 456, 456, 75, 149, 185, - 190, 185, 185, 144, 185, 457, 185, 185, - 458, 185, 455, 185, 455, 185, 459, 185, - 231, 185, 457, 185, 185, 185, 185, 455, - 185, 194, 185, 251, 107, 460, 460, 146, - 149, 185, 190, 185, 185, 185, 185, 185, - 194, 185, 461, 168, 462, 463, 148, 149, - 185, 455, 185, 168, 462, 463, 148, 149, - 185, 455, 185, 462, 462, 148, 149, 185, - 455, 185, 464, 165, 465, 466, 152, 149, - 185, 455, 185, 165, 465, 466, 152, 149, - 185, 455, 185, 465, 465, 152, 149, 185, - 455, 185, 467, 162, 468, 469, 155, 149, - 185, 455, 185, 162, 468, 469, 155, 149, - 185, 455, 185, 468, 468, 155, 149, 185, - 455, 185, 470, 159, 471, 472, 185, 149, - 185, 455, 185, 159, 471, 472, 185, 149, - 185, 455, 185, 471, 471, 185, 149, 185, - 455, 185, 474, 473, 475, 475, 473, 170, - 473, 476, 473, 475, 475, 473, 170, 473, - 476, 473, 477, 473, 473, 478, 473, 476, - 473, 476, 473, 479, 473, 480, 473, 477, - 473, 473, 473, 473, 476, 473, 172, 383, - 383, 383, 383, 383, 383, 383, 383, 383, - 179, 383, 383, 383, 383, 172, 383, 0 + 1, 0, 2, 3, 3, 4, 1, 0, + 5, 5, 4, 0, 4, 0, 6, 6, + 7, 1, 0, 8, 8, 7, 0, 7, + 0, 9, 9, 10, 1, 0, 11, 11, + 10, 0, 10, 0, 12, 12, 13, 1, + 0, 14, 14, 13, 0, 13, 0, 15, + 0, 0, 0, 1, 0, 16, 0, 17, + 0, 18, 12, 12, 13, 1, 0, 19, + 0, 20, 0, 21, 9, 9, 10, 1, + 0, 22, 0, 23, 0, 24, 6, 6, + 7, 1, 0, 25, 0, 26, 0, 2, + 3, 3, 4, 1, 0, 0, 0, 0, + 27, 0, 28, 3, 3, 4, 1, 0, + 28, 3, 3, 4, 1, 0, 0, 0, + 0, 29, 0, 30, 3, 3, 4, 1, + 0, 30, 3, 3, 4, 1, 0, 0, + 0, 0, 31, 0, 32, 3, 3, 4, + 1, 0, 32, 3, 3, 4, 1, 0, + 0, 0, 0, 33, 0, 34, 3, 3, + 4, 1, 0, 34, 3, 3, 4, 1, + 0, 0, 0, 0, 35, 0, 37, 36, + 38, 39, 39, 40, 37, 36, 41, 41, + 40, 36, 40, 36, 42, 42, 43, 37, + 36, 44, 44, 43, 36, 43, 36, 45, + 45, 46, 37, 36, 47, 47, 46, 36, + 46, 36, 48, 48, 49, 37, 36, 50, + 50, 49, 36, 49, 36, 51, 36, 36, + 36, 37, 36, 52, 36, 53, 36, 54, + 48, 48, 49, 37, 36, 55, 36, 56, + 36, 57, 45, 45, 46, 37, 36, 58, + 36, 59, 36, 60, 42, 42, 43, 37, + 36, 61, 36, 62, 36, 38, 39, 39, + 40, 37, 36, 36, 36, 36, 63, 36, + 64, 39, 39, 40, 37, 36, 64, 39, + 39, 40, 37, 36, 36, 36, 36, 65, + 36, 66, 39, 39, 40, 37, 36, 66, + 39, 39, 40, 37, 36, 36, 36, 36, + 67, 36, 68, 39, 39, 40, 37, 36, + 68, 39, 39, 40, 37, 36, 36, 36, + 36, 69, 36, 70, 39, 39, 40, 37, + 36, 70, 39, 39, 40, 37, 36, 36, + 36, 36, 71, 36, 73, 72, 74, 75, + 75, 76, 73, 72, 78, 78, 76, 77, + 76, 77, 79, 79, 80, 73, 72, 81, + 81, 80, 72, 80, 72, 82, 82, 83, + 73, 72, 84, 84, 83, 72, 83, 72, + 85, 85, 86, 73, 72, 87, 87, 86, + 72, 86, 72, 88, 72, 72, 72, 73, + 72, 89, 72, 90, 72, 91, 85, 85, + 86, 73, 72, 92, 72, 93, 72, 94, + 82, 82, 83, 73, 72, 95, 72, 96, + 72, 97, 79, 79, 80, 73, 72, 98, + 72, 99, 72, 74, 75, 75, 76, 73, + 72, 72, 72, 72, 100, 72, 101, 75, + 75, 76, 73, 72, 101, 75, 75, 76, + 73, 72, 72, 72, 72, 102, 72, 103, + 75, 75, 76, 73, 72, 103, 75, 75, + 76, 73, 72, 72, 72, 72, 104, 72, + 105, 75, 75, 76, 73, 72, 105, 75, + 75, 76, 73, 72, 72, 72, 72, 106, + 72, 107, 75, 75, 76, 73, 72, 109, + 108, 110, 111, 111, 112, 109, 108, 113, + 113, 112, 108, 112, 108, 114, 114, 115, + 109, 108, 116, 116, 115, 108, 115, 108, + 117, 117, 118, 109, 108, 119, 119, 118, + 108, 118, 108, 120, 120, 121, 109, 108, + 122, 122, 121, 108, 121, 108, 123, 108, + 108, 108, 109, 108, 124, 108, 125, 108, + 126, 120, 120, 121, 109, 108, 127, 108, + 128, 108, 129, 117, 117, 118, 109, 108, + 130, 108, 131, 108, 132, 114, 114, 115, + 109, 108, 133, 108, 134, 108, 110, 111, + 111, 112, 109, 108, 108, 108, 108, 135, + 108, 136, 111, 111, 112, 109, 108, 136, + 111, 111, 112, 109, 108, 108, 108, 108, + 137, 108, 138, 111, 111, 112, 109, 108, + 138, 111, 111, 112, 109, 108, 108, 108, + 108, 139, 108, 140, 111, 111, 112, 109, + 108, 140, 111, 111, 112, 109, 108, 108, + 108, 108, 141, 108, 142, 111, 111, 112, + 109, 108, 142, 111, 111, 112, 109, 108, + 108, 108, 108, 143, 108, 107, 75, 75, + 76, 73, 72, 72, 72, 72, 144, 72, + 78, 78, 76, 1, 0, 146, 145, 148, + 149, 150, 151, 152, 153, 76, 73, 147, + 154, 155, 155, 144, 147, 156, 157, 147, + 158, 159, 147, 161, 162, 163, 164, 4, + 1, 160, 165, 160, 160, 35, 160, 166, + 162, 167, 167, 4, 1, 160, 165, 160, + 162, 167, 167, 4, 1, 160, 165, 160, + 168, 160, 160, 160, 17, 169, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 168, + 160, 170, 171, 172, 173, 4, 1, 160, + 165, 160, 160, 33, 160, 174, 171, 175, + 175, 4, 1, 160, 165, 160, 171, 175, + 175, 4, 1, 160, 165, 160, 176, 160, + 160, 160, 17, 177, 160, 1, 160, 165, + 160, 160, 160, 160, 160, 176, 160, 178, + 179, 180, 181, 4, 1, 160, 165, 160, + 160, 31, 160, 182, 179, 183, 183, 4, + 1, 160, 165, 160, 179, 183, 183, 4, + 1, 160, 165, 160, 184, 160, 160, 160, + 17, 185, 160, 1, 160, 165, 160, 160, + 160, 160, 160, 184, 160, 186, 187, 188, + 189, 4, 1, 160, 165, 160, 160, 29, + 160, 190, 187, 191, 191, 4, 1, 160, + 165, 160, 187, 191, 191, 4, 1, 160, + 165, 160, 192, 160, 160, 160, 17, 193, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 192, 160, 194, 195, 196, 197, 4, + 1, 160, 165, 160, 160, 27, 160, 198, + 195, 199, 199, 4, 1, 160, 165, 160, + 195, 199, 199, 4, 1, 160, 165, 160, + 17, 200, 160, 1, 160, 165, 160, 201, + 201, 160, 1, 160, 165, 160, 202, 160, + 160, 203, 160, 165, 160, 165, 160, 204, + 160, 205, 160, 202, 160, 160, 160, 160, + 165, 160, 17, 160, 201, 201, 160, 1, + 160, 165, 160, 201, 200, 160, 1, 160, + 165, 160, 206, 26, 207, 208, 7, 1, + 160, 165, 160, 26, 207, 208, 7, 1, + 160, 165, 160, 207, 207, 7, 1, 160, + 165, 160, 209, 23, 210, 211, 10, 1, + 160, 165, 160, 23, 210, 211, 10, 1, + 160, 165, 160, 210, 210, 10, 1, 160, + 165, 160, 212, 20, 213, 214, 13, 1, + 160, 165, 160, 20, 213, 214, 13, 1, + 160, 165, 160, 213, 213, 13, 1, 160, + 165, 160, 215, 17, 201, 216, 160, 1, + 160, 165, 160, 17, 201, 216, 160, 1, + 160, 165, 160, 194, 195, 199, 199, 4, + 1, 160, 165, 160, 194, 195, 196, 199, + 4, 1, 160, 165, 160, 160, 27, 160, + 192, 160, 217, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 192, + 160, 192, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 192, 160, 192, 160, 160, 160, 201, 193, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 192, 160, 186, 187, 191, 191, 4, + 1, 160, 165, 160, 186, 187, 188, 191, + 4, 1, 160, 165, 160, 160, 29, 160, + 184, 160, 218, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 184, + 160, 184, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 184, 160, 184, 160, 160, 160, 201, 185, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 184, 160, 178, 179, 183, 183, 4, + 1, 160, 165, 160, 178, 179, 180, 183, + 4, 1, 160, 165, 160, 160, 31, 160, + 176, 160, 219, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 176, + 160, 176, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 176, 160, 176, 160, 160, 160, 201, 177, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 176, 160, 170, 171, 175, 175, 4, + 1, 160, 165, 160, 170, 171, 172, 175, + 4, 1, 160, 165, 160, 160, 33, 160, + 168, 160, 220, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 168, + 160, 168, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 168, 160, 168, 160, 160, 160, 201, 169, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 168, 160, 161, 162, 167, 167, 4, + 1, 160, 165, 160, 161, 162, 163, 167, + 4, 1, 160, 165, 160, 160, 35, 160, + 222, 223, 224, 225, 40, 37, 221, 226, + 221, 221, 71, 221, 227, 223, 228, 225, + 40, 37, 221, 226, 221, 223, 228, 225, + 40, 37, 221, 226, 221, 229, 221, 221, + 221, 53, 230, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 229, 221, 231, 232, + 233, 234, 40, 37, 221, 226, 221, 221, + 69, 221, 235, 232, 236, 236, 40, 37, + 221, 226, 221, 232, 236, 236, 40, 37, + 221, 226, 221, 237, 221, 221, 221, 53, + 238, 221, 37, 221, 226, 221, 221, 221, + 221, 221, 237, 221, 239, 240, 241, 242, + 40, 37, 221, 226, 221, 221, 67, 221, + 243, 240, 244, 244, 40, 37, 221, 226, + 221, 240, 244, 244, 40, 37, 221, 226, + 221, 245, 221, 221, 221, 53, 246, 221, + 37, 221, 226, 221, 221, 221, 221, 221, + 245, 221, 247, 248, 249, 250, 40, 37, + 221, 226, 221, 221, 65, 221, 251, 248, + 252, 252, 40, 37, 221, 226, 221, 248, + 252, 252, 40, 37, 221, 226, 221, 253, + 221, 221, 221, 53, 254, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 253, 221, + 255, 256, 257, 258, 40, 37, 221, 226, + 221, 221, 63, 221, 259, 256, 260, 260, + 40, 37, 221, 226, 221, 256, 260, 260, + 40, 37, 221, 226, 221, 53, 261, 221, + 37, 221, 226, 221, 262, 262, 221, 37, + 221, 226, 221, 263, 221, 221, 264, 221, + 226, 221, 226, 221, 265, 221, 266, 221, + 263, 221, 221, 221, 221, 226, 221, 53, + 221, 262, 262, 221, 37, 221, 226, 221, + 262, 261, 221, 37, 221, 226, 221, 267, + 62, 268, 269, 43, 37, 221, 226, 221, + 62, 268, 269, 43, 37, 221, 226, 221, + 268, 268, 43, 37, 221, 226, 221, 270, + 59, 271, 272, 46, 37, 221, 226, 221, + 59, 271, 272, 46, 37, 221, 226, 221, + 271, 271, 46, 37, 221, 226, 221, 273, + 56, 274, 275, 49, 37, 221, 226, 221, + 56, 274, 275, 49, 37, 221, 226, 221, + 274, 274, 49, 37, 221, 226, 221, 276, + 53, 262, 277, 221, 37, 221, 226, 221, + 53, 262, 277, 221, 37, 221, 226, 221, + 255, 256, 260, 260, 40, 37, 221, 226, + 221, 255, 256, 257, 260, 40, 37, 221, + 226, 221, 221, 63, 221, 253, 221, 278, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 253, 221, 253, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 253, 221, 253, + 221, 221, 221, 262, 254, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 253, 221, + 247, 248, 252, 252, 40, 37, 221, 226, + 221, 247, 248, 249, 252, 40, 37, 221, + 226, 221, 221, 65, 221, 245, 221, 279, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 245, 221, 245, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 245, 221, 245, + 221, 221, 221, 262, 246, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 245, 221, + 239, 240, 244, 244, 40, 37, 221, 226, + 221, 239, 240, 241, 244, 40, 37, 221, + 226, 221, 221, 67, 221, 237, 221, 280, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 237, 221, 237, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 237, 221, 237, + 221, 221, 221, 262, 238, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 237, 221, + 231, 232, 236, 236, 40, 37, 221, 226, + 221, 231, 232, 233, 236, 40, 37, 221, + 226, 221, 221, 69, 221, 229, 221, 281, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 229, 221, 229, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 229, 221, 229, + 221, 221, 221, 262, 230, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 229, 221, + 70, 39, 39, 40, 37, 221, 222, 223, + 228, 225, 40, 37, 221, 226, 221, 283, + 151, 284, 284, 76, 73, 282, 154, 282, + 151, 284, 284, 76, 73, 282, 154, 282, + 285, 282, 282, 282, 90, 286, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 285, + 282, 287, 288, 289, 290, 76, 73, 282, + 154, 282, 282, 106, 282, 291, 288, 292, + 292, 76, 73, 282, 154, 282, 288, 292, + 292, 76, 73, 282, 154, 282, 293, 282, + 282, 282, 90, 294, 282, 73, 282, 154, + 282, 282, 282, 282, 282, 293, 282, 295, + 296, 297, 298, 76, 73, 282, 154, 282, + 282, 104, 282, 299, 296, 300, 300, 76, + 73, 282, 154, 282, 296, 300, 300, 76, + 73, 282, 154, 282, 301, 282, 282, 282, + 90, 302, 282, 73, 282, 154, 282, 282, + 282, 282, 282, 301, 282, 303, 304, 305, + 306, 76, 73, 282, 154, 282, 282, 102, + 282, 307, 304, 308, 308, 76, 73, 282, + 154, 282, 304, 308, 308, 76, 73, 282, + 154, 282, 309, 282, 282, 282, 90, 310, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 309, 282, 311, 312, 313, 314, 76, + 73, 282, 154, 282, 282, 100, 282, 315, + 312, 316, 316, 76, 73, 282, 154, 282, + 312, 316, 316, 76, 73, 282, 154, 282, + 90, 317, 282, 73, 282, 154, 282, 318, + 318, 282, 73, 282, 154, 282, 319, 282, + 282, 320, 282, 154, 282, 154, 282, 321, + 282, 322, 282, 319, 282, 282, 282, 282, + 154, 282, 90, 282, 318, 318, 282, 73, + 282, 154, 282, 318, 317, 282, 73, 282, + 154, 282, 323, 99, 324, 325, 80, 73, + 282, 154, 282, 99, 324, 325, 80, 73, + 282, 154, 282, 324, 324, 80, 73, 282, + 154, 282, 326, 96, 327, 328, 83, 73, + 282, 154, 282, 96, 327, 328, 83, 73, + 282, 154, 282, 327, 327, 83, 73, 282, + 154, 282, 329, 93, 330, 331, 86, 73, + 282, 154, 282, 93, 330, 331, 86, 73, + 282, 154, 282, 330, 330, 86, 73, 282, + 154, 282, 332, 90, 318, 333, 282, 73, + 282, 154, 282, 90, 318, 333, 282, 73, + 282, 154, 282, 311, 312, 316, 316, 76, + 73, 282, 154, 282, 311, 312, 313, 316, + 76, 73, 282, 154, 282, 282, 100, 282, + 309, 282, 334, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 309, + 282, 309, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 309, 282, 309, 282, 282, 282, 318, 310, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 309, 282, 303, 304, 308, 308, 76, + 73, 282, 154, 282, 303, 304, 305, 308, + 76, 73, 282, 154, 282, 282, 102, 282, + 301, 282, 335, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 301, + 282, 301, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 301, 282, 301, 282, 282, 282, 318, 302, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 301, 282, 295, 296, 300, 300, 76, + 73, 282, 154, 282, 295, 296, 297, 300, + 76, 73, 282, 154, 282, 282, 104, 282, + 293, 282, 336, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 293, + 282, 293, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 293, 282, 293, 282, 282, 282, 318, 294, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 293, 282, 287, 288, 292, 292, 76, + 73, 282, 154, 282, 287, 288, 289, 292, + 76, 73, 282, 154, 282, 282, 106, 282, + 285, 282, 337, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 285, + 282, 285, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 285, 282, 285, 282, 282, 282, 318, 286, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 285, 282, 107, 75, 75, 76, 73, + 338, 338, 338, 338, 144, 338, 150, 151, + 284, 284, 76, 73, 282, 154, 282, 107, + 75, 75, 76, 73, 338, 340, 341, 342, + 343, 112, 109, 339, 344, 339, 339, 143, + 339, 345, 341, 343, 343, 112, 109, 339, + 344, 339, 341, 343, 343, 112, 109, 339, + 344, 339, 346, 339, 339, 339, 125, 347, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 346, 339, 348, 349, 350, 351, 112, + 109, 339, 344, 339, 339, 141, 339, 352, + 349, 353, 353, 112, 109, 339, 344, 339, + 349, 353, 353, 112, 109, 339, 344, 339, + 354, 339, 339, 339, 125, 355, 339, 109, + 339, 344, 339, 339, 339, 339, 339, 354, + 339, 356, 357, 358, 359, 112, 109, 339, + 344, 339, 339, 139, 339, 360, 357, 361, + 361, 112, 109, 339, 344, 339, 357, 361, + 361, 112, 109, 339, 344, 339, 362, 339, + 339, 339, 125, 363, 339, 109, 339, 344, + 339, 339, 339, 339, 339, 362, 339, 364, + 365, 366, 367, 112, 109, 339, 344, 339, + 339, 137, 339, 368, 365, 369, 369, 112, + 109, 339, 344, 339, 365, 369, 369, 112, + 109, 339, 344, 339, 370, 339, 339, 339, + 125, 371, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 370, 339, 372, 373, 374, + 375, 112, 109, 339, 344, 339, 339, 135, + 339, 376, 373, 377, 377, 112, 109, 339, + 344, 339, 373, 377, 377, 112, 109, 339, + 344, 339, 125, 378, 339, 109, 339, 344, + 339, 379, 379, 339, 109, 339, 344, 339, + 380, 339, 339, 381, 339, 344, 339, 344, + 339, 382, 339, 383, 339, 380, 339, 339, + 339, 339, 344, 339, 125, 339, 379, 379, + 339, 109, 339, 344, 339, 379, 378, 339, + 109, 339, 344, 339, 384, 134, 385, 386, + 115, 109, 339, 344, 339, 134, 385, 386, + 115, 109, 339, 344, 339, 385, 385, 115, + 109, 339, 344, 339, 387, 131, 388, 389, + 118, 109, 339, 344, 339, 131, 388, 389, + 118, 109, 339, 344, 339, 388, 388, 118, + 109, 339, 344, 339, 390, 128, 391, 392, + 121, 109, 339, 344, 339, 128, 391, 392, + 121, 109, 339, 344, 339, 391, 391, 121, + 109, 339, 344, 339, 393, 125, 379, 394, + 339, 109, 339, 344, 339, 125, 379, 394, + 339, 109, 339, 344, 339, 372, 373, 377, + 377, 112, 109, 339, 344, 339, 372, 373, + 374, 377, 112, 109, 339, 344, 339, 339, + 135, 339, 370, 339, 395, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 370, 339, 370, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 370, 339, 370, 339, 339, 339, + 379, 371, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 370, 339, 364, 365, 369, + 369, 112, 109, 339, 344, 339, 364, 365, + 366, 369, 112, 109, 339, 344, 339, 339, + 137, 339, 362, 339, 396, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 362, 339, 362, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 362, 339, 362, 339, 339, 339, + 379, 363, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 362, 339, 356, 357, 361, + 361, 112, 109, 339, 344, 339, 356, 357, + 358, 361, 112, 109, 339, 344, 339, 339, + 139, 339, 354, 339, 397, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 354, 339, 354, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 354, 339, 354, 339, 339, 339, + 379, 355, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 354, 339, 348, 349, 353, + 353, 112, 109, 339, 344, 339, 348, 349, + 350, 353, 112, 109, 339, 344, 339, 339, + 141, 339, 346, 339, 398, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 346, 339, 346, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 346, 339, 346, 339, 339, 339, + 379, 347, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 346, 339, 340, 341, 343, + 343, 112, 109, 339, 344, 339, 148, 149, + 150, 151, 399, 284, 76, 73, 282, 154, + 155, 155, 144, 282, 282, 148, 282, 161, + 400, 163, 164, 4, 1, 160, 165, 160, + 160, 35, 160, 168, 149, 150, 151, 401, + 402, 76, 403, 160, 404, 160, 155, 144, + 160, 160, 168, 160, 107, 405, 405, 76, + 403, 160, 165, 160, 160, 144, 160, 406, + 160, 160, 407, 160, 404, 160, 404, 160, + 408, 160, 205, 160, 406, 160, 160, 160, + 160, 404, 160, 168, 160, 220, 107, 405, + 405, 76, 403, 160, 165, 160, 160, 160, + 160, 160, 168, 160, 410, 409, 411, 411, + 409, 146, 409, 412, 409, 411, 411, 409, + 146, 409, 412, 409, 413, 409, 409, 414, + 409, 412, 409, 412, 409, 415, 409, 416, + 409, 413, 409, 409, 409, 409, 412, 409, + 148, 338, 338, 338, 338, 338, 338, 338, + 338, 338, 155, 338, 338, 338, 338, 148, + 338, 0 }; static const short _indic_syllable_machine_trans_targs[] = { - 166, 188, 2, 194, 3, 5, 197, 6, - 8, 200, 9, 11, 203, 12, 14, 15, - 187, 17, 18, 202, 20, 21, 199, 23, - 24, 196, 205, 208, 212, 214, 218, 220, - 224, 226, 230, 232, 166, 255, 37, 261, - 38, 40, 264, 41, 43, 267, 44, 46, - 270, 47, 49, 50, 254, 52, 53, 269, - 55, 56, 266, 58, 59, 263, 272, 275, - 279, 281, 285, 287, 291, 293, 297, 300, - 166, 321, 72, 327, 166, 73, 75, 330, - 76, 78, 333, 79, 81, 336, 82, 84, - 85, 320, 87, 88, 335, 90, 91, 332, - 93, 94, 329, 338, 341, 345, 347, 351, - 353, 357, 359, 363, 166, 389, 106, 395, - 107, 109, 398, 110, 112, 401, 113, 115, - 404, 116, 118, 119, 388, 121, 122, 403, - 124, 125, 400, 127, 128, 397, 406, 409, - 413, 415, 419, 421, 425, 427, 431, 433, - 366, 142, 444, 144, 447, 438, 145, 147, - 450, 148, 150, 453, 151, 154, 155, 455, - 157, 158, 452, 160, 161, 449, 163, 164, - 446, 166, 458, 166, 167, 234, 301, 303, - 365, 367, 323, 368, 434, 435, 340, 456, - 463, 166, 168, 170, 34, 233, 190, 207, - 169, 33, 171, 228, 172, 174, 32, 227, - 173, 31, 175, 222, 176, 178, 30, 221, - 177, 29, 179, 216, 180, 182, 28, 215, - 181, 27, 183, 210, 184, 186, 26, 209, - 185, 25, 193, 0, 189, 192, 191, 166, - 1, 195, 4, 22, 198, 7, 19, 201, - 10, 16, 204, 13, 206, 211, 213, 217, - 219, 223, 225, 229, 231, 166, 235, 237, - 69, 299, 257, 274, 236, 68, 238, 295, - 239, 241, 67, 294, 240, 66, 242, 289, - 243, 245, 65, 288, 244, 64, 246, 283, - 247, 249, 63, 282, 248, 62, 250, 277, - 251, 253, 61, 276, 252, 60, 260, 35, - 256, 259, 258, 166, 36, 262, 39, 57, - 265, 42, 54, 268, 45, 51, 271, 48, - 273, 278, 280, 284, 286, 290, 292, 296, - 298, 166, 302, 103, 304, 361, 305, 307, - 102, 360, 306, 101, 308, 355, 309, 311, - 100, 354, 310, 99, 312, 349, 313, 315, - 98, 348, 314, 97, 316, 343, 317, 319, - 96, 342, 318, 95, 326, 70, 322, 325, - 324, 166, 71, 328, 74, 92, 331, 77, - 89, 334, 80, 86, 337, 83, 339, 344, - 346, 350, 352, 356, 358, 362, 364, 166, - 166, 369, 371, 138, 137, 391, 408, 370, - 372, 429, 373, 375, 136, 428, 374, 135, - 376, 423, 377, 379, 134, 422, 378, 133, - 380, 417, 381, 383, 132, 416, 382, 131, - 384, 411, 385, 387, 130, 410, 386, 129, - 394, 104, 390, 393, 392, 166, 105, 396, - 108, 126, 399, 111, 123, 402, 114, 120, - 405, 117, 407, 412, 414, 418, 420, 424, - 426, 430, 432, 139, 436, 437, 443, 440, - 140, 439, 442, 441, 141, 445, 143, 162, - 448, 146, 159, 451, 149, 156, 454, 152, - 153, 166, 457, 165, 460, 459, 462, 461, - 166 + 138, 160, 166, 2, 167, 3, 5, 170, + 6, 8, 173, 9, 11, 176, 12, 14, + 15, 159, 17, 18, 175, 20, 21, 172, + 23, 24, 169, 178, 182, 183, 187, 188, + 192, 193, 197, 198, 138, 221, 227, 36, + 228, 37, 39, 231, 40, 42, 234, 43, + 45, 237, 46, 48, 49, 220, 51, 52, + 236, 54, 55, 233, 57, 58, 230, 239, + 243, 244, 248, 249, 253, 254, 258, 260, + 138, 281, 287, 70, 288, 138, 71, 73, + 291, 74, 76, 294, 77, 79, 297, 80, + 82, 83, 280, 85, 86, 296, 88, 89, + 293, 91, 92, 290, 299, 303, 304, 308, + 309, 313, 314, 318, 138, 343, 349, 103, + 350, 104, 106, 353, 107, 109, 356, 110, + 112, 359, 113, 115, 116, 342, 118, 119, + 358, 121, 122, 355, 124, 125, 352, 361, + 365, 366, 370, 371, 375, 376, 380, 381, + 320, 138, 394, 138, 139, 200, 261, 263, + 319, 321, 283, 322, 382, 383, 392, 399, + 138, 140, 142, 33, 199, 162, 141, 32, + 143, 195, 144, 146, 31, 194, 145, 30, + 147, 190, 148, 150, 29, 189, 149, 28, + 151, 185, 152, 154, 27, 184, 153, 26, + 155, 180, 156, 158, 25, 179, 157, 1, + 165, 0, 161, 164, 163, 138, 168, 4, + 22, 171, 7, 19, 174, 10, 16, 177, + 13, 181, 186, 191, 196, 138, 201, 203, + 67, 259, 223, 202, 66, 204, 256, 205, + 207, 65, 255, 206, 64, 208, 251, 209, + 211, 63, 250, 210, 62, 212, 246, 213, + 215, 61, 245, 214, 60, 216, 241, 217, + 219, 59, 240, 218, 35, 226, 34, 222, + 225, 224, 138, 229, 38, 56, 232, 41, + 53, 235, 44, 50, 238, 47, 242, 247, + 252, 257, 138, 262, 100, 264, 316, 265, + 267, 99, 315, 266, 98, 268, 311, 269, + 271, 97, 310, 270, 96, 272, 306, 273, + 275, 95, 305, 274, 94, 276, 301, 277, + 279, 93, 300, 278, 69, 286, 68, 282, + 285, 284, 138, 289, 72, 90, 292, 75, + 87, 295, 78, 84, 298, 81, 302, 307, + 312, 317, 138, 138, 323, 325, 134, 133, + 345, 324, 326, 378, 327, 329, 132, 377, + 328, 131, 330, 373, 331, 333, 130, 372, + 332, 129, 334, 368, 335, 337, 128, 367, + 336, 127, 338, 363, 339, 341, 126, 362, + 340, 102, 348, 101, 344, 347, 346, 138, + 351, 105, 123, 354, 108, 120, 357, 111, + 117, 360, 114, 364, 369, 374, 379, 135, + 384, 385, 391, 386, 388, 136, 387, 390, + 389, 138, 393, 137, 396, 395, 398, 397, + 138 }; static const char _indic_syllable_machine_trans_actions[] = { - 1, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 0, 0, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 4, 0, 0, 2, 5, 0, 0, 2, + 1, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 2, 6, 2, 6, 2, - 6, 2, 6, 2, 7, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 2, 2, + 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 0, 2, 0, + 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 6, 0, 2, 0, 2, 0, 0, 0, - 2, 0, 0, 2, 0, 0, 0, 2, + 4, 0, 2, 0, 2, 5, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, - 2, 8, 0, 11, 2, 2, 6, 0, - 12, 12, 0, 2, 6, 2, 6, 2, - 0, 13, 2, 0, 0, 2, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 0, 0, 0, 0, 14, - 0, 2, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 15, 2, 0, - 0, 2, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 0, - 0, 0, 0, 16, 0, 2, 0, 0, + 2, 0, 0, 2, 6, 2, 6, 2, + 6, 2, 6, 2, 7, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 17, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 0, 0, 0, - 0, 18, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 19, - 20, 2, 0, 0, 0, 0, 2, 2, + 6, 8, 0, 11, 2, 2, 6, 0, + 12, 12, 0, 2, 6, 2, 2, 0, + 13, 2, 0, 0, 2, 0, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, - 2, 0, 0, 0, 0, 21, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 0, 0, 22, 2, 0, - 0, 0, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 0, 0, 14, 2, 0, + 0, 2, 0, 0, 2, 0, 0, 2, + 0, 2, 2, 2, 2, 15, 2, 0, + 0, 2, 0, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 0, 0, + 0, 0, 16, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 2, 0, 2, 2, + 2, 2, 17, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 2, 0, 0, + 0, 0, 18, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 2, 0, 2, 2, + 2, 2, 19, 20, 2, 0, 0, 0, + 0, 2, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 0, 0, 0, 0, 21, 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 2, 2, 2, 2, 0, + 0, 22, 22, 0, 0, 0, 0, 0, 0, 23, 2, 0, 0, 0, 0, 0, 24 }; @@ -937,15 +759,7 @@ static const char _indic_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -998,15 +812,7 @@ static const char _indic_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1046,67 +852,59 @@ static const short _indic_syllable_machine_eof_trans[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 37, 37, 37, 37, 37, + 1, 1, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 73, 73, - 77, 77, 73, 73, 73, 73, 73, 73, + 37, 37, 37, 37, 73, 73, 78, 78, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 73, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 170, 0, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 384, 322, 384, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 322, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 474, 474, 474, 474, 474, 474, 474, 384 + 109, 109, 109, 109, 109, 109, 109, 73, + 1, 146, 0, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 339, + 283, 339, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 283, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 410, 410, 410, 410, 410, 410, 410, 339 }; -static const int indic_syllable_machine_start = 166; -static const int indic_syllable_machine_first_final = 166; +static const int indic_syllable_machine_start = 138; +static const int indic_syllable_machine_first_final = 138; static const int indic_syllable_machine_error = -1; -static const int indic_syllable_machine_en_main = 166; +static const int indic_syllable_machine_en_main = 138; #line 36 "hb-ot-shape-complex-indic-machine.rl" @@ -1118,10 +916,9 @@ static const int indic_syllable_machine_en_main = 166; #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -1129,11 +926,11 @@ static const int indic_syllable_machine_en_main = 166; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 1137 "hb-ot-shape-complex-indic-machine.hh" +#line 934 "hb-ot-shape-complex-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1141,16 +938,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 113 "hb-ot-shape-complex-indic-machine.rl" +#line 112 "hb-ot-shape-complex-indic-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 1154 "hb-ot-shape-complex-indic-machine.hh" +#line 950 "hb-ot-shape-complex-indic-machine.hh" { int _slen; int _trans; @@ -1164,7 +960,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 1168 "hb-ot-shape-complex-indic-machine.hh" +#line 964 "hb-ot-shape-complex-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1287,7 +1083,7 @@ _eof_trans: #line 88 "hb-ot-shape-complex-indic-machine.rl" {act = 6;} break; -#line 1291 "hb-ot-shape-complex-indic-machine.hh" +#line 1087 "hb-ot-shape-complex-indic-machine.hh" } _again: @@ -1296,7 +1092,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1300 "hb-ot-shape-complex-indic-machine.hh" +#line 1096 "hb-ot-shape-complex-indic-machine.hh" } if ( ++p != pe ) @@ -1312,7 +1108,7 @@ _again: } -#line 122 "hb-ot-shape-complex-indic-machine.rl" +#line 120 "hb-ot-shape-complex-indic-machine.rl" } diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl index 35e7ce9..c5d945d 100644 --- a/src/hb-ot-shape-complex-indic-machine.rl +++ b/src/hb-ot-shape-complex-indic-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine indic_syllable_machine; @@ -52,7 +52,6 @@ DOTTEDCIRCLE = 12; RS = 13; Repha = 15; Ra = 16; -CM = 17; Symbol= 18; CS = 19; @@ -68,15 +67,16 @@ matra_group = z{0,3}.M.N?.(H | forced_rakar)?; syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}?; halant_group = (z?.H.(ZWJ.N?)?); final_halant_group = halant_group | H.ZWNJ; -medial_group = CM?; -halant_or_matra_group = (final_halant_group | (H.ZWJ)? matra_group{0,4}); +halant_or_matra_group = (final_halant_group | matra_group{0,4}); +complex_syllable_tail = (halant_group.cn){0,4} halant_or_matra_group syllable_tail; -consonant_syllable = (Repha|CS)? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail; -vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail); -standalone_cluster = ((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; + +consonant_syllable = (Repha|CS)? cn complex_syllable_tail; +vowel_syllable = reph? V.n? (ZWJ | complex_syllable_tail); +standalone_cluster = ((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? complex_syllable_tail; symbol_cluster = symbol syllable_tail; -broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; +broken_cluster = reph? n? complex_syllable_tail; other = any; main := |* @@ -93,10 +93,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -104,7 +103,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -115,7 +114,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc index 54291bc..43b5ef8 100644 --- a/src/hb-ot-shape-complex-indic-table.cc +++ b/src/hb-ot-shape-complex-indic-table.cc @@ -14,8 +14,10 @@ * # Date: 2017-10-16, 24:39:00 GMT [KW] */ -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" #define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 16 chars; Avagraha */ #define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 83 chars; Bindu */ @@ -69,6 +71,7 @@ #define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */ #define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */ #define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */ +#pragma GCC diagnostic pop #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M) diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 447e36c..d2d0a5a 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -24,8 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-indic-private.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-shape-complex-indic.hh" +#include "hb-ot-shape-complex-vowel-constraints.hh" +#include "hb-ot-layout.hh" /* @@ -95,42 +96,41 @@ static const indic_config_t indic_configs[] = * Indic shaper. */ -struct feature_list_t { - hb_tag_t tag; - hb_ot_map_feature_flags_t flags; -}; - -static const feature_list_t +static const hb_ot_map_feature_t indic_features[] = { /* * Basic features. * These features are applied in order, one at a time, after initial_reordering. */ - {HB_TAG('n','u','k','t'), F_GLOBAL}, - {HB_TAG('a','k','h','n'), F_GLOBAL}, - {HB_TAG('r','p','h','f'), F_NONE}, - {HB_TAG('r','k','r','f'), F_GLOBAL}, - {HB_TAG('p','r','e','f'), F_NONE}, - {HB_TAG('b','l','w','f'), F_NONE}, - {HB_TAG('a','b','v','f'), F_NONE}, - {HB_TAG('h','a','l','f'), F_NONE}, - {HB_TAG('p','s','t','f'), F_NONE}, - {HB_TAG('v','a','t','u'), F_GLOBAL}, - {HB_TAG('c','j','c','t'), F_GLOBAL}, + {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS}, + {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, + {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, + {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS}, /* * Other features. - * These features are applied all at once, after final_reordering. + * These features are applied all at once, after final_reordering + * but before clearing syllables. * Default Bengali font in Windows for example has intermixed * lookups for init,pres,abvs,blws features. */ - {HB_TAG('i','n','i','t'), F_NONE}, - {HB_TAG('p','r','e','s'), F_GLOBAL}, - {HB_TAG('a','b','v','s'), F_GLOBAL}, - {HB_TAG('b','l','w','s'), F_GLOBAL}, - {HB_TAG('p','s','t','s'), F_GLOBAL}, - {HB_TAG('h','a','l','n'), F_GLOBAL}, - /* Positioning features, though we don't care about the types. */ + {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS}, + {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS}, + /* + * Positioning features. + * We don't care about the types. + */ {HB_TAG('d','i','s','t'), F_GLOBAL}, {HB_TAG('a','b','v','m'), F_GLOBAL}, {HB_TAG('b','l','w','m'), F_GLOBAL}, @@ -158,12 +158,13 @@ enum { _BLWS, _PSTS, _HALN, + _DIST, _ABVM, _BLWM, INDIC_NUM_FEATURES, - INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ + INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */ }; static void @@ -191,25 +192,27 @@ collect_features_indic (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->add_global_bool_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p')); unsigned int i = 0; map->add_gsub_pause (initial_reordering); + for (; i < INDIC_BASIC_FEATURES; i++) { - map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); + map->add_feature (indic_features[i]); map->add_gsub_pause (nullptr); } + map->add_gsub_pause (final_reordering); - for (; i < INDIC_NUM_FEATURES; i++) { - map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - } - map->add_global_bool_feature (HB_TAG('c','a','l','t')); - map->add_global_bool_feature (HB_TAG('c','l','i','g')); + for (; i < INDIC_NUM_FEATURES; i++) + map->add_feature (indic_features[i]); + + map->enable_feature (HB_TAG('c','a','l','t')); + map->enable_feature (HB_TAG('c','l','i','g')); map->add_gsub_pause (clear_syllables); } @@ -217,13 +220,13 @@ collect_features_indic (hb_ot_shape_planner_t *plan) static void override_features_indic (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('l','i','g','a')); } struct would_substitute_feature_t { - inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) + void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) { zero_context = zero_context_; map->get_stage_lookups (0/*GSUB*/, @@ -231,9 +234,9 @@ struct would_substitute_feature_t &lookups, &count); } - inline bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const + bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + hb_face_t *face) const { for (unsigned int i = 0; i < count; i++) if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) @@ -249,12 +252,10 @@ struct would_substitute_feature_t struct indic_shape_plan_t { - ASSERT_POD (); - - inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const + bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const { - hb_codepoint_t glyph = virama_glyph; - if (unlikely (virama_glyph == (hb_codepoint_t) -1)) + hb_codepoint_t glyph = virama_glyph.get_relaxed (); + if (unlikely (glyph == (hb_codepoint_t) -1)) { if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph)) glyph = 0; @@ -262,8 +263,8 @@ struct indic_shape_plan_t * Maybe one day... */ /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph - * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ - virama_glyph = glyph; + * during shape planning... Instead, overwrite it here. */ + virama_glyph.set_relaxed ((int) glyph); } *pglyph = glyph; @@ -273,7 +274,8 @@ struct indic_shape_plan_t const indic_config_t *config; bool is_old_spec; - mutable hb_codepoint_t virama_glyph; + bool uniscribe_bug_compatible; + mutable hb_atomic_int_t virama_glyph; would_substitute_feature_t rphf; would_substitute_feature_t pref; @@ -298,7 +300,8 @@ data_create_indic (const hb_ot_shape_plan_t *plan) } indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2'); - indic_plan->virama_glyph = (hb_codepoint_t) -1; + indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible; + indic_plan->virama_glyph.set_relaxed (-1); /* Use zero-context would_substitute() matching for new-spec of the main * Indic scripts, and scripts with one spec only, but not for old-specs. @@ -419,7 +422,7 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan, return; hb_codepoint_t virama; - if (indic_plan->get_virama_glyph (font, &virama)) + if (indic_plan->load_virama_glyph (font, &virama)) { hb_face_t *face = font->face; unsigned int count = buffer->len; @@ -667,9 +670,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * last consonant. * * Reports suggest that in some scripts Uniscribe does this only if there - * is *not* a Halant after last consonant already (eg. Kannada), while it - * does it unconditionally in other scripts (eg. Malayalam). We don't - * currently know about other scripts, so we single out Malayalam for now. + * is *not* a Halant after last consonant already. We know that is the + * case for Kannada, while it reorders unconditionally in other scripts, + * eg. Malayalam, Bengali, and Devanagari. We don't currently know about + * other scripts, so we blacklist Kannada. * * Kannada test case: * U+0C9A,U+0CCD,U+0C9A,U+0CCD @@ -679,10 +683,20 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * Malayalam test case: * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D * With lohit-ttf-20121122/Lohit-Malayalam.ttf + * + * Bengali test case: + * U+0998,U+09CD,U+09AF,U+09CD + * With Windows XP vrinda.ttf + * https://github.com/harfbuzz/harfbuzz/issues/1073 + * + * Devanagari test case: + * U+091F,U+094D,U+0930,U+094D + * With chandas.ttf + * https://github.com/harfbuzz/harfbuzz/issues/1071 */ if (indic_plan->is_old_spec) { - bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM; + bool disallow_double_halants = buffer->props.script == HB_SCRIPT_KANNADA; for (unsigned int i = base + 1; i < end; i++) if (info[i].indic_category() == OT_H) { @@ -706,7 +720,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, indic_position_t last_pos = POS_START; for (unsigned int i = start; i < end; i++) { - if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H)))) + if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H)))) { info[i].indic_position() = last_pos; if (unlikely (info[i].indic_category() == OT_H && @@ -772,8 +786,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * * We could use buffer->sort() for this, if there was no special * reordering of pre-base stuff happening later... + * We don't want to merge_clusters all of that, which buffer->sort() + * would. */ - if (indic_plan->is_old_spec || end - base > 127) + if (indic_plan->is_old_spec || end - start > 127) buffer->merge_clusters (base, end); else { @@ -902,10 +918,12 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end) { + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; + /* We treat placeholder/dotted-circle as if they are consonants, so we * should just chain. Only if not in compatibility mode that is... */ - if (hb_options ().uniscribe_bug_compatible) + if (indic_plan->uniscribe_bug_compatible) { /* For dotted-circle, this is what Uniscribe does: * If dotted-circle is the last glyph, it just does nothing. @@ -947,7 +965,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer) { - /* Note: This loop is extra overhead, but should not be measurable. */ + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -999,7 +1018,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, else buffer->next_glyph (); } - buffer->swap_buffers (); } @@ -1029,9 +1047,11 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * phase, and that might have messed up our properties. Recover * from a particular case of that where we're fairly sure that a * class of OT_H is desired but has been lost. */ - if (indic_plan->virama_glyph) + /* We don't call load_virama_glyph(), since we know it's already + * loaded. */ + hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed (); + if (virama_glyph) { - unsigned int virama_glyph = indic_plan->virama_glyph; for (unsigned int i = start; i < end; i++) if (info[i].codepoint == virama_glyph && _hb_glyph_info_ligated (&info[i]) && @@ -1120,6 +1140,24 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * defined as “after last standalone halant glyph, after initial matra * position and before the main consonant”. If ZWJ or ZWNJ follow this * halant, position is moved after it. + * + * IMPLEMENTATION NOTES: + * + * It looks like the last sentence is wrong. Testing, with Windows 7 Uniscribe + * and Devanagari shows that the behavior is best described as: + * + * "If ZWJ follows this halant, matra is NOT repositioned after this halant. + * If ZWNJ follows this halant, position is moved after it." + * + * Test case, with Adobe Devanagari or Nirmala UI: + * + * U+091F,U+094D,U+200C,U+092F,U+093F + * (Matra moves to the middle, after ZWNJ.) + * + * U+091F,U+094D,U+200D,U+092F,U+093F + * (Matra does NOT move, stays to the left.) + * + * https://github.com/harfbuzz/harfbuzz/issues/1070 */ if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ @@ -1133,6 +1171,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, */ if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) { + search: while (new_pos > start && !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H))))) new_pos--; @@ -1143,9 +1182,27 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (is_halant (info[new_pos]) && info[new_pos].indic_position() != POS_PRE_M) { +#if 0 // See comment above /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) new_pos++; +#endif + if (new_pos + 1 < end) + { + /* -> If ZWJ follows this halant, matra is NOT repositioned after this halant. */ + if (info[new_pos + 1].indic_category() == OT_ZWJ) + { + /* Keep searching. */ + if (new_pos > start) + { + new_pos--; + goto search; + } + } + /* -> If ZWNJ follows this halant, position is moved after it. */ + if (info[new_pos + 1].indic_category() == OT_ZWNJ) + new_pos++; + } } else new_pos = start; /* No move. */ @@ -1306,7 +1363,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * Uniscribe doesn't do this. * TEST: U+0930,U+094D,U+0915,U+094B,U+094D */ - if (!hb_options ().uniscribe_bug_compatible && + if (!indic_plan->uniscribe_bug_compatible && unlikely (is_halant (info[new_reph_pos]))) { for (unsigned int i = base + 1; i < new_reph_pos; i++) if (info[i].indic_category() == OT_M) { @@ -1412,7 +1469,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, /* * Finish off the clusters and go home! */ - if (hb_options ().uniscribe_bug_compatible) + if (indic_plan->uniscribe_bug_compatible) { switch ((hb_tag_t) plan->props.script) { @@ -1460,6 +1517,14 @@ clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, } +static void +preprocess_text_indic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + _hb_preprocess_text_vowel_constraints (plan, buffer, font); +} + static bool decompose_indic (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t ab, @@ -1559,13 +1624,13 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = override_features_indic, data_create_indic, data_destroy_indic, - nullptr, /* preprocess_text */ + preprocess_text_indic, nullptr, /* postprocess_glyphs */ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, decompose_indic, compose_indic, setup_masks_indic, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic.hh index 9554994..dcc2a7a 100644 --- a/src/hb-ot-shape-complex-indic-private.hh +++ b/src/hb-ot-shape-complex-indic.hh @@ -24,14 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_HH -#include "hb-private.hh" +#include "hb.hh" - -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-private.hh" /* XXX Remove */ +#include "hb-ot-shape-complex.hh" /* buffer var allocations */ @@ -64,19 +62,17 @@ enum indic_category_t { OT_Coeng = 14, /* Khmer-style Virama. */ OT_Repha = 15, /* Atomically-encoded logical or visual repha. */ OT_Ra = 16, - OT_CM = 17, /* Consonant-Medial. */ + OT_CM = 17, /* Consonant-Medial; Unused by Indic shaper. */ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */ OT_CS = 19 }; -#define MEDIAL_FLAGS (FLAG (OT_CM)) - /* Note: * * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels * cannot happen in a consonant syllable. The plus side however is, we can call the * consonant syllable logic from the vowel syllable function and get it all right! */ -#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) +#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) @@ -125,7 +121,7 @@ enum indic_syllabic_category_t { INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha, INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N, + INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_CS, INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng, @@ -300,7 +296,9 @@ static const hb_codepoint_t ra_chars[] = { 0x0CB0u, /* Kannada */ 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */ - 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */ + 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */ + + 0x179Au, /* Khmer */ }; static inline bool @@ -398,4 +396,4 @@ set_indic_properties (hb_glyph_info_t &info) } -#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */ diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh index d001021..2bc8ca6 100644 --- a/src/hb-ot-shape-complex-khmer-machine.hh +++ b/src/hb-ot-shape-complex-khmer-machine.hh @@ -29,143 +29,212 @@ #ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { - 7u, 7u, 1u, 16u, 13u, 13u, 1u, 16u, 7u, 13u, 7u, 7u, 1u, 16u, 13u, 13u, - 1u, 16u, 7u, 13u, 1u, 16u, 3u, 14u, 3u, 14u, 5u, 14u, 3u, 14u, 5u, 14u, - 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u, 3u, 14u, 5u, 14u, - 3u, 14u, 5u, 14u, 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u, - 3u, 14u, 7u, 13u, 7u, 7u, 1u, 16u, 0 + 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, + 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, + 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u, + 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u, + 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, + 5u, 29u, 0 }; static const char _khmer_syllable_machine_key_spans[] = { - 1, 16, 1, 16, 7, 1, 16, 1, - 16, 7, 16, 12, 12, 10, 12, 10, - 1, 11, 6, 1, 6, 12, 12, 10, - 12, 10, 1, 11, 6, 1, 6, 12, - 12, 7, 1, 16 + 22, 17, 22, 17, 16, 17, 22, 17, + 22, 17, 16, 17, 22, 17, 16, 17, + 22, 17, 22, 17, 22, 16, 29, 25, + 25, 25, 1, 18, 25, 25, 25, 22, + 25, 25, 1, 18, 25, 25, 16, 25, + 25 }; static const short _khmer_syllable_machine_index_offsets[] = { - 0, 2, 19, 21, 38, 46, 48, 65, - 67, 84, 92, 109, 122, 135, 146, 159, - 170, 172, 184, 191, 193, 200, 213, 226, - 237, 250, 261, 263, 275, 282, 284, 291, - 304, 317, 325, 327 + 0, 23, 41, 64, 82, 99, 117, 140, + 158, 181, 199, 216, 234, 257, 275, 292, + 310, 333, 351, 374, 392, 415, 432, 462, + 488, 514, 540, 542, 561, 587, 613, 639, + 662, 688, 714, 716, 735, 761, 787, 804, + 830 }; static const char _khmer_syllable_machine_indicies[] = { - 1, 0, 2, 2, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 3, 0, 0, 0, 0, 4, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 3, 0, 4, 4, 0, + 0, 3, 0, 0, 0, 0, 4, 0, + 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, 1, 0, - 0, 0, 0, 0, 5, 0, 7, 6, - 8, 8, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 8, - 6, 9, 6, 10, 10, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 10, 6, 7, 6, 6, 6, - 6, 6, 11, 6, 4, 4, 13, 12, - 14, 15, 7, 16, 12, 12, 4, 4, - 11, 17, 12, 4, 12, 19, 18, 20, - 21, 1, 22, 18, 18, 18, 18, 5, - 23, 18, 24, 18, 21, 21, 1, 22, - 18, 18, 18, 18, 18, 23, 18, 21, - 21, 1, 22, 18, 18, 18, 18, 18, - 23, 18, 25, 18, 21, 21, 1, 22, - 18, 18, 18, 18, 18, 26, 18, 21, - 21, 1, 22, 18, 18, 18, 18, 18, - 26, 18, 27, 18, 28, 18, 29, 18, - 18, 22, 18, 18, 18, 18, 3, 18, - 30, 18, 18, 18, 18, 22, 18, 22, - 18, 28, 18, 18, 18, 18, 22, 18, - 19, 18, 21, 21, 1, 22, 18, 18, - 18, 18, 18, 23, 18, 32, 31, 33, - 33, 7, 16, 31, 31, 31, 31, 31, - 34, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 34, 31, 35, 31, 33, - 33, 7, 16, 31, 31, 31, 31, 31, - 36, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 36, 31, 37, 31, 38, - 31, 39, 31, 31, 16, 31, 31, 31, - 31, 9, 31, 40, 31, 31, 31, 31, - 16, 31, 16, 31, 38, 31, 31, 31, - 31, 16, 31, 13, 31, 41, 33, 7, - 16, 31, 31, 31, 31, 11, 34, 31, - 13, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 34, 31, 7, 42, 42, - 42, 42, 42, 11, 42, 7, 42, 10, - 10, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 10, 42, + 4, 0, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 0, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 4, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 11, 11, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 0, + 0, 0, 0, 4, 0, 11, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 0, 13, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 13, 0, + 15, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 16, 14, 15, 15, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 16, 17, 17, 17, 17, 18, + 17, 19, 19, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 18, 17, 20, 20, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 20, 17, 21, 21, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 22, 17, 23, 23, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 24, 17, + 17, 17, 17, 18, 17, 23, 23, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 24, 17, 25, + 25, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 26, + 17, 17, 17, 17, 18, 17, 25, 25, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 26, 17, + 15, 15, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 27, + 16, 17, 17, 17, 17, 18, 17, 28, + 28, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 28, 17, + 13, 13, 29, 29, 30, 30, 29, 29, + 29, 29, 2, 2, 29, 31, 29, 13, + 29, 29, 29, 29, 16, 20, 29, 29, + 29, 18, 24, 26, 22, 29, 33, 33, + 32, 32, 32, 32, 32, 32, 32, 34, + 32, 32, 32, 32, 32, 2, 3, 6, + 32, 32, 32, 4, 10, 12, 8, 32, + 35, 35, 32, 32, 32, 32, 32, 32, + 32, 36, 32, 32, 32, 32, 32, 32, + 3, 6, 32, 32, 32, 4, 10, 12, + 8, 32, 5, 5, 32, 32, 32, 32, + 32, 32, 32, 36, 32, 32, 32, 32, + 32, 32, 4, 6, 32, 32, 32, 32, + 32, 32, 8, 32, 6, 32, 7, 7, + 32, 32, 32, 32, 32, 32, 32, 36, + 32, 32, 32, 32, 32, 32, 8, 6, + 32, 37, 37, 32, 32, 32, 32, 32, + 32, 32, 36, 32, 32, 32, 32, 32, + 32, 10, 6, 32, 32, 32, 4, 32, + 32, 8, 32, 38, 38, 32, 32, 32, + 32, 32, 32, 32, 36, 32, 32, 32, + 32, 32, 32, 12, 6, 32, 32, 32, + 4, 10, 32, 8, 32, 35, 35, 32, + 32, 32, 32, 32, 32, 32, 34, 32, + 32, 32, 32, 32, 32, 3, 6, 32, + 32, 32, 4, 10, 12, 8, 32, 15, + 15, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 16, + 39, 39, 39, 39, 18, 39, 41, 41, + 40, 40, 40, 40, 40, 40, 40, 42, + 40, 40, 40, 40, 40, 40, 16, 20, + 40, 40, 40, 18, 24, 26, 22, 40, + 19, 19, 40, 40, 40, 40, 40, 40, + 40, 42, 40, 40, 40, 40, 40, 40, + 18, 20, 40, 40, 40, 40, 40, 40, + 22, 40, 20, 40, 21, 21, 40, 40, + 40, 40, 40, 40, 40, 42, 40, 40, + 40, 40, 40, 40, 22, 20, 40, 43, + 43, 40, 40, 40, 40, 40, 40, 40, + 42, 40, 40, 40, 40, 40, 40, 24, + 20, 40, 40, 40, 18, 40, 40, 22, + 40, 44, 44, 40, 40, 40, 40, 40, + 40, 40, 42, 40, 40, 40, 40, 40, + 40, 26, 20, 40, 40, 40, 18, 24, + 40, 22, 40, 28, 28, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 28, 39, 45, 45, 40, 40, + 40, 40, 40, 40, 40, 46, 40, 40, + 40, 40, 40, 27, 16, 20, 40, 40, + 40, 18, 24, 26, 22, 40, 41, 41, + 40, 40, 40, 40, 40, 40, 40, 46, + 40, 40, 40, 40, 40, 40, 16, 20, + 40, 40, 40, 18, 24, 26, 22, 40, 0 }; static const char _khmer_syllable_machine_trans_targs[] = { - 10, 14, 17, 20, 11, 21, 10, 24, - 27, 30, 31, 32, 10, 22, 33, 34, - 26, 35, 10, 12, 4, 0, 16, 3, - 13, 15, 1, 10, 18, 2, 19, 10, - 23, 5, 8, 25, 6, 10, 28, 7, - 29, 9, 10 + 22, 1, 30, 24, 25, 3, 26, 5, + 27, 7, 28, 9, 29, 23, 22, 11, + 32, 22, 33, 13, 34, 15, 35, 17, + 36, 19, 37, 40, 39, 22, 31, 38, + 22, 0, 10, 2, 4, 6, 8, 22, + 22, 12, 14, 16, 18, 20, 21 }; static const char _khmer_syllable_machine_trans_actions[] = { - 1, 2, 2, 0, 2, 2, 3, 2, - 2, 0, 2, 2, 6, 2, 0, 0, - 0, 0, 7, 2, 0, 0, 0, 0, - 2, 2, 0, 8, 0, 0, 0, 9, - 2, 0, 0, 2, 0, 10, 0, 0, - 0, 0, 11 + 1, 0, 2, 2, 2, 0, 0, 0, + 2, 0, 2, 0, 2, 2, 3, 0, + 4, 5, 2, 0, 0, 0, 2, 0, + 2, 0, 2, 4, 4, 8, 9, 0, + 10, 0, 0, 0, 0, 0, 0, 11, + 12, 0, 0, 0, 0, 0, 0 }; static const char _khmer_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0 }; static const char _khmer_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0 }; static const unsigned char _khmer_syllable_machine_eof_trans[] = { - 1, 1, 1, 1, 1, 7, 7, 7, - 7, 7, 0, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 43, 43, 43 + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 0, 33, + 33, 33, 33, 33, 33, 33, 33, 40, + 41, 41, 41, 41, 41, 41, 40, 41, + 41 }; -static const int khmer_syllable_machine_start = 10; -static const int khmer_syllable_machine_first_final = 10; +static const int khmer_syllable_machine_start = 22; +static const int khmer_syllable_machine_first_final = 22; static const int khmer_syllable_machine_error = -1; -static const int khmer_syllable_machine_en_main = 10; +static const int khmer_syllable_machine_en_main = 22; #line 36 "hb-ot-shape-complex-khmer-machine.rl" -#line 74 "hb-ot-shape-complex-khmer-machine.rl" +#line 80 "hb-ot-shape-complex-khmer-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -173,11 +242,11 @@ static const int khmer_syllable_machine_en_main = 10; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 181 "hb-ot-shape-complex-khmer-machine.hh" +#line 250 "hb-ot-shape-complex-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -185,16 +254,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 95 "hb-ot-shape-complex-khmer-machine.rl" +#line 100 "hb-ot-shape-complex-khmer-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 198 "hb-ot-shape-complex-khmer-machine.hh" +#line 266 "hb-ot-shape-complex-khmer-machine.hh" { int _slen; int _trans; @@ -204,11 +272,11 @@ find_syllables (hb_buffer_t *buffer) goto _test_eof; _resume: switch ( _khmer_syllable_machine_from_state_actions[cs] ) { - case 5: + case 7: #line 1 "NONE" {ts = p;} break; -#line 212 "hb-ot-shape-complex-khmer-machine.hh" +#line 280 "hb-ot-shape-complex-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -231,47 +299,63 @@ _eof_trans: {te = p+1;} break; case 8: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" - {te = p+1;{ found_syllable (consonant_syllable); }} - break; - case 10: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" - {te = p+1;{ found_syllable (broken_cluster); }} - break; - case 6: -#line 70 "hb-ot-shape-complex-khmer-machine.rl" +#line 76 "hb-ot-shape-complex-khmer-machine.rl" {te = p+1;{ found_syllable (non_khmer_cluster); }} break; - case 7: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" + case 10: +#line 74 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (consonant_syllable); }} break; - case 9: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" + case 12: +#line 75 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; case 11: -#line 70 "hb-ot-shape-complex-khmer-machine.rl" +#line 76 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (non_khmer_cluster); }} break; case 1: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" +#line 74 "hb-ot-shape-complex-khmer-machine.rl" {{p = ((te))-1;}{ found_syllable (consonant_syllable); }} break; - case 3: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" + case 5: +#line 75 "hb-ot-shape-complex-khmer-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; -#line 266 "hb-ot-shape-complex-khmer-machine.hh" + case 3: +#line 1 "NONE" + { switch( act ) { + case 2: + {{p = ((te))-1;} found_syllable (broken_cluster); } + break; + case 3: + {{p = ((te))-1;} found_syllable (non_khmer_cluster); } + break; + } + } + break; + case 4: +#line 1 "NONE" + {te = p+1;} +#line 75 "hb-ot-shape-complex-khmer-machine.rl" + {act = 2;} + break; + case 9: +#line 1 "NONE" + {te = p+1;} +#line 76 "hb-ot-shape-complex-khmer-machine.rl" + {act = 3;} + break; +#line 350 "hb-ot-shape-complex-khmer-machine.hh" } _again: switch ( _khmer_syllable_machine_to_state_actions[cs] ) { - case 4: + case 6: #line 1 "NONE" {ts = 0;} break; -#line 275 "hb-ot-shape-complex-khmer-machine.hh" +#line 359 "hb-ot-shape-complex-khmer-machine.hh" } if ( ++p != pe ) @@ -287,7 +371,7 @@ _again: } -#line 104 "hb-ot-shape-complex-khmer-machine.rl" +#line 108 "hb-ot-shape-complex-khmer-machine.rl" } diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl index 54644d8..4c596ab 100644 --- a/src/hb-ot-shape-complex-khmer-machine.rl +++ b/src/hb-ot-shape-complex-khmer-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine khmer_syllable_machine; @@ -40,28 +40,34 @@ # Same order as enum khmer_category_t. Not sure how to avoid duplication. C = 1; V = 2; -N = 3; ZWNJ = 5; ZWJ = 6; -M = 7; -SM = 8; PLACEHOLDER = 11; DOTTEDCIRCLE = 12; -RS = 13; -Coeng = 14; -Ra = 16; - -c = (C | Ra | V); # is_consonant -n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier -z = ZWJ|ZWNJ; # is_joiner - -cn = c.n?; -matra_group = z?.M.N?; -syllable_tail = (SM.SM?)?; - - -broken_cluster = n? (Coeng.cn)* matra_group* (Coeng.cn)? syllable_tail; -consonant_syllable = (c|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster; +Coeng= 14; +Ra = 16; +Robatic = 20; +Xgroup = 21; +Ygroup = 22; +VAbv = 26; +VBlw = 27; +VPre = 28; +VPst = 29; + +c = (C | Ra | V); +cn = c.((ZWJ|ZWNJ)?.Robatic)?; +joiner = (ZWJ | ZWNJ); +xgroup = (joiner*.Xgroup)*; +ygroup = Ygroup*; + +# This grammar was experimentally extracted from what Uniscribe allows. + +matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?; +syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup; + + +broken_cluster = (Coeng.cn)* syllable_tail; +consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster; other = any; main := |* @@ -75,10 +81,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -86,7 +91,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -97,7 +102,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-khmer-private.hh b/src/hb-ot-shape-complex-khmer-private.hh deleted file mode 100644 index f90ef96..0000000 --- a/src/hb-ot-shape-complex-khmer-private.hh +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright © 2018 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): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH - -#include "hb-private.hh" - -#include "hb-ot-shape-complex-indic-private.hh" - - -/* buffer var allocations */ -#define khmer_category() indic_category() /* khmer_category_t */ -#define khmer_position() indic_position() /* khmer_position_t */ - - -typedef indic_category_t khmer_category_t; -typedef indic_position_t khmer_position_t; - - -static inline khmer_position_t -matra_position_khmer (khmer_position_t side) -{ - switch ((int) side) - { - case POS_PRE_C: - return POS_PRE_M; - - case POS_POST_C: - case POS_ABOVE_C: - case POS_BELOW_C: - return POS_AFTER_POST; - - default: - return side; - }; -} - -static inline bool -is_consonant_or_vowel (const hb_glyph_info_t &info) -{ - return is_one_of (info, CONSONANT_FLAGS | FLAG (OT_V)); -} - -static inline bool -is_coeng (const hb_glyph_info_t &info) -{ - return is_one_of (info, FLAG (OT_Coeng)); -} - -static inline void -set_khmer_properties (hb_glyph_info_t &info) -{ - hb_codepoint_t u = info.codepoint; - unsigned int type = hb_indic_get_categories (u); - khmer_category_t cat = (khmer_category_t) (type & 0x7Fu); - khmer_position_t pos = (khmer_position_t) (type >> 8); - - - /* - * Re-assign category - */ - - if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */ - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) || - u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */ - { - /* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier. - * https://github.com/roozbehp/unicode-data/issues/5 */ - cat = OT_M; - pos = POS_ABOVE_C; - } - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u))) cat = OT_PLACEHOLDER; - else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE; - - - /* - * Re-assign position. - */ - - if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS)) - { - pos = POS_BASE_C; - if (u == 0x179Au) - cat = OT_Ra; - } - else if (cat == OT_M) - { - pos = matra_position_khmer (pos); - } - else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) | FLAG (OT_A) | FLAG (OT_Symbol)))) - { - pos = POS_SMVD; - } - - info.khmer_category() = cat; - info.khmer_position() = pos; -} - - -#endif /* HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH */ diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 18e3c94..4475ceb 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -24,42 +24,38 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-khmer-private.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-shape-complex-khmer.hh" +#include "hb-ot-layout.hh" /* * Khmer shaper. */ -struct feature_list_t { - hb_tag_t tag; - hb_ot_map_feature_flags_t flags; -}; - -static const feature_list_t +static const hb_ot_map_feature_t khmer_features[] = { /* * Basic features. - * These features are applied in order, one at a time, after initial_reordering. + * These features are applied in order, one at a time, after reordering. */ - {HB_TAG('p','r','e','f'), F_NONE}, - {HB_TAG('b','l','w','f'), F_NONE}, - {HB_TAG('a','b','v','f'), F_NONE}, - {HB_TAG('p','s','t','f'), F_NONE}, - {HB_TAG('c','f','a','r'), F_NONE}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, + {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS}, /* * Other features. - * These features are applied all at once, after final_reordering. - * Default Bengali font in Windows for example has intermixed - * lookups for init,pres,abvs,blws features. + * These features are applied all at once after clearing syllables. + */ + {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, + /* + * Positioning features. + * We don't care about the types. */ - {HB_TAG('p','r','e','s'), F_GLOBAL}, - {HB_TAG('a','b','v','s'), F_GLOBAL}, - {HB_TAG('b','l','w','s'), F_GLOBAL}, - {HB_TAG('p','s','t','s'), F_GLOBAL}, - /* Positioning features, though we don't care about the types. */ {HB_TAG('d','i','s','t'), F_GLOBAL}, {HB_TAG('a','b','v','m'), F_GLOBAL}, {HB_TAG('b','l','w','m'), F_GLOBAL}, @@ -79,12 +75,13 @@ enum { _ABVS, _BLWS, _PSTS, + _DIST, _ABVM, _BLWM, KHMER_NUM_FEATURES, - KHMER_BASIC_FEATURES = _PRES /* Don't forget to update this! */ + KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */ }; static void @@ -92,13 +89,9 @@ setup_syllables (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +reorder (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void clear_syllables (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -111,46 +104,54 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (reorder); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); - /* The Indic specs do not require ccmp, but we apply it here since if - * there is a use of it, it's typically at the beginning. */ - map->add_global_bool_feature (HB_TAG('c','c','m','p')); - + /* Testing suggests that Uniscribe does NOT pause between basic + * features. Test with KhmerUI.ttf and the following three + * sequences: + * + * U+1789,U+17BC + * U+1789,U+17D2,U+1789 + * U+1789,U+17D2,U+1789,U+17BC + * + * https://github.com/harfbuzz/harfbuzz/issues/974 + */ + map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); unsigned int i = 0; - map->add_gsub_pause (initial_reordering); - for (; i < KHMER_BASIC_FEATURES; i++) { - map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - map->add_gsub_pause (nullptr); - } - map->add_gsub_pause (final_reordering); - for (; i < KHMER_NUM_FEATURES; i++) { - map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - } - - map->add_global_bool_feature (HB_TAG('c','a','l','t')); - map->add_global_bool_feature (HB_TAG('c','l','i','g')); + for (; i < KHMER_BASIC_FEATURES; i++) + map->add_feature (khmer_features[i]); map->add_gsub_pause (clear_syllables); + + for (; i < KHMER_NUM_FEATURES; i++) + map->add_feature (khmer_features[i]); } static void override_features_khmer (hb_ot_shape_planner_t *plan) { + hb_ot_map_builder_t *map = &plan->map; + + /* Khmer spec has 'clig' as part of required shaping features: + * "Apply feature 'clig' to form ligatures that are desired for + * typographical correctness.", hence in overrides... */ + map->enable_feature (HB_TAG('c','l','i','g')); + /* Uniscribe does not apply 'kern' in Khmer. */ if (hb_options ().uniscribe_bug_compatible) { - plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); + map->disable_feature (HB_TAG('k','e','r','n')); } - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + map->disable_feature (HB_TAG('l','i','g','a')); } struct would_substitute_feature_t { - inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) + void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) { zero_context = zero_context_; map->get_stage_lookups (0/*GSUB*/, @@ -158,9 +159,9 @@ struct would_substitute_feature_t &lookups, &count); } - inline bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const + bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + hb_face_t *face) const { for (unsigned int i = 0; i < count; i++) if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) @@ -176,9 +177,7 @@ struct would_substitute_feature_t struct khmer_shape_plan_t { - ASSERT_POD (); - - inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const + bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const { hb_codepoint_t glyph = virama_glyph; if (unlikely (virama_glyph == (hb_codepoint_t) -1)) @@ -243,7 +242,6 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED) { HB_BUFFER_ALLOCATE_VAR (buffer, khmer_category); - HB_BUFFER_ALLOCATE_VAR (buffer, khmer_position); /* We cannot setup masks here. We save information about characters * and setup masks later on in a pause-callback. */ @@ -264,159 +262,58 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, buffer->unsafe_to_break (start, end); } -static int -compare_khmer_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) -{ - int a = pa->khmer_position(); - int b = pb->khmer_position(); - - return a < b ? -1 : a == b ? 0 : +1; -} - /* Rules from: * https://docs.microsoft.com/en-us/typography/script-development/devanagari */ static void -initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, + hb_face_t *face HB_UNUSED, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { const khmer_shape_plan_t *khmer_plan = (const khmer_shape_plan_t *) plan->data; hb_glyph_info_t *info = buffer->info; - /* 1. Khmer shaping assumes that a syllable will begin with a Cons, IndV, or Number. */ - - /* The first consonant is always the base. */ - unsigned int base = start; - info[base].khmer_position() = POS_BASE_C; - - /* Mark all subsequent consonants as below. */ - for (unsigned int i = base + 1; i < end; i++) - if (is_consonant_or_vowel (info[i])) - info[i].khmer_position() = POS_BELOW_C; - - /* Mark final consonants. A final consonant is one appearing after a matra, - * like in Khmer. */ - for (unsigned int i = base + 1; i < end; i++) - if (info[i].khmer_category() == OT_M) { - for (unsigned int j = i + 1; j < end; j++) - if (is_consonant_or_vowel (info[j])) { - info[j].khmer_position() = POS_FINAL_C; - break; - } - break; - } - - /* Attach misc marks to previous char to move with them. */ + /* Setup masks. */ { - khmer_position_t last_pos = POS_START; - for (unsigned int i = start; i < end; i++) - { - if ((FLAG_UNSAFE (info[i].khmer_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_Coeng)))) - { - info[i].khmer_position() = last_pos; - if (unlikely (info[i].khmer_category() == OT_Coeng && - info[i].khmer_position() == POS_PRE_M)) - { - /* - * Uniscribe doesn't move the Halant with Left Matra. - * TEST: U+092B,U+093F,U+094DE - * We follow. This is important for the Sinhala - * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA - * where U+0DD9 is a left matra and U+0DCA is the virama. - * We don't want to move the virama with the left matra. - * TEST: U+0D9A,U+0DDA - */ - for (unsigned int j = i; j > start; j--) - if (info[j - 1].khmer_position() != POS_PRE_M) { - info[i].khmer_position() = info[j - 1].khmer_position(); - break; - } - } - } else if (info[i].khmer_position() != POS_SMVD) { - last_pos = (khmer_position_t) info[i].khmer_position(); - } - } - } - /* For post-base consonants let them own anything before them - * since the last consonant or matra. */ - { - unsigned int last = base; - for (unsigned int i = base + 1; i < end; i++) - if (is_consonant_or_vowel (info[i])) - { - for (unsigned int j = last + 1; j < i; j++) - if (info[j].khmer_position() < POS_SMVD) - info[j].khmer_position() = info[i].khmer_position(); - last = i; - } else if (info[i].khmer_category() == OT_M) - last = i; - } - - { - /* Use syllable() for sort accounting temporarily. */ - unsigned int syllable = info[start].syllable(); - for (unsigned int i = start; i < end; i++) - info[i].syllable() = i - start; - - /* Sit tight, rock 'n roll! */ - hb_stable_sort (info + start, end - start, compare_khmer_order); - /* Find base again */ - base = end; - for (unsigned int i = start; i < end; i++) - if (info[i].khmer_position() == POS_BASE_C) - { - base = i; - break; - } - - /* Note! syllable() is a one-byte field. */ - for (unsigned int i = base; i < end; i++) - if (info[i].syllable() != 255) - { - unsigned int max = i; - unsigned int j = start + info[i].syllable(); - while (j != i) - { - max = MAX (max, j); - unsigned int next = start + info[j].syllable(); - info[j].syllable() = 255; /* So we don't process j later again. */ - j = next; - } - if (i != max) - buffer->merge_clusters (i, max + 1); - } - - /* Put syllable back in. */ - for (unsigned int i = start; i < end; i++) - info[i].syllable() = syllable; - } - - /* Setup masks now */ - - { - hb_mask_t mask; - /* Post-base */ - mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF]; - for (unsigned int i = base + 1; i < end; i++) + hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF]; + for (unsigned int i = start + 1; i < end; i++) info[i].mask |= mask; } - unsigned int pref_len = 2; - if (khmer_plan->mask_array[PREF] && base + pref_len < end) + unsigned int num_coengs = 0; + for (unsigned int i = start + 1; i < end; i++) { - /* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */ - for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { - hb_codepoint_t glyphs[2]; - for (unsigned int j = 0; j < pref_len; j++) - glyphs[j] = info[i + j].codepoint; - if (khmer_plan->pref.would_substitute (glyphs, pref_len, face)) + /* """ + * When a COENG + (Cons | IndV) combination are found (and subscript count + * is less than two) the character combination is handled according to the + * subscript type of the character following the COENG. + * + * ... + * + * Subscript Type 2 - The COENG + RO characters are reordered to immediately + * before the base glyph. Then the COENG + RO characters are assigned to have + * the 'pref' OpenType feature applied to them. + * """ + */ + if (info[i].khmer_category() == OT_Coeng && num_coengs <= 2 && i + 1 < end) + { + num_coengs++; + + if (info[i + 1].khmer_category() == OT_Ra) { - for (unsigned int j = 0; j < pref_len; j++) - info[i++].mask |= khmer_plan->mask_array[PREF]; + for (unsigned int j = 0; j < 2; j++) + info[i + j].mask |= khmer_plan->mask_array[PREF]; + + /* Move the Coeng,Ro sequence to the start. */ + buffer->merge_clusters (start, i + 2); + hb_glyph_info_t t0 = info[i]; + hb_glyph_info_t t1 = info[i + 1]; + memmove (&info[start + 2], &info[start], (i - start) * sizeof (info[0])); + info[start] = t0; + info[start + 1] = t1; /* Mark the subsequent stuff with 'cfar'. Used in Khmer. * Read the feature spec. @@ -425,12 +322,22 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * U+1784,U+17D2,U+1782,U+17D2,U+179A */ if (khmer_plan->mask_array[CFAR]) - for (; i < end; i++) - info[i].mask |= khmer_plan->mask_array[CFAR]; + for (unsigned int j = i + 2; j < end; j++) + info[j].mask |= khmer_plan->mask_array[CFAR]; - break; + num_coengs = 2; /* Done. */ } } + + /* Reorder left matra piece. */ + else if (info[i].khmer_category() == OT_VPre) + { + /* Move to the start. */ + buffer->merge_clusters (start, i + 1); + hb_glyph_info_t t = info[i]; + memmove (&info[start + 1], &info[start], (i - start) * sizeof (info[0])); + info[start] = t; + } } } @@ -445,7 +352,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan, { case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ case consonant_syllable: - initial_reordering_consonant_syllable (plan, face, buffer, start, end); + reorder_consonant_syllable (plan, face, buffer, start, end); break; case non_khmer_cluster: @@ -510,263 +417,22 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, else buffer->next_glyph (); } - buffer->swap_buffers (); } static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { insert_dotted_circles (plan, font, buffer); foreach_syllable (buffer, start, end) initial_reordering_syllable (plan, font->face, buffer, start, end); -} - -static void -final_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) -{ - const khmer_shape_plan_t *khmer_plan = (const khmer_shape_plan_t *) plan->data; - hb_glyph_info_t *info = buffer->info; - - - /* This function relies heavily on halant glyphs. Lots of ligation - * and possibly multiple substitutions happened prior to this - * phase, and that might have messed up our properties. Recover - * from a particular case of that where we're fairly sure that a - * class of OT_Coeng is desired but has been lost. */ - if (khmer_plan->virama_glyph) - { - unsigned int virama_glyph = khmer_plan->virama_glyph; - for (unsigned int i = start; i < end; i++) - if (info[i].codepoint == virama_glyph && - _hb_glyph_info_ligated (&info[i]) && - _hb_glyph_info_multiplied (&info[i])) - { - /* This will make sure that this glyph passes is_coeng() test. */ - info[i].khmer_category() = OT_Coeng; - _hb_glyph_info_clear_ligated_and_multiplied (&info[i]); - } - } - - - /* 4. Final reordering: - * - * After the localized forms and basic shaping forms GSUB features have been - * applied (see below), the shaping engine performs some final glyph - * reordering before applying all the remaining font features to the entire - * syllable. - */ - - bool try_pref = !!khmer_plan->mask_array[PREF]; - - /* Find base again */ - unsigned int base; - for (base = start; base < end; base++) - if (info[base].khmer_position() >= POS_BASE_C) - { - if (try_pref && base + 1 < end) - { - for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & khmer_plan->mask_array[PREF]) != 0) - { - if (!(_hb_glyph_info_substituted (&info[i]) && - _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) - { - /* Ok, this was a 'pref' candidate but didn't form any. - * Base is around here... */ - base = i; - while (base < end && is_coeng (info[base])) - base++; - info[base].khmer_position() = POS_BASE_C; - - try_pref = false; - } - break; - } - } - - if (start < base && info[base].khmer_position() > POS_BASE_C) - base--; - break; - } - if (base == end && start < base && - is_one_of (info[base - 1], FLAG (OT_ZWJ))) - base--; - if (base < end) - while (start < base && - is_one_of (info[base], (FLAG (OT_N) | FLAG (OT_Coeng)))) - base--; - - - /* o Reorder matras: - * - * If a pre-base matra character had been reordered before applying basic - * features, the glyph can be moved closer to the main consonant based on - * whether half-forms had been formed. Actual position for the matra is - * defined as “after last standalone halant glyph, after initial matra - * position and before the main consonant”. If ZWJ or ZWNJ follow this - * halant, position is moved after it. - */ - - if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ - { - /* If we lost track of base, alas, position before last thingy. */ - unsigned int new_pos = base == end ? base - 2 : base - 1; - - while (new_pos > start && - !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_Coeng))))) - new_pos--; - - /* If we found no Halant we are done. - * Otherwise only proceed if the Halant does - * not belong to the Matra itself! */ - if (is_coeng (info[new_pos]) && - info[new_pos].khmer_position() != POS_PRE_M) - { - /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ - if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) - new_pos++; - } - else - new_pos = start; /* No move. */ - - if (start < new_pos && info[new_pos].khmer_position () != POS_PRE_M) - { - /* Now go see if there's actually any matras... */ - for (unsigned int i = new_pos; i > start; i--) - if (info[i - 1].khmer_position () == POS_PRE_M) - { - unsigned int old_pos = i - 1; - if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ - base--; - - hb_glyph_info_t tmp = info[old_pos]; - memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); - info[new_pos] = tmp; - - /* Note: this merge_clusters() is intentionally *after* the reordering. - * Indic matra reordering is special and tricky... */ - buffer->merge_clusters (new_pos, MIN (end, base + 1)); - - new_pos--; - } - } else { - for (unsigned int i = start; i < base; i++) - if (info[i].khmer_position () == POS_PRE_M) { - buffer->merge_clusters (i, MIN (end, base + 1)); - break; - } - } - } - - - /* o Reorder pre-base-reordering consonants: - * - * If a pre-base-reordering consonant is found, reorder it according to - * the following rules: - */ - - if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */ - { - for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & khmer_plan->mask_array[PREF]) != 0) - { - /* 1. Only reorder a glyph produced by substitution during application - * of the <pref> feature. (Note that a font may shape a Ra consonant with - * the feature generally but block it in certain contexts.) - */ - /* Note: We just check that something got substituted. We don't check that - * the <pref> feature actually did it... - * - * Reorder pref only if it ligated. */ - if (_hb_glyph_info_ligated_and_didnt_multiply (&info[i])) - { - /* - * 2. Try to find a target position the same way as for pre-base matra. - * If it is found, reorder pre-base consonant glyph. - * - * 3. If position is not found, reorder immediately before main - * consonant. - */ - - unsigned int new_pos = base; - while (new_pos > start && - !(is_one_of (info[new_pos - 1], FLAG(OT_M) | FLAG (OT_Coeng)))) - new_pos--; - - /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a - * split matra, it should be reordered to *before* the left part of such matra. */ - if (new_pos > start && info[new_pos - 1].khmer_category() == OT_M) - { - unsigned int old_pos = i; - for (unsigned int j = base + 1; j < old_pos; j++) - if (info[j].khmer_category() == OT_M) - { - new_pos--; - break; - } - } - - if (new_pos > start && is_coeng (info[new_pos - 1])) - { - /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ - if (new_pos < end && is_joiner (info[new_pos])) - new_pos++; - } - - { - unsigned int old_pos = i; - - buffer->merge_clusters (new_pos, old_pos + 1); - hb_glyph_info_t tmp = info[old_pos]; - memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); - info[new_pos] = tmp; - - if (new_pos <= base && base < old_pos) - base++; - } - } - - break; - } - } - - - /* - * Finish off the clusters and go home! - */ - if (hb_options ().uniscribe_bug_compatible) - { - /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala. - * This means, half forms are submerged into the main consonant's cluster. - * This is unnecessary, and makes cursor positioning harder, but that's what - * Uniscribe does. */ - buffer->merge_clusters (start, end); - } -} - - -static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - unsigned int count = buffer->len; - if (unlikely (!count)) return; - - foreach_syllable (buffer, start, end) - final_reordering_syllable (plan, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category); - HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_position); } - static void clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, @@ -828,7 +494,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer = decompose_khmer, compose_khmer, setup_masks_khmer, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh new file mode 100644 index 0000000..6222945 --- /dev/null +++ b/src/hb-ot-shape-complex-khmer.hh @@ -0,0 +1,114 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_KHMER_HH +#define HB_OT_SHAPE_COMPLEX_KHMER_HH + +#include "hb.hh" + +#include "hb-ot-shape-complex-indic.hh" + + +/* buffer var allocations */ +#define khmer_category() indic_category() /* khmer_category_t */ + + +/* Note: This enum is duplicated in the -machine.rl source file. + * Not sure how to avoid duplication. */ +enum khmer_category_t +{ + OT_Robatic = 20, + OT_Xgroup = 21, + OT_Ygroup = 22, + + OT_VAbv = 26, + OT_VBlw = 27, + OT_VPre = 28, + OT_VPst = 29, +}; + +static inline void +set_khmer_properties (hb_glyph_info_t &info) +{ + hb_codepoint_t u = info.codepoint; + unsigned int type = hb_indic_get_categories (u); + khmer_category_t cat = (khmer_category_t) (type & 0x7Fu); + indic_position_t pos = (indic_position_t) (type >> 8); + + + /* + * Re-assign category + * + * These categories are experimentally extracted from what Uniscribe allows. + */ + switch (u) + { + case 0x179Au: + cat = (khmer_category_t) OT_Ra; + break; + + case 0x17CCu: + case 0x17C9u: + case 0x17CAu: + cat = OT_Robatic; + break; + + case 0x17C6u: + case 0x17CBu: + case 0x17CDu: + case 0x17CEu: + case 0x17CFu: + case 0x17D0u: + case 0x17D1u: + cat = OT_Xgroup; + break; + + case 0x17C7u: + case 0x17C8u: + case 0x17DDu: + case 0x17D3u: /* Just guessing. Uniscribe doesn't categorize it. */ + cat = OT_Ygroup; + break; + } + + /* + * Re-assign position. + */ + if (cat == (khmer_category_t) OT_M) + switch ((int) pos) + { + case POS_PRE_C: cat = OT_VPre; break; + case POS_BELOW_C: cat = OT_VBlw; break; + case POS_ABOVE_C: cat = OT_VAbv; break; + case POS_POST_C: cat = OT_VPst; break; + default: assert (0); + }; + + info.khmer_category() = cat; +} + + +#endif /* HB_OT_SHAPE_COMPLEX_KHMER_HH */ diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh index fb67dd4..0c19e4f 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.hh +++ b/src/hb-ot-shape-complex-myanmar-machine.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-myanmar-machine.hh" @@ -283,10 +283,9 @@ static const int myanmar_syllable_machine_en_main = 0; #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -294,11 +293,11 @@ static const int myanmar_syllable_machine_en_main = 0; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 302 "hb-ot-shape-complex-myanmar-machine.hh" +#line 301 "hb-ot-shape-complex-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -306,16 +305,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 115 "hb-ot-shape-complex-myanmar-machine.rl" +#line 114 "hb-ot-shape-complex-myanmar-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 319 "hb-ot-shape-complex-myanmar-machine.hh" +#line 317 "hb-ot-shape-complex-myanmar-machine.hh" { int _slen; int _trans; @@ -329,7 +327,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 333 "hb-ot-shape-complex-myanmar-machine.hh" +#line 331 "hb-ot-shape-complex-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -379,7 +377,7 @@ _eof_trans: #line 90 "hb-ot-shape-complex-myanmar-machine.rl" {te = p;p--;{ found_syllable (non_myanmar_cluster); }} break; -#line 383 "hb-ot-shape-complex-myanmar-machine.hh" +#line 381 "hb-ot-shape-complex-myanmar-machine.hh" } _again: @@ -388,7 +386,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 392 "hb-ot-shape-complex-myanmar-machine.hh" +#line 390 "hb-ot-shape-complex-myanmar-machine.hh" } if ( ++p != pe ) @@ -404,7 +402,7 @@ _again: } -#line 124 "hb-ot-shape-complex-myanmar-machine.rl" +#line 122 "hb-ot-shape-complex-myanmar-machine.rl" } diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl index 0cd84fa..7845a86 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.rl +++ b/src/hb-ot-shape-complex-myanmar-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine myanmar_syllable_machine; @@ -95,10 +95,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -106,7 +105,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -117,7 +116,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index e4214b8..8fdf2f4 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-myanmar-private.hh" +#include "hb-ot-shape-complex-myanmar.hh" /* @@ -36,7 +36,7 @@ basic_features[] = { /* * Basic features. - * These features are applied in order, one at a time, after initial_reordering. + * These features are applied in order, one at a time, after reordering. */ HB_TAG('r','p','h','f'), HB_TAG('p','r','e','f'), @@ -48,13 +48,20 @@ other_features[] = { /* * Other features. - * These features are applied all at once, after final_reordering. + * These features are applied all at once, after clearing syllables. */ HB_TAG('p','r','e','s'), HB_TAG('a','b','v','s'), HB_TAG('b','l','w','s'), HB_TAG('p','s','t','s'), - /* Positioning features, though we don't care about the types. */ +}; +static const hb_tag_t +positioning_features[] = +{ + /* + * Positioning features. + * We don't care about the types. + */ HB_TAG('d','i','s','t'), /* Pre-release version of Windows 8 Myanmar font had abvm,blwm * features. The released Windows 8 version of the font (as well @@ -73,13 +80,13 @@ setup_syllables (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +reorder (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +clear_syllables (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_myanmar (hb_ot_shape_planner_t *plan) @@ -89,27 +96,33 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->add_global_bool_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p')); + + map->add_gsub_pause (reorder); - map->add_gsub_pause (initial_reordering); for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) { - map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); } - map->add_gsub_pause (final_reordering); + + map->add_gsub_pause (clear_syllables); + for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (other_features[i], F_MANUAL_ZWJ); + + for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) + map->enable_feature (positioning_features[i]); } static void override_features_myanmar (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('l','i','g','a')); } @@ -261,8 +274,8 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, +initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_face_t *face HB_UNUSED, hb_buffer_t *buffer, unsigned int start, unsigned int end) { @@ -330,72 +343,71 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, else buffer->next_glyph (); } - buffer->swap_buffers (); } static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { insert_dotted_circles (plan, font, buffer); foreach_syllable (buffer, start, end) initial_reordering_syllable (plan, font->face, buffer, start, end); + + HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category); + HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); } static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { hb_glyph_info_t *info = buffer->info; unsigned int count = buffer->len; - - /* Zero syllables now... */ for (unsigned int i = 0; i < count; i++) info[i].syllable() = 0; - - HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category); - HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); } -/* Uniscribe seems to have a shaper for 'mymr' that is like the - * generic shaper, except that it zeros mark advances GDEF_LATE. */ -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old = +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = { - nullptr, /* collect_features */ - nullptr, /* override_features */ + collect_features_myanmar, + override_features_myanmar, nullptr, /* data_create */ nullptr, /* data_destroy */ nullptr, /* preprocess_text */ nullptr, /* postprocess_glyphs */ - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, nullptr, /* decompose */ nullptr, /* compose */ - nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + setup_masks_myanmar, + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, - true, /* fallback_position */ + HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, + false, /* fallback_position */ }; -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = + +/* Ugly Zawgyi encoding. + * Disable all auto processing. + * https://github.com/harfbuzz/harfbuzz/issues/1162 */ +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi = { - collect_features_myanmar, - override_features_myanmar, + nullptr, /* collect_features */ + nullptr, /* override_features */ nullptr, /* data_create */ nullptr, /* data_destroy */ nullptr, /* preprocess_text */ nullptr, /* postprocess_glyphs */ - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + HB_OT_SHAPE_NORMALIZATION_MODE_NONE, nullptr, /* decompose */ nullptr, /* compose */ - setup_masks_myanmar, - nullptr, /* disable_otl */ + nullptr, /* setup_masks */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, + HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; diff --git a/src/hb-ot-shape-complex-myanmar-private.hh b/src/hb-ot-shape-complex-myanmar.hh index 14d011d..3e9537a 100644 --- a/src/hb-ot-shape-complex-myanmar-private.hh +++ b/src/hb-ot-shape-complex-myanmar.hh @@ -24,12 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_HH +#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" /* buffer var allocations */ @@ -64,42 +64,42 @@ set_myanmar_properties (hb_glyph_info_t &info) { hb_codepoint_t u = info.codepoint; unsigned int type = hb_indic_get_categories (u); - indic_category_t cat = (indic_category_t) (type & 0x7Fu); + unsigned int cat = type & 0x7Fu; indic_position_t pos = (indic_position_t) (type >> 8); /* Myanmar * https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze */ if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu))) - cat = (indic_category_t) OT_VS; + cat = OT_VS; switch (u) { case 0x104Eu: - cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ + cat = OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ break; case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u: case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u: case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu: case 0x25FEu: - cat = (indic_category_t) OT_GB; + cat = OT_GB; break; case 0x1004u: case 0x101Bu: case 0x105Au: - cat = (indic_category_t) OT_Ra; + cat = OT_Ra; break; case 0x1032u: case 0x1036u: - cat = (indic_category_t) OT_A; + cat = OT_A; break; case 0x1039u: - cat = (indic_category_t) OT_H; + cat = OT_H; break; case 0x103Au: - cat = (indic_category_t) OT_As; + cat = OT_As; break; case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u: @@ -107,47 +107,47 @@ set_myanmar_properties (hb_glyph_info_t &info) case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u: case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u: case 0x1097u: case 0x1098u: case 0x1099u: - cat = (indic_category_t) OT_D; + cat = OT_D; break; case 0x1040u: - cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ + cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ break; case 0x103Eu: case 0x1060u: - cat = (indic_category_t) OT_MH; + cat = OT_MH; break; case 0x103Cu: - cat = (indic_category_t) OT_MR; + cat = OT_MR; break; case 0x103Du: case 0x1082u: - cat = (indic_category_t) OT_MW; + cat = OT_MW; break; case 0x103Bu: case 0x105Eu: case 0x105Fu: - cat = (indic_category_t) OT_MY; + cat = OT_MY; break; case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au: case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu: - cat = (indic_category_t) OT_PT; + cat = OT_PT; break; case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u: case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du: case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu: - cat = (indic_category_t) OT_SM; + cat = OT_SM; break; case 0x104Au: case 0x104Bu: - cat = (indic_category_t) OT_P; + cat = OT_P; break; case 0xAA74u: case 0xAA75u: case 0xAA76u: /* https://github.com/roozbehp/unicode-data/issues/3 */ - cat = (indic_category_t) OT_C; + cat = OT_C; break; } @@ -155,17 +155,17 @@ set_myanmar_properties (hb_glyph_info_t &info) { switch ((int) pos) { - case POS_PRE_C: cat = (indic_category_t) OT_VPre; - pos = POS_PRE_M; break; - case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break; - case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break; - case POS_POST_C: cat = (indic_category_t) OT_VPst; break; + case POS_PRE_C: cat = OT_VPre; + pos = POS_PRE_M; break; + case POS_ABOVE_C: cat = OT_VAbv; break; + case POS_BELOW_C: cat = OT_VBlw; break; + case POS_POST_C: cat = OT_VPst; break; } } - info.myanmar_category() = (myanmar_category_t) cat; + info.myanmar_category() = cat; info.myanmar_position() = pos; } -#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */ diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc index 02d78ac..650c980 100644 --- a/src/hb-ot-shape-complex-thai.cc +++ b/src/hb-ot-shape-complex-thai.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" /* Thai / Lao shaper */ @@ -324,9 +324,9 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, } /* Is SARA AM. Decompose and reorder. */ - hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)), - hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))}; - buffer->replace_glyphs (1, 2, decomposed); + hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u)); + _hb_glyph_info_set_continuation (&nikhahit); + buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)); if (unlikely (!buffer->successful)) return; @@ -376,7 +376,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = nullptr, /* decompose */ nullptr, /* compose */ nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, false,/* fallback_position */ diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc deleted file mode 100644 index eaac0bf..0000000 --- a/src/hb-ot-shape-complex-tibetan.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2010,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): Behdad Esfahbod - */ - -#include "hb-ot-shape-complex-private.hh" - - -static const hb_tag_t tibetan_features[] = -{ - HB_TAG('a','b','v','s'), - HB_TAG('b','l','w','s'), - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), - HB_TAG_NONE -}; - -static void -collect_features_tibetan (hb_ot_shape_planner_t *plan) -{ - for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++) - plan->map.add_global_bool_feature (*script_features); -} - - -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan = -{ - collect_features_tibetan, - nullptr, /* override_features */ - nullptr, /* data_create */ - nullptr, /* data_destroy */ - nullptr, /* preprocess_text */ - nullptr, /* postprocess_glyphs */ - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, - nullptr, /* decompose */ - nullptr, /* compose */ - nullptr, /* setup_masks */ - nullptr, /* disable_otl */ - nullptr, /* reorder_marks */ - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, - true, /* fallback_position */ -}; diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh index 0ec805a..c9410e4 100644 --- a/src/hb-ot-shape-complex-use-machine.hh +++ b/src/hb-ot-shape-complex-use-machine.hh @@ -31,232 +31,271 @@ #ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 38 "hb-ot-shape-complex-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 12u, 12u, 1u, 15u, 1u, 1u, 12u, 12u, 0u, 43u, 21u, 21u, 8u, 39u, 8u, 39u, - 1u, 15u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u, 4u, 4u, 13u, 13u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, - 8u, 39u, 1u, 15u, 12u, 12u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u, 42u, 42u, - 1u, 5u, 0 + 12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u, + 1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, + 8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, + 8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u, + 8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, + 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, + 8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u, + 41u, 42u, 42u, 42u, 1u, 5u, 0 }; static const char _use_syllable_machine_key_spans[] = { - 1, 15, 1, 1, 44, 1, 32, 32, - 15, 1, 32, 32, 32, 19, 19, 19, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 9, 1, 1, 32, - 32, 32, 32, 19, 19, 19, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 15, 1, 39, 32, 22, 2, 1, - 5 + 33, 15, 1, 33, 45, 1, 37, 37, + 15, 1, 37, 37, 32, 19, 19, 19, + 32, 32, 32, 37, 37, 37, 37, 37, + 37, 37, 37, 39, 37, 9, 1, 1, + 37, 37, 37, 32, 19, 19, 19, 32, + 32, 32, 37, 37, 37, 37, 37, 37, + 37, 37, 39, 15, 33, 44, 37, 22, + 2, 1, 5 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 2, 18, 20, 22, 67, 69, 102, - 135, 151, 153, 186, 219, 252, 272, 292, - 312, 345, 378, 411, 444, 477, 510, 543, - 576, 609, 642, 675, 708, 718, 720, 722, - 755, 788, 821, 854, 874, 894, 914, 947, - 980, 1013, 1046, 1079, 1112, 1145, 1178, 1211, - 1244, 1277, 1293, 1295, 1335, 1368, 1391, 1394, - 1396 + 0, 34, 50, 52, 86, 132, 134, 172, + 210, 226, 228, 266, 304, 337, 357, 377, + 397, 430, 463, 496, 534, 572, 610, 648, + 686, 724, 762, 800, 840, 878, 888, 890, + 892, 930, 968, 1006, 1039, 1059, 1079, 1099, + 1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388, + 1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675, + 1698, 1701, 1703 }; static const char _use_syllable_machine_indicies[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 4, 2, 3, 2, 6, 5, 7, 8, + 4, 2, 3, 2, 6, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 6, 5, 7, 8, 9, 7, 10, 8, 9, 9, 11, 9, 9, 3, 12, 9, 9, 13, 7, 7, 14, 15, 9, 9, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24, 25, 26, 27, 28, 9, 29, 30, 31, 9, 9, - 9, 32, 9, 34, 33, 36, 35, 35, - 37, 1, 35, 35, 38, 35, 35, 35, - 35, 35, 39, 40, 41, 42, 43, 44, - 45, 46, 40, 47, 39, 48, 49, 50, - 51, 35, 52, 53, 54, 35, 36, 35, - 35, 37, 1, 35, 35, 38, 35, 35, - 35, 35, 35, 55, 40, 41, 42, 43, - 44, 45, 46, 40, 47, 48, 48, 49, - 50, 51, 35, 52, 53, 54, 35, 37, - 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 57, 56, 37, - 56, 36, 35, 35, 37, 1, 35, 35, - 38, 35, 35, 35, 35, 35, 35, 40, - 41, 42, 43, 44, 45, 46, 40, 47, - 48, 48, 49, 50, 51, 35, 52, 53, - 54, 35, 36, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 40, 41, 42, 43, 44, 35, 35, 35, - 35, 35, 35, 49, 50, 51, 35, 52, - 53, 54, 35, 36, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 41, 42, 43, 44, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 52, 53, 54, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 42, 43, 44, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 43, 44, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 44, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 42, 43, 44, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 52, 53, 54, - 35, 36, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 42, 43, 44, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 53, - 54, 35, 36, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 42, 43, 44, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 54, 35, 36, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 41, 42, 43, 44, 35, 35, - 35, 35, 35, 35, 49, 50, 51, 35, - 52, 53, 54, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 41, 42, 43, 44, 35, - 35, 35, 35, 35, 35, 35, 50, 51, - 35, 52, 53, 54, 35, 36, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 41, 42, 43, 44, - 35, 35, 35, 35, 35, 35, 35, 35, - 51, 35, 52, 53, 54, 35, 36, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 40, 41, 42, 43, - 44, 35, 46, 40, 35, 35, 35, 49, - 50, 51, 35, 52, 53, 54, 35, 36, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 40, 41, 42, - 43, 44, 35, 58, 40, 35, 35, 35, - 49, 50, 51, 35, 52, 53, 54, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 40, 41, - 42, 43, 44, 35, 35, 40, 35, 35, - 35, 49, 50, 51, 35, 52, 53, 54, - 35, 36, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 40, - 41, 42, 43, 44, 45, 46, 40, 35, - 35, 35, 49, 50, 51, 35, 52, 53, - 54, 35, 36, 35, 35, 37, 1, 35, - 35, 38, 35, 35, 35, 35, 35, 35, - 40, 41, 42, 43, 44, 45, 46, 40, - 47, 35, 48, 49, 50, 51, 35, 52, - 53, 54, 35, 36, 35, 35, 37, 1, - 35, 35, 38, 35, 35, 35, 35, 35, - 35, 40, 41, 42, 43, 44, 45, 46, - 40, 47, 39, 48, 49, 50, 51, 35, - 52, 53, 54, 35, 60, 59, 59, 59, - 59, 59, 59, 59, 61, 59, 10, 62, - 60, 59, 11, 63, 63, 3, 6, 63, - 63, 64, 63, 63, 63, 63, 63, 65, + 9, 32, 33, 9, 35, 34, 37, 36, + 36, 38, 1, 36, 36, 39, 36, 36, + 36, 36, 36, 40, 41, 42, 43, 44, + 45, 46, 47, 41, 48, 40, 49, 50, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 56, 36, 37, 36, 36, 38, + 1, 36, 36, 39, 36, 36, 36, 36, + 36, 57, 41, 42, 43, 44, 45, 46, + 47, 41, 48, 49, 49, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 56, 36, 38, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, + 59, 58, 38, 58, 37, 36, 36, 38, + 1, 36, 36, 39, 36, 36, 36, 36, + 36, 36, 41, 42, 43, 44, 45, 46, + 47, 41, 48, 49, 49, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 56, 36, 37, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 36, 36, 36, + 36, 36, 36, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 42, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 42, + 43, 44, 45, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 53, 54, 55, + 36, 37, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 43, 44, 45, 36, 37, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 44, 45, + 36, 37, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 45, 36, 37, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 43, 44, 45, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 53, 54, 55, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 43, 44, + 45, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 54, 55, 36, 37, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 43, + 44, 45, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 55, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 42, + 43, 44, 45, 36, 36, 36, 36, 36, + 36, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 42, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 42, 43, 44, + 45, 36, 36, 36, 36, 36, 36, 36, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 42, 36, 37, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 42, 43, 44, 45, 36, + 36, 36, 36, 36, 36, 36, 36, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 42, 36, 37, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 36, 47, 41, + 36, 36, 36, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 42, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 41, 42, + 43, 44, 45, 36, 60, 41, 36, 36, + 36, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 42, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 41, 42, 43, 44, + 45, 36, 36, 41, 36, 36, 36, 50, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 42, 36, 37, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 41, 42, 43, 44, 45, 46, + 47, 41, 36, 36, 36, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 42, 36, 37, 36, 36, 38, 1, 36, + 36, 39, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 46, 47, 41, + 48, 36, 49, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 56, 36, + 38, 58, 58, 58, 58, 58, 58, 37, + 58, 58, 58, 58, 58, 58, 59, 58, + 58, 58, 58, 58, 58, 58, 42, 43, + 44, 45, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 53, 54, 55, 58, + 37, 36, 36, 38, 1, 36, 36, 39, + 36, 36, 36, 36, 36, 36, 41, 42, + 43, 44, 45, 46, 47, 41, 48, 40, + 49, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 56, 36, 62, 61, + 61, 61, 61, 61, 61, 61, 63, 61, + 10, 64, 62, 61, 11, 65, 65, 3, + 6, 65, 65, 66, 65, 65, 65, 65, + 65, 67, 16, 17, 18, 19, 20, 21, + 22, 16, 23, 25, 25, 26, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 33, 65, 11, 65, 65, 3, 6, 65, + 65, 66, 65, 65, 65, 65, 65, 65, 16, 17, 18, 19, 20, 21, 22, 16, - 23, 25, 25, 26, 27, 28, 63, 29, - 30, 31, 63, 11, 63, 63, 3, 6, - 63, 63, 64, 63, 63, 63, 63, 63, - 63, 16, 17, 18, 19, 20, 21, 22, - 16, 23, 25, 25, 26, 27, 28, 63, - 29, 30, 31, 63, 11, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 16, 17, 18, 19, 20, 63, - 63, 63, 63, 63, 63, 26, 27, 28, - 63, 29, 30, 31, 63, 11, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 17, 18, 19, 20, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 29, 30, 31, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 18, 19, - 20, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 19, 20, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 20, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 18, 19, 20, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 29, - 30, 31, 63, 11, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 18, 19, 20, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 30, 31, 63, 11, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 18, 19, 20, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 31, 63, 11, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 17, 18, 19, 20, - 63, 63, 63, 63, 63, 63, 26, 27, - 28, 63, 29, 30, 31, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 17, 18, 19, - 20, 63, 63, 63, 63, 63, 63, 63, - 27, 28, 63, 29, 30, 31, 63, 11, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 17, 18, - 19, 20, 63, 63, 63, 63, 63, 63, - 63, 63, 28, 63, 29, 30, 31, 63, - 11, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 16, 17, - 18, 19, 20, 63, 22, 16, 63, 63, - 63, 26, 27, 28, 63, 29, 30, 31, - 63, 11, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 16, - 17, 18, 19, 20, 63, 66, 16, 63, - 63, 63, 26, 27, 28, 63, 29, 30, - 31, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 16, 17, 18, 19, 20, 63, 63, 16, - 63, 63, 63, 26, 27, 28, 63, 29, - 30, 31, 63, 11, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 16, 17, 18, 19, 20, 21, 22, - 16, 63, 63, 63, 26, 27, 28, 63, - 29, 30, 31, 63, 11, 63, 63, 3, - 6, 63, 63, 64, 63, 63, 63, 63, - 63, 63, 16, 17, 18, 19, 20, 21, - 22, 16, 23, 63, 25, 26, 27, 28, - 63, 29, 30, 31, 63, 3, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 4, 67, 6, 67, 8, - 63, 63, 63, 8, 63, 63, 11, 63, - 63, 3, 6, 63, 63, 64, 63, 63, - 63, 63, 63, 63, 16, 17, 18, 19, - 20, 21, 22, 16, 23, 24, 25, 26, - 27, 28, 63, 29, 30, 31, 63, 11, - 63, 63, 3, 6, 63, 63, 64, 63, - 63, 63, 63, 63, 63, 16, 17, 18, + 23, 25, 25, 26, 27, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 33, 65, + 11, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 65, 65, 65, 65, 65, + 65, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 17, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 17, 18, 19, + 20, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 29, 30, 31, 65, 11, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 18, + 19, 20, 65, 11, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 19, 20, 65, 11, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 20, 65, 11, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 18, 19, 20, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 29, 30, 31, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 18, 19, 20, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 30, 31, 65, 11, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 18, 19, 20, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 31, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 17, 18, 19, + 20, 65, 65, 65, 65, 65, 65, 26, + 27, 28, 65, 29, 30, 31, 65, 65, + 65, 65, 17, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 17, 18, 19, 20, 65, + 65, 65, 65, 65, 65, 65, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 17, 65, 11, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 17, 18, 19, 20, 65, 65, 65, + 65, 65, 65, 65, 65, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 17, 65, + 11, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 65, 22, 16, 65, 65, + 65, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 17, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 16, 17, 18, 19, + 20, 65, 68, 16, 65, 65, 65, 26, + 27, 28, 65, 29, 30, 31, 65, 65, + 65, 65, 17, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 16, 17, 18, 19, 20, 65, + 65, 16, 65, 65, 65, 26, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 17, 65, 11, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 16, 17, 18, 19, 20, 21, 22, 16, + 65, 65, 65, 26, 27, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 17, 65, + 11, 65, 65, 3, 6, 65, 65, 66, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 21, 22, 16, 23, 65, + 25, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 33, 65, 3, 65, + 65, 65, 65, 65, 65, 11, 65, 65, + 65, 65, 65, 65, 4, 65, 65, 65, + 65, 65, 65, 65, 17, 18, 19, 20, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 29, 30, 31, 65, 3, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 4, 69, 6, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 6, 69, + 8, 65, 65, 65, 8, 65, 65, 11, + 65, 65, 3, 6, 65, 65, 66, 65, + 65, 65, 65, 65, 65, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24, 25, - 26, 27, 28, 63, 29, 30, 31, 63, - 69, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 69, 70, 68, 69, - 70, 68, 70, 68, 8, 67, 67, 67, - 8, 67, 0 + 26, 27, 28, 65, 29, 30, 31, 65, + 65, 65, 65, 33, 65, 11, 65, 65, + 3, 6, 65, 65, 66, 65, 65, 65, + 65, 65, 65, 16, 17, 18, 19, 20, + 21, 22, 16, 23, 24, 25, 26, 27, + 28, 65, 29, 30, 31, 65, 65, 65, + 65, 33, 65, 71, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 71, + 72, 70, 71, 72, 70, 72, 70, 8, + 69, 69, 69, 8, 69, 0 }; static const char _use_syllable_machine_trans_targs[] = { - 4, 8, 4, 31, 2, 4, 1, 5, - 6, 4, 28, 4, 49, 50, 51, 53, - 33, 34, 35, 36, 37, 44, 45, 47, - 52, 48, 41, 42, 43, 38, 39, 40, - 56, 4, 4, 4, 4, 7, 0, 27, - 11, 12, 13, 14, 15, 22, 23, 25, - 26, 19, 20, 21, 16, 17, 18, 10, - 4, 9, 24, 4, 29, 30, 4, 4, - 3, 32, 46, 4, 4, 54, 55 + 4, 8, 4, 32, 2, 4, 1, 5, + 6, 4, 29, 4, 51, 52, 53, 55, + 34, 35, 36, 37, 38, 45, 46, 48, + 54, 49, 42, 43, 44, 39, 40, 41, + 58, 50, 4, 4, 4, 4, 7, 0, + 28, 11, 12, 13, 14, 15, 22, 23, + 25, 26, 19, 20, 21, 16, 17, 18, + 27, 10, 4, 9, 24, 4, 30, 31, + 4, 4, 3, 33, 47, 4, 4, 56, + 57 }; static const char _use_syllable_machine_trans_actions[] = { @@ -264,11 +303,12 @@ static const char _use_syllable_machine_trans_actions[] = { 7, 8, 0, 9, 10, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, - 0, 11, 12, 13, 14, 7, 0, 7, - 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 7, - 15, 0, 0, 16, 0, 0, 17, 18, - 0, 3, 0, 19, 20, 0, 0 + 0, 3, 11, 12, 13, 14, 7, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, + 0, 7, 15, 0, 0, 16, 0, 0, + 17, 18, 0, 3, 0, 19, 20, 0, + 0 }; static const char _use_syllable_machine_to_state_actions[] = { @@ -279,7 +319,7 @@ static const char _use_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0 }; static const char _use_syllable_machine_from_state_actions[] = { @@ -290,18 +330,18 @@ static const char _use_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0 }; static const short _use_syllable_machine_eof_trans[] = { - 1, 3, 3, 6, 0, 34, 36, 36, - 57, 57, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 63, 60, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 68, 68, 64, 64, 69, 69, 69, - 68 + 1, 3, 3, 6, 0, 35, 37, 37, + 59, 59, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 59, 37, 62, 65, 62, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 70, 70, 66, 66, 71, + 71, 71, 70 }; static const int use_syllable_machine_start = 4; @@ -315,15 +355,14 @@ static const int use_syllable_machine_en_main = 4; -#line 141 "hb-ot-shape-complex-use-machine.rl" +#line 143 "hb-ot-shape-complex-use-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -331,11 +370,11 @@ static const int use_syllable_machine_en_main = 4; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 339 "hb-ot-shape-complex-use-machine.hh" +#line 378 "hb-ot-shape-complex-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -343,16 +382,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 162 "hb-ot-shape-complex-use-machine.rl" +#line 163 "hb-ot-shape-complex-use-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 356 "hb-ot-shape-complex-use-machine.hh" +#line 394 "hb-ot-shape-complex-use-machine.hh" { int _slen; int _trans; @@ -366,7 +404,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 370 "hb-ot-shape-complex-use-machine.hh" +#line 408 "hb-ot-shape-complex-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -389,59 +427,59 @@ _eof_trans: {te = p+1;} break; case 12: -#line 130 "hb-ot-shape-complex-use-machine.rl" +#line 132 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (independent_cluster); }} break; case 14: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (standard_cluster); }} break; case 9: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (broken_cluster); }} break; case 8: -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (non_cluster); }} break; case 11: -#line 130 "hb-ot-shape-complex-use-machine.rl" +#line 132 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (independent_cluster); }} break; case 15: -#line 131 "hb-ot-shape-complex-use-machine.rl" +#line 133 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (virama_terminated_cluster); }} break; case 13: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (standard_cluster); }} break; case 17: -#line 133 "hb-ot-shape-complex-use-machine.rl" +#line 135 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }} break; case 16: -#line 134 "hb-ot-shape-complex-use-machine.rl" +#line 136 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (numeral_cluster); }} break; case 20: -#line 135 "hb-ot-shape-complex-use-machine.rl" +#line 137 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (symbol_cluster); }} break; case 18: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; case 19: -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (non_cluster); }} break; case 1: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (standard_cluster); }} break; case 4: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; case 2: @@ -459,16 +497,16 @@ _eof_trans: case 3: #line 1 "NONE" {te = p+1;} -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {act = 7;} break; case 10: #line 1 "NONE" {te = p+1;} -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {act = 8;} break; -#line 472 "hb-ot-shape-complex-use-machine.hh" +#line 510 "hb-ot-shape-complex-use-machine.hh" } _again: @@ -477,7 +515,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 481 "hb-ot-shape-complex-use-machine.hh" +#line 519 "hb-ot-shape-complex-use-machine.hh" } if ( ++p != pe ) diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl index 7ec8a7f..7702cd9 100644 --- a/src/hb-ot-shape-complex-use-machine.rl +++ b/src/hb-ot-shape-complex-use-machine.rl @@ -29,7 +29,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine use_syllable_machine; @@ -88,22 +88,19 @@ SMAbv = 41; # SYM_MOD_ABOVE SMBlw = 42; # SYM_MOD_BELOW CS = 43; # CONS_WITH_STACKER +HVM = 44; # HALANT_OR_VOWEL_MODIFIER + +h = H | HVM; # https://github.com/harfbuzz/harfbuzz/issues/1102 # Override: Adhoc ZWJ placement. https://github.com/harfbuzz/harfbuzz/issues/542#issuecomment-353169729 -consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.H.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*; +consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.h.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*; # Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376 medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?; dependent_vowels = VPre* VAbv* VBlw* VPst*; -vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*; +vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*; final_consonants = FAbv* FBlw* FPst* FM?; -virama_terminated_cluster = - (R|CS)? (B | GB) VS? - consonant_modifiers - ZWJ?.H.ZWJ? -; -standard_cluster = - (R|CS)? (B | GB) VS? +complex_syllable_tail = consonant_modifiers medial_consonants dependent_vowels @@ -111,13 +108,18 @@ standard_cluster = final_consonants ; +virama_terminated_cluster = + (R|CS)? (B | GB) VS? + consonant_modifiers + ZWJ?.h.ZWJ? +; +standard_cluster = + (R|CS)? (B | GB) VS? + complex_syllable_tail +; broken_cluster = R? - consonant_modifiers - medial_consonants - dependent_vowels - vowel_modifiers - final_consonants + complex_syllable_tail ; number_joiner_terminated_cluster = N VS? (HN N VS?)* HN; @@ -142,10 +144,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -153,7 +154,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -164,7 +165,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index 1431533..835b95b 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -15,8 +15,10 @@ * UnicodeData.txt does not have a header. */ -#include "hb-ot-shape-complex-use-private.hh" +#include "hb-ot-shape-complex-use.hh" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" #define B USE_B /* BASE */ #define CGJ USE_CGJ /* CGJ */ #define CS USE_CS /* CONS_WITH_STACKER */ @@ -24,6 +26,7 @@ #define GB USE_GB /* BASE_OTHER */ #define H USE_H /* HALANT */ #define HN USE_HN /* HALANT_NUM */ +#define HVM USE_HVM /* HALANT_OR_VOWEL_MODIFIER */ #define IND USE_IND /* BASE_IND */ #define N USE_N /* BASE_NUM */ #define O USE_O /* OTHER */ @@ -54,6 +57,7 @@ #define VMBlw USE_VMBlw #define VMPst USE_VMPst #define VMAbv USE_VMAbv +#pragma GCC diagnostic pop static const USE_TABLE_ELEMENT_TYPE use_table[] = { @@ -101,7 +105,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre, - /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, IND, O, + /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPst, VPst, H, IND, O, /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B, /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FM, O, @@ -134,7 +138,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, - /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, + /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, O, O, VPst, VPst, H, O, O, /* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B, /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -145,7 +149,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B, /* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B, /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst, - /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O, + /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, O, O, /* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O, /* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -178,7 +182,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst, - /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O, + /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, R, O, /* 0D50 */ O, O, O, O, IND, IND, IND, VPst, O, O, O, O, O, O, O, B, /* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 0D70 */ O, O, O, O, O, O, O, O, O, O, IND, IND, IND, IND, IND, IND, @@ -190,11 +194,28 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O, /* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst, - /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, + /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPst, VPre, VPst, VPst, VPst, VPst, /* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, /* 0DF0 */ O, O, VPst, VPst, O, O, O, O, -#define use_offset_0x1000u 1360 +#define use_offset_0x0f18u 1360 + + + /* Tibetan */ + VBlw, VBlw, O, O, O, O, O, O, + /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0F30 */ B, B, B, B, O, FM, O, FM, O, CMAbv, O, O, O, O, VPst, VPre, + /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B, + /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, + /* 0F70 */ O, VBlw, VBlw, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, VMPst, + /* 0F80 */ VBlw, VAbv, VMAbv, VMAbv, VBlw, IND, VMAbv, VMAbv, B, B, B, B, B, SUB, SUB, SUB, + /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O, + /* 0FC0 */ O, O, O, O, O, O, FM, O, + +#define use_offset_0x1000u 1536 /* Myanmar */ @@ -210,7 +231,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst, /* 1090 */ B, B, B, B, B, B, B, B, B, B, VMPst, VMPst, VPst, VAbv, O, O, -#define use_offset_0x1700u 1520 +#define use_offset_0x1700u 1696 /* Tagalog */ @@ -238,12 +259,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre, - /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM, + /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPst, VPst, + /* 17C0 */ VPst, VPre, VPre, VPre, VPst, VPst, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM, /* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O, /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x1900u 1760 +#define use_offset_0x1900u 1936 /* Limbu */ @@ -287,7 +308,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x1b00u 2176 +#define use_offset_0x1b00u 2352 /* Balinese */ @@ -296,7 +317,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, - /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, + /* 1B40 */ VPst, VPst, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O, @@ -319,11 +340,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, + /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv, /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FM, CMBlw, O, O, O, O, O, O, O, O, /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, -#define use_offset_0x1cd0u 2512 +#define use_offset_0x1cd0u 2688 /* Vedic Extensions */ @@ -332,20 +353,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O, /* 1CF0 */ O, O, VMPst, VMPst, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, O, O, O, O, O, O, -#define use_offset_0x1df8u 2560 +#define use_offset_0x1df8u 2736 /* Combining Diacritical Marks Supplement */ O, O, O, FM, O, O, O, O, -#define use_offset_0x2008u 2568 +#define use_offset_0x2008u 2744 /* General Punctuation */ O, O, O, O, ZWNJ, ZWJ, O, O, /* 2010 */ GB, GB, GB, GB, GB, O, O, O, -#define use_offset_0x2060u 2584 +#define use_offset_0x2060u 2760 /* 2060 */ WJ, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -354,20 +375,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O, /* 2080 */ O, O, FM, FM, FM, O, O, O, -#define use_offset_0x20f0u 2624 +#define use_offset_0x20f0u 2800 /* Combining Diacritical Marks for Symbols */ /* 20F0 */ VMAbv, O, O, O, O, O, O, O, -#define use_offset_0x25c8u 2632 +#define use_offset_0x25c8u 2808 /* Geometric Shapes */ O, O, O, O, GB, O, O, O, -#define use_offset_0xa800u 2640 +#define use_offset_0xa800u 2816 /* Syloti Nagri */ @@ -454,7 +475,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst, /* AAF0 */ O, O, O, O, O, VMPst, H, O, -#define use_offset_0xabc0u 3400 +#define use_offset_0xabc0u 3576 /* Meetei Mayek */ @@ -464,14 +485,14 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O, /* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0xfe00u 3464 +#define use_offset_0xfe00u 3640 /* Variation Selectors */ /* FE00 */ VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, -#define use_offset_0x10a00u 3480 +#define use_offset_0x10a00u 3656 /* Kharoshthi */ @@ -482,7 +503,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 10A30 */ B, B, B, B, B, B, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H, /* 10A40 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, -#define use_offset_0x11000u 3560 +#define use_offset_0x11000u 3736 /* Brahmi */ @@ -491,7 +512,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, - /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O, + /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, HVM, O, O, O, O, O, O, O, O, O, /* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N, /* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B, /* 11070 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, HN, @@ -503,15 +524,15 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O, -#define use_offset_0x11100u 3752 +#define use_offset_0x11100u 3928 /* Chakma */ /* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11120 */ B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv, - /* 11130 */ VAbv, VBlw, VBlw, H, VAbv, O, B, B, B, B, B, B, B, B, B, B, + /* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv, + /* 11130 */ VBlw, VAbv, VAbv, H, CMBlw, O, B, B, B, B, B, B, B, B, B, B, /* 11140 */ O, O, O, O, B, VPst, VPst, O, O, O, O, O, O, O, O, O, /* Mahajani */ @@ -526,7 +547,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, - /* 111C0 */ H, B, R, R, O, O, O, O, O, FM, CMBlw, VAbv, VBlw, O, O, O, + /* 111C0 */ H, B, R, R, O, O, O, O, GB, FBlw, CMBlw, VAbv, VBlw, O, O, O, /* 111D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* Sinhala Archaic Numbers */ @@ -541,7 +562,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw, /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O, -#define use_offset_0x11280u 4072 +#define use_offset_0x11280u 4248 /* Multani */ @@ -560,16 +581,16 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Grantha */ - /* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B, + /* 11300 */ VMAbv, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, O, O, B, /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, - /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, + /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, HVM, O, O, /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B, /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, -#define use_offset_0x11400u 4320 +#define use_offset_0x11400u 4496 /* Newa */ @@ -588,11 +609,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11480 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv, + /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPst, VPst, VPst, VPst, VMAbv, /* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O, /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x11580u 4544 +#define use_offset_0x11580u 4720 /* Siddham */ @@ -600,7 +621,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst, - /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H, + /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, VPst, VPst, VMAbv, VMAbv, VMPst, H, /* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O, /* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -635,7 +656,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O, /* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, -#define use_offset_0x11800u 4992 +#define use_offset_0x11800u 5168 /* Dogra */ @@ -645,7 +666,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw, /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O, -#define use_offset_0x11a00u 5056 +#define use_offset_0x11a00u 5232 /* Zanabazar Square */ @@ -664,7 +685,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11A80 */ B, B, B, B, O, O, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O, -#define use_offset_0x11c00u 5216 +#define use_offset_0x11c00u 5392 /* Bhaiksuki */ @@ -673,7 +694,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst, /* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H, - /* 11C40 */ B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11C40 */ B, O, O, O, GB, GB, O, O, O, O, O, O, O, O, O, O, /* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, @@ -685,7 +706,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O, -#define use_offset_0x11d00u 5400 +#define use_offset_0x11d00u 5576 /* Masaram Gondi */ @@ -705,7 +726,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O, /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x11ee0u 5576 +#define use_offset_0x11ee0u 5752 /* Makasar */ @@ -713,7 +734,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O, -}; /* Table items: 5600; occupancy: 73% */ +}; /* Table items: 5776; occupancy: 74% */ USE_TABLE_ELEMENT_TYPE hb_use_get_category (hb_codepoint_t u) @@ -725,6 +746,7 @@ hb_use_get_category (hb_codepoint_t u) if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u]; if (hb_in_range<hb_codepoint_t> (u, 0x0348u, 0x034Fu)) return use_table[u - 0x0348u + use_offset_0x0348u]; if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u]; + if (hb_in_range<hb_codepoint_t> (u, 0x0F18u, 0x0FC7u)) return use_table[u - 0x0F18u + use_offset_0x0f18u]; break; case 0x1u: @@ -782,6 +804,7 @@ hb_use_get_category (hb_codepoint_t u) #undef GB #undef H #undef HN +#undef HVM #undef IND #undef N #undef O diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index 66b9571..2e3f202 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -26,8 +26,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-use-private.hh" -#include "hb-ot-shape-complex-arabic-private.hh" +#include "hb-ot-shape-complex-use.hh" +#include "hb-ot-shape-complex-arabic.hh" +#include "hb-ot-shape-complex-vowel-constraints.hh" /* buffer var allocations */ #define use_category() complex_var_u8_0() @@ -79,14 +80,22 @@ other_features[] = { /* * Other features. - * These features are applied all at once, after reordering. + * These features are applied all at once, after reordering and + * clearing syllables. */ HB_TAG('a','b','v','s'), HB_TAG('b','l','w','s'), HB_TAG('h','a','l','n'), HB_TAG('p','r','e','s'), HB_TAG('p','s','t','s'), - /* Positioning features, though we don't care about the types. */ +}; +static const hb_tag_t +positioning_features[] = +{ + /* + * Positioning features. + * We don't care about the types. + */ HB_TAG('d','i','s','t'), HB_TAG('a','b','v','m'), HB_TAG('b','l','w','m'), @@ -112,6 +121,10 @@ static void reorder (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); +static void +clear_syllables (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_use (hb_ot_shape_planner_t *plan) @@ -122,39 +135,42 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->add_gsub_pause (setup_syllables); /* "Default glyph pre-processing group" */ - map->add_global_bool_feature (HB_TAG('l','o','c','l')); - map->add_global_bool_feature (HB_TAG('c','c','m','p')); - map->add_global_bool_feature (HB_TAG('n','u','k','t')); - map->add_global_bool_feature (HB_TAG('a','k','h','n')); + map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('n','u','k','t')); + map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); /* "Reordering group" */ map->add_gsub_pause (clear_substitution_flags); - map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ); + map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); map->add_gsub_pause (record_rphf); map->add_gsub_pause (clear_substitution_flags); - map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); map->add_gsub_pause (record_pref); /* "Orthographic unit shaping group" */ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) - map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (reorder); + map->add_gsub_pause (clear_syllables); /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) - map->add_feature (arabic_features[i], 1, F_NONE); + map->add_feature (arabic_features[i]); map->add_gsub_pause (nullptr); - /* "Standard typographic presentation" and "Positional feature application" */ + /* "Standard typographic presentation" */ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (other_features[i], F_MANUAL_ZWJ); + + /* "Positional feature application" */ + for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) + map->enable_feature (positioning_features[i]); } struct use_shape_plan_t { - ASSERT_POD (); - hb_mask_t rphf_mask; arabic_shape_plan_t *arabic_plan; @@ -361,7 +377,7 @@ setup_syllables (const hb_ot_shape_plan_t *plan, } static void -clear_substitution_flags (const hb_ot_shape_plan_t *plan, +clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { @@ -373,7 +389,7 @@ clear_substitution_flags (const hb_ot_shape_plan_t *plan, static void record_rphf (const hb_ot_shape_plan_t *plan, - hb_font_t *font, + hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data; @@ -395,8 +411,8 @@ record_rphf (const hb_ot_shape_plan_t *plan, } static void -record_pref (const hb_ot_shape_plan_t *plan, - hb_font_t *font, +record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { hb_glyph_info_t *info = buffer->info; @@ -416,7 +432,8 @@ record_pref (const hb_ot_shape_plan_t *plan, static inline bool is_halant (const hb_glyph_info_t &info) { - return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info); + return (info.use_category() == USE_H || info.use_category() == USE_HVM) && + !_hb_glyph_info_ligated (&info); } static void @@ -433,19 +450,38 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) hb_glyph_info_t *info = buffer->info; -#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB)) +#define POST_BASE_FLAGS64 (FLAG64 (USE_FM) | \ + FLAG64 (USE_FAbv) | \ + FLAG64 (USE_FBlw) | \ + FLAG64 (USE_FPst) | \ + FLAG64 (USE_MAbv) | \ + FLAG64 (USE_MBlw) | \ + FLAG64 (USE_MPst) | \ + FLAG64 (USE_MPre) | \ + FLAG64 (USE_VAbv) | \ + FLAG64 (USE_VBlw) | \ + FLAG64 (USE_VPst) | \ + FLAG64 (USE_VPre) | \ + FLAG64 (USE_VMAbv) | \ + FLAG64 (USE_VMBlw) | \ + FLAG64 (USE_VMPst) | \ + FLAG64 (USE_VMPre)) /* Move things forward. */ if (info[start].use_category() == USE_R && end - start > 1) { - /* Got a repha. Reorder it to after first base, before first halant. */ + /* Got a repha. Reorder it towards the end, but before the first post-base + * glyph. */ for (unsigned int i = start + 1; i < end; i++) - if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i])) + { + bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) || + is_halant (info[i]); + if (is_post_base_glyph || i == end - 1) { - /* If we hit a halant, move before it; otherwise it's a base: move to it's - * place, and shift things in between backward. */ + /* If we hit a post-base glyph, move before it; otherwise move to the + * end. Shift things in between backward. */ - if (is_halant (info[i])) + if (is_post_base_glyph) i--; buffer->merge_clusters (start, i + 1); @@ -455,21 +491,19 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) break; } + } } /* Move things back. */ - unsigned int j = end; + unsigned int j = start; for (unsigned int i = start; i < end; i++) { uint32_t flag = FLAG_UNSAFE (info[i].use_category()); - if ((flag & (BASE_FLAGS)) || is_halant (info[i])) + if (is_halant (info[i])) { - /* If we hit a halant, move after it; otherwise it's a base: move to it's - * place, and shift things in between backward. */ - if (is_halant (info[i])) - j = i + 1; - else - j = i; + /* If we hit a halant, move after it; otherwise move to the beginning, and + * shift things in between forward. */ + j = i + 1; } else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) && /* Only move the first component of a MultipleSubst. */ @@ -536,7 +570,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, else buffer->next_glyph (); } - buffer->swap_buffers (); } @@ -547,36 +580,30 @@ reorder (const hb_ot_shape_plan_t *plan, { insert_dotted_circles (plan, font, buffer); - hb_glyph_info_t *info = buffer->info; - foreach_syllable (buffer, start, end) reorder_syllable (buffer, start, end); - /* Zero syllables now... */ + HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); +} + +static void +clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) info[i].syllable() = 0; - - HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); } -static bool -decompose_use (const hb_ot_shape_normalize_context_t *c, - hb_codepoint_t ab, - hb_codepoint_t *a, - hb_codepoint_t *b) -{ - switch (ab) - { - /* Chakma: - * Special case where the Unicode decomp gives matras in the wrong order - * for cluster validation. - */ - case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true; - case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true; - } - return (bool) c->unicode->decompose (ab, a, b); +static void +preprocess_text_use (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + _hb_preprocess_text_vowel_constraints (plan, buffer, font); } static bool @@ -599,13 +626,13 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use = nullptr, /* override_features */ data_create_use, data_destroy_use, - nullptr, /* preprocess_text */ + preprocess_text_use, nullptr, /* postprocess_glyphs */ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, - decompose_use, + nullptr, /* decompose */ compose_use, setup_masks_use, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-use-private.hh b/src/hb-ot-shape-complex-use.hh index b4bda8b..ab56e1b 100644 --- a/src/hb-ot-shape-complex-use-private.hh +++ b/src/hb-ot-shape-complex-use.hh @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_USE_HH +#define HB_OT_SHAPE_COMPLEX_USE_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" #define USE_TABLE_ELEMENT_TYPE uint8_t @@ -88,10 +88,13 @@ enum use_category_t { USE_VMPre = 23, /* VOWEL_MOD_PRE */ USE_SMAbv = 41, /* SYM_MOD_ABOVE */ USE_SMBlw = 42, /* SYM_MOD_BELOW */ - USE_CS = 43 /* CONS_WITH_STACKER */ + USE_CS = 43, /* CONS_WITH_STACKER */ + + /* https://github.com/harfbuzz/harfbuzz/issues/1102 */ + USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */ }; HB_INTERNAL USE_TABLE_ELEMENT_TYPE hb_use_get_category (hb_codepoint_t u); -#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */ diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc new file mode 100644 index 0000000..0e53258 --- /dev/null +++ b/src/hb-ot-shape-complex-vowel-constraints.cc @@ -0,0 +1,437 @@ +/* == Start of generated functions == */ +/* + * The following functions are generated by running: + * + * ./gen-vowel-constraints.py use Scripts.txt + * + * on files with these headers: + * + * # Copied from https://docs.microsoft.com/en-us/typography/script-development/use + * # On October 23, 2018; with documentd dated 02/07/2018. + * + * # Scripts-11.0.0.txt + * # Date: 2018-02-21, 05:34:31 GMT + */ + +#include "hb-ot-shape-complex-vowel-constraints.hh" + +static void +_output_dotted_circle (hb_buffer_t *buffer) +{ + hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu); + _hb_glyph_info_reset_continuation (&dottedcircle); +} + +static void +_output_with_dotted_circle (hb_buffer_t *buffer) +{ + _output_dotted_circle (buffer); + buffer->next_glyph (); +} + +void +_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_buffer_t *buffer, + hb_font_t *font HB_UNUSED) +{ + /* UGLY UGLY UGLY business of adding dotted-circle in the middle of + * vowel-sequences that look like another vowel. Data for each script + * collected from the USE script development spec. + * + * https://github.com/harfbuzz/harfbuzz/issues/1019 + */ + bool processed = false; + buffer->clear_output (); + unsigned int count = buffer->len; + switch ((unsigned) buffer->props.script) + { + case HB_SCRIPT_DEVANAGARI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0905u: + switch (buffer->cur (1).codepoint) + { + case 0x093Au: case 0x093Bu: case 0x093Eu: case 0x0945u: + case 0x0946u: case 0x0949u: case 0x094Au: case 0x094Bu: + case 0x094Cu: case 0x094Fu: case 0x0956u: case 0x0957u: + matched = true; + break; + } + break; + case 0x0906u: + switch (buffer->cur (1).codepoint) + { + case 0x093Au: case 0x0945u: case 0x0946u: case 0x0947u: + case 0x0948u: + matched = true; + break; + } + break; + case 0x0909u: + matched = 0x0941u == buffer->cur (1).codepoint; + break; + case 0x090Fu: + switch (buffer->cur (1).codepoint) + { + case 0x0945u: case 0x0946u: case 0x0947u: + matched = true; + break; + } + break; + case 0x0930u: + if (0x094Du == buffer->cur (1).codepoint && + buffer->idx + 2 < count && + 0x0907u == buffer->cur (2).codepoint) + { + buffer->next_glyph (); + buffer->next_glyph (); + _output_dotted_circle (buffer); + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_BENGALI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0985u: + matched = 0x09BEu == buffer->cur (1).codepoint; + break; + case 0x098Bu: + matched = 0x09C3u == buffer->cur (1).codepoint; + break; + case 0x098Cu: + matched = 0x09E2u == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_GURMUKHI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0A05u: + switch (buffer->cur (1).codepoint) + { + case 0x0A3Eu: case 0x0A48u: case 0x0A4Cu: + matched = true; + break; + } + break; + case 0x0A72u: + switch (buffer->cur (1).codepoint) + { + case 0x0A3Fu: case 0x0A40u: case 0x0A47u: + matched = true; + break; + } + break; + case 0x0A73u: + switch (buffer->cur (1).codepoint) + { + case 0x0A41u: case 0x0A42u: case 0x0A4Bu: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_GUJARATI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0A85u: + switch (buffer->cur (1).codepoint) + { + case 0x0ABEu: case 0x0AC5u: case 0x0AC7u: case 0x0AC8u: + case 0x0AC9u: case 0x0ACBu: case 0x0ACCu: + matched = true; + break; + } + break; + case 0x0AC5u: + matched = 0x0ABEu == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_ORIYA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0B05u: + matched = 0x0B3Eu == buffer->cur (1).codepoint; + break; + case 0x0B0Fu: case 0x0B13u: + matched = 0x0B57u == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_TELUGU: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0C12u: + switch (buffer->cur (1).codepoint) + { + case 0x0C4Cu: case 0x0C55u: + matched = true; + break; + } + break; + case 0x0C3Fu: case 0x0C46u: case 0x0C4Au: + matched = 0x0C55u == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_KANNADA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0C89u: case 0x0C8Bu: + matched = 0x0CBEu == buffer->cur (1).codepoint; + break; + case 0x0C92u: + matched = 0x0CCCu == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_MALAYALAM: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0D07u: case 0x0D09u: + matched = 0x0D57u == buffer->cur (1).codepoint; + break; + case 0x0D0Eu: + matched = 0x0D46u == buffer->cur (1).codepoint; + break; + case 0x0D12u: + switch (buffer->cur (1).codepoint) + { + case 0x0D3Eu: case 0x0D57u: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_SINHALA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x0D85u: + switch (buffer->cur (1).codepoint) + { + case 0x0DCFu: case 0x0DD0u: case 0x0DD1u: + matched = true; + break; + } + break; + case 0x0D8Bu: case 0x0D8Fu: case 0x0D94u: + matched = 0x0DDFu == buffer->cur (1).codepoint; + break; + case 0x0D8Du: + matched = 0x0DD8u == buffer->cur (1).codepoint; + break; + case 0x0D91u: + switch (buffer->cur (1).codepoint) + { + case 0x0DCAu: case 0x0DD9u: case 0x0DDAu: case 0x0DDCu: + case 0x0DDDu: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_BRAHMI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x11005u: + matched = 0x11038u == buffer->cur (1).codepoint; + break; + case 0x1100Bu: + matched = 0x1103Eu == buffer->cur (1).codepoint; + break; + case 0x1100Fu: + matched = 0x11042u == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_KHUDAWADI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x112B0u: + switch (buffer->cur (1).codepoint) + { + case 0x112E0u: case 0x112E5u: case 0x112E6u: case 0x112E7u: + case 0x112E8u: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_TIRHUTA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x11481u: + matched = 0x114B0u == buffer->cur (1).codepoint; + break; + case 0x1148Bu: case 0x1148Du: + matched = 0x114BAu == buffer->cur (1).codepoint; + break; + case 0x114AAu: + switch (buffer->cur (1).codepoint) + { + case 0x114B5u: case 0x114B6u: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_MODI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x11600u: case 0x11601u: + switch (buffer->cur (1).codepoint) + { + case 0x11639u: case 0x1163Au: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_TAKRI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur ().codepoint) + { + case 0x11680u: + switch (buffer->cur (1).codepoint) + { + case 0x116ADu: case 0x116B4u: case 0x116B5u: + matched = true; + break; + } + break; + case 0x11686u: + matched = 0x116B2u == buffer->cur (1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + default: + break; + } + if (processed) + { + if (buffer->idx < count) + buffer->next_glyph (); + buffer->swap_buffers (); + } +} + +/* == End of generated functions == */ diff --git a/src/hb-aat-layout-private.hh b/src/hb-ot-shape-complex-vowel-constraints.hh index ce75c8e..d9082d4 100644 --- a/src/hb-aat-layout-private.hh +++ b/src/hb-ot-shape-complex-vowel-constraints.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2017 Google, Inc. + * Copyright © 2018 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,20 +24,16 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_AAT_LAYOUT_PRIVATE_HH -#define HB_AAT_LAYOUT_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH +#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" -#include "hb-open-type-private.hh" - - -HB_INTERNAL void -hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer); +#include "hb-ot-shape-complex.hh" HB_INTERNAL void -hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer); +_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font); -#endif /* HB_AAT_LAYOUT_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */ diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex.hh index ed6849b..a2499de 100644 --- a/src/hb-ot-shape-complex-private.hh +++ b/src/hb-ot-shape-complex.hh @@ -24,14 +24,14 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_HH +#define HB_OT_SHAPE_COMPLEX_HH -#include "hb-private.hh" - -#include "hb-ot-shape-private.hh" -#include "hb-ot-shape-normalize-private.hh" +#include "hb.hh" +#include "hb-ot-layout.hh" +#include "hb-ot-shape.hh" +#include "hb-ot-shape-normalize.hh" /* buffer var allocations, used by complex shapers */ @@ -57,9 +57,8 @@ enum hb_ot_shape_zero_width_marks_type_t { HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ - HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \ + HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \ HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ - HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \ HB_COMPLEX_SHAPER_IMPLEMENT (use) \ /* ^--- Add new shapers here */ @@ -69,7 +68,7 @@ struct hb_ot_complex_shaper_t /* collect_features() * Called during shape_plan(). * Shapers should use plan->map to add their features and callbacks. - * May be nullptr. + * May be NULL. */ void (*collect_features) (hb_ot_shape_planner_t *plan); @@ -77,7 +76,7 @@ struct hb_ot_complex_shaper_t * Called during shape_plan(). * Shapers should use plan->map to override features and add callbacks after * common features are added. - * May be nullptr. + * May be NULL. */ void (*override_features) (hb_ot_shape_planner_t *plan); @@ -93,7 +92,7 @@ struct hb_ot_complex_shaper_t * Called when the shape_plan is being destroyed. * plan->data is passed here for destruction. * If nullptr is returned, means a plan failure. - * May be nullptr. + * May be NULL. */ void (*data_destroy) (void *data); @@ -101,7 +100,7 @@ struct hb_ot_complex_shaper_t /* preprocess_text() * Called during shape(). * Shapers can use to modify text before shaping starts. - * May be nullptr. + * May be NULL. */ void (*preprocess_text) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -110,7 +109,7 @@ struct hb_ot_complex_shaper_t /* postprocess_glyphs() * Called during shape(). * Shapers can use to modify glyphs after shaping ends. - * May be nullptr. + * May be NULL. */ void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -121,7 +120,7 @@ struct hb_ot_complex_shaper_t /* decompose() * Called during shape()'s normalization. - * May be nullptr. + * May be NULL. */ bool (*decompose) (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t ab, @@ -130,7 +129,7 @@ struct hb_ot_complex_shaper_t /* compose() * Called during shape()'s normalization. - * May be nullptr. + * May be NULL. */ bool (*compose) (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t a, @@ -141,24 +140,22 @@ struct hb_ot_complex_shaper_t * Called during shape(). * Shapers should use map to get feature masks and set on buffer. * Shapers may NOT modify characters. - * May be nullptr. + * May be NULL. */ void (*setup_masks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font); - /* disable_otl() - * Called during shape(). - * If set and returns true, GDEF/GSUB/GPOS of the font are ignored - * and fallback operations used. - * May be nullptr. + /* gpos_tag() + * If not HB_TAG_NONE, then must match found GPOS script tag for + * GPOS to be applied. Otherwise, fallback positioning will be used. */ - bool (*disable_otl) (const hb_ot_shape_plan_t *plan); + hb_tag_t gpos_tag; /* reorder_marks() * Called during shape(). * Shapers can use to modify ordering of combining marks. - * May be nullptr. + * May be NULL. */ void (*reorder_marks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -234,25 +231,12 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) return &_hb_ot_complex_shaper_hangul; - /* Unicode-2.0 additions */ - case HB_SCRIPT_TIBETAN: - - return &_hb_ot_complex_shaper_tibetan; - - /* Unicode-1.1 additions */ case HB_SCRIPT_HEBREW: return &_hb_ot_complex_shaper_hebrew; - /* ^--- Add new shapers here */ - -#if 0 - /* Unicode-4.1 additions */ - case HB_SCRIPT_NEW_TAI_LUE: -#endif - /* Unicode-1.1 additions */ case HB_SCRIPT_BENGALI: case HB_SCRIPT_DEVANAGARI: @@ -270,41 +254,43 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. - * Note that for some simple scripts, there may not be *any* - * GSUB/GPOS needed, so there may be no scripts found! */ + * + * If it's indy3 tag, send to USE. */ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || planner->map.chosen_script[0] == HB_TAG ('l','a','t','n')) return &_hb_ot_complex_shaper_default; + else if ((planner->map.chosen_script[0] & 0x000000FF) == '3') + return &_hb_ot_complex_shaper_use; else return &_hb_ot_complex_shaper_indic; case HB_SCRIPT_KHMER: - /* A number of Khmer fonts in the wild don't have a 'pref' feature, - * and as such won't shape properly via the Indic shaper; - * however, they typically have 'liga' / 'clig' features that implement - * the necessary "reordering" by means of ligature substitutions. - * So we send such pref-less fonts through the generic shaper instead. */ - if (planner->map.found_script[0] && - hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB, - planner->map.script_index[0], - planner->map.language_index[0], - HB_TAG ('p','r','e','f'), - nullptr)) return &_hb_ot_complex_shaper_khmer; - else - return &_hb_ot_complex_shaper_default; case HB_SCRIPT_MYANMAR: - if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2')) - return &_hb_ot_complex_shaper_myanmar; - else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r')) - return &_hb_ot_complex_shaper_myanmar_old; - else + /* If the designer designed the font for the 'DFLT' script, + * (or we ended up arbitrarily pick 'latn'), use the default shaper. + * Otherwise, use the specific shaper. + * + * If designer designed for 'mymr' tag, also send to default + * shaper. That's tag used from before Myanmar shaping spec + * was developed. The shaping spec uses 'mym2' tag. */ + if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || + planner->map.chosen_script[0] == HB_TAG ('l','a','t','n') || + planner->map.chosen_script[0] == HB_TAG ('m','y','m','r')) return &_hb_ot_complex_shaper_default; + else + return &_hb_ot_complex_shaper_myanmar; + + + /* https://github.com/harfbuzz/harfbuzz/issues/1162 */ + case HB_SCRIPT_MYANMAR_ZAWGYI: + + return &_hb_ot_complex_shaper_myanmar_zawgyi; /* Unicode-2.0 additions */ - //case HB_SCRIPT_TIBETAN: + case HB_SCRIPT_TIBETAN: /* Unicode-3.0 additions */ //case HB_SCRIPT_MONGOLIAN: @@ -372,9 +358,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-8.0 additions */ case HB_SCRIPT_AHOM: - //case HB_SCRIPT_MULTANI: /* Unicode-9.0 additions */ + //case HB_SCRIPT_ADLAM: case HB_SCRIPT_BHAIKSUKI: case HB_SCRIPT_MARCHEN: case HB_SCRIPT_NEWA: @@ -387,7 +373,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-11.0 additions */ case HB_SCRIPT_DOGRA: case HB_SCRIPT_GUNJALA_GONDI: + //case HB_SCRIPT_HANIFI_ROHINGYA: case HB_SCRIPT_MAKASAR: + //case HB_SCRIPT_SOGDIAN: /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. @@ -403,4 +391,4 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) } -#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_HH */ diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index fbf31ab..f9d4a75 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-fallback-private.hh" -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-shape-fallback.hh" +#include "hb-kern.hh" static unsigned int recategorize_combining_class (hb_codepoint_t u, @@ -162,9 +162,9 @@ recategorize_combining_class (hb_codepoint_t u, } void -_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +_hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -180,19 +180,25 @@ _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *pla static void zero_mark_advances (hb_buffer_t *buffer, unsigned int start, - unsigned int end) + unsigned int end, + bool adjust_offsets_when_zeroing) { hb_glyph_info_t *info = buffer->info; for (unsigned int i = start; i < end; i++) if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) { + if (adjust_offsets_when_zeroing) + { + buffer->pos[i].x_offset -= buffer->pos[i].x_advance; + buffer->pos[i].y_offset -= buffer->pos[i].y_advance; + } buffer->pos[i].x_advance = 0; buffer->pos[i].y_advance = 0; } } static inline void -position_mark (const hb_ot_shape_plan_t *plan, +position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer, hb_glyph_extents_t &base_extents, @@ -303,7 +309,8 @@ position_around_base (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer, unsigned int base, - unsigned int end) + unsigned int end, + bool adjust_offsets_when_zeroing) { hb_direction_t horiz_dir = HB_DIRECTION_INVALID; @@ -314,11 +321,15 @@ position_around_base (const hb_ot_shape_plan_t *plan, &base_extents)) { /* If extents don't work, zero marks and go home. */ - zero_mark_advances (buffer, base + 1, end); + zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing); return; } - base_extents.x_bearing += buffer->pos[base].x_offset; base_extents.y_bearing += buffer->pos[base].y_offset; + /* Use horizontal advance for horizontal positioning. + * Generally a better idea. Also works for zero-ink glyphs. See: + * https://github.com/harfbuzz/harfbuzz/issues/1532 */ + base_extents.x_bearing = 0; + base_extents.width = font->get_glyph_h_advance (buffer->info[base].codepoint); unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]); /* Use integer for num_lig_components such that it doesn't convert to unsigned @@ -394,7 +405,8 @@ position_cluster (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer, unsigned int start, - unsigned int end) + unsigned int end, + bool adjust_offsets_when_zeroing) { if (end - start < 2) return; @@ -410,16 +422,17 @@ position_cluster (const hb_ot_shape_plan_t *plan, if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j]))) break; - position_around_base (plan, font, buffer, i, j); + position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing); i = j - 1; } } void -_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +_hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer, + bool adjust_offsets_when_zeroing) { _hb_buffer_assert_gsubgpos_vars (buffer); @@ -428,81 +441,66 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, hb_glyph_info_t *info = buffer->info; for (unsigned int i = 1; i < count; i++) if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) { - position_cluster (plan, font, buffer, start, i); + position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing); start = i; } - position_cluster (plan, font, buffer, start, count); + position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing); } -/* Performs old-style TrueType kerning. */ +struct hb_ot_shape_fallback_kern_driver_t +{ + hb_ot_shape_fallback_kern_driver_t (hb_font_t *font_, + hb_buffer_t *buffer) : + font (font_), direction (buffer->props.direction) {} + + hb_position_t get_kerning (hb_codepoint_t first, hb_codepoint_t second) const + { + hb_position_t kern = 0; + font->get_glyph_kerning_for_direction (first, second, + direction, + &kern, &kern); + return kern; + } + + hb_font_t *font; + hb_direction_t direction; +}; + +/* Performs font-assisted kerning. */ void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer) + hb_buffer_t *buffer) { - if (!plan->has_kern) return; - - OT::hb_ot_apply_context_t c (1, font, buffer); - c.set_lookup_mask (plan->kern_mask); - c.set_lookup_props (OT::LookupFlag::IgnoreMarks); - OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; - skippy_iter.init (&c); - - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - hb_glyph_position_t *pos = buffer->pos; - for (unsigned int idx = 0; idx < count;) - { - skippy_iter.reset (idx, 1); - if (!skippy_iter.next ()) - { - idx++; - continue; - } + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? + !font->has_glyph_h_kerning_func () : + !font->has_glyph_v_kerning_func ()) + return; - hb_position_t x_kern, y_kern; - font->get_glyph_kerning_for_direction (info[idx].codepoint, - info[skippy_iter.idx].codepoint, - buffer->props.direction, - &x_kern, &y_kern); + bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); - if (x_kern) - { - hb_position_t kern1 = x_kern >> 1; - hb_position_t kern2 = x_kern - kern1; - pos[idx].x_advance += kern1; - pos[skippy_iter.idx].x_advance += kern2; - pos[skippy_iter.idx].x_offset += kern2; - buffer->unsafe_to_break (idx, skippy_iter.idx + 1); - } + if (reverse) + buffer->reverse (); - if (y_kern) - { - hb_position_t kern1 = y_kern >> 1; - hb_position_t kern2 = y_kern - kern1; - pos[idx].y_advance += kern1; - pos[skippy_iter.idx].y_advance += kern2; - pos[skippy_iter.idx].y_offset += kern2; - buffer->unsafe_to_break (idx, skippy_iter.idx + 1); - } + hb_ot_shape_fallback_kern_driver_t driver (font, buffer); + OT::hb_kern_machine_t<hb_ot_shape_fallback_kern_driver_t> machine (driver); + machine.kern (font, buffer, plan->kern_mask, false); - idx = skippy_iter.idx; - } + if (reverse) + buffer->reverse (); } /* Adjusts width of various spaces. */ void -_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, +_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer) { - if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) - return; - hb_glyph_info_t *info = buffer->info; hb_glyph_position_t *pos = buffer->pos; + bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i])) @@ -523,27 +521,40 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, case t::SPACE_EM_5: case t::SPACE_EM_6: case t::SPACE_EM_16: - pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type; + if (horizontal) + pos[i].x_advance = +(font->x_scale + ((int) space_type)/2) / (int) space_type; + else + pos[i].y_advance = -(font->y_scale + ((int) space_type)/2) / (int) space_type; break; case t::SPACE_4_EM_18: - pos[i].x_advance = (int64_t) font->x_scale * 4 / 18; + if (horizontal) + pos[i].x_advance = (int64_t) +font->x_scale * 4 / 18; + else + pos[i].y_advance = (int64_t) -font->y_scale * 4 / 18; break; case t::SPACE_FIGURE: for (char u = '0'; u <= '9'; u++) if (font->get_nominal_glyph (u, &glyph)) { - pos[i].x_advance = font->get_glyph_h_advance (glyph); + if (horizontal) + pos[i].x_advance = font->get_glyph_h_advance (glyph); + else + pos[i].y_advance = font->get_glyph_v_advance (glyph); break; } break; case t::SPACE_PUNCTUATION: - if (font->get_nominal_glyph ('.', &glyph)) - pos[i].x_advance = font->get_glyph_h_advance (glyph); - else if (font->get_nominal_glyph (',', &glyph)) - pos[i].x_advance = font->get_glyph_h_advance (glyph); + if (font->get_nominal_glyph ('.', &glyph) || + font->get_nominal_glyph (',', &glyph)) + { + if (horizontal) + pos[i].x_advance = font->get_glyph_h_advance (glyph); + else + pos[i].y_advance = font->get_glyph_v_advance (glyph); + } break; case t::SPACE_NARROW: @@ -552,7 +563,10 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, * However, in my testing, many fonts have their regular space being about that * size. To me, a percentage of the space width makes more sense. Half is as * good as any. */ - pos[i].x_advance /= 2; + if (horizontal) + pos[i].x_advance /= 2; + else + pos[i].y_advance /= 2; break; } } diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback.hh index e134224..5faf5f2 100644 --- a/src/hb-ot-shape-fallback-private.hh +++ b/src/hb-ot-shape-fallback.hh @@ -24,21 +24,22 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_FALLBACK_PRIVATE_HH -#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH +#ifndef HB_OT_SHAPE_FALLBACK_HH +#define HB_OT_SHAPE_FALLBACK_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape.hh" -HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer, + bool adjust_offsets_when_zeroing); -HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, @@ -50,4 +51,4 @@ HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer); -#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_FALLBACK_HH */ diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc index 358450e..82bb24b 100644 --- a/src/hb-ot-shape-normalize.cc +++ b/src/hb-ot-shape-normalize.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-normalize-private.hh" -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape-normalize.hh" +#include "hb-ot-shape-complex.hh" +#include "hb-ot-shape.hh" /* @@ -213,17 +213,19 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor } static inline void -handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit) +handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, + unsigned int end, + bool short_circuit HB_UNUSED) { /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ hb_buffer_t * const buffer = c->buffer; hb_font_t * const font = c->font; for (; buffer->idx < end - 1 && buffer->successful;) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { - /* The next two lines are some ugly lines... But work. */ if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index())) { - buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); + hb_codepoint_t unicode = buffer->cur().codepoint; + buffer->replace_glyphs (2, 1, &unicode); } else { @@ -264,15 +266,6 @@ decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned decompose_current_character (c, short_circuit); } -static inline void -decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit) -{ - if (likely (c->buffer->idx + 1 == end)) - decompose_current_character (c, might_short_circuit); - else - decompose_multi_char_cluster (c, end, always_short_circuit); -} - static int compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) @@ -294,6 +287,16 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, _hb_buffer_assert_unicode_vars (buffer); hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference; + if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_AUTO) + { + if (plan->has_gpos_mark) + // https://github.com/harfbuzz/harfbuzz/issues/653#issuecomment-423905920 + //mode = HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED; + mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; + else + mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; + } + const hb_ot_shape_normalize_context_t c = { plan, buffer, @@ -318,105 +321,81 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, /* First round, decompose */ - buffer->clear_output (); - count = buffer->len; - for (buffer->idx = 0; buffer->idx < count && buffer->successful;) + bool all_simple = true; { - unsigned int end; - for (end = buffer->idx + 1; end < count; end++) - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) - break; + buffer->clear_output (); + count = buffer->len; + buffer->idx = 0; + do + { + unsigned int end; + for (end = buffer->idx + 1; end < count; end++) + if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) + break; - decompose_cluster (&c, end, might_short_circuit, always_short_circuit); - } - buffer->swap_buffers (); + if (end < count) + end--; /* Leave one base for the marks to cluster with. */ + /* From idx to end are simple clusters. */ + if (might_short_circuit) + { + unsigned int done = font->get_nominal_glyphs (end - buffer->idx, + &buffer->cur().codepoint, + sizeof (buffer->info[0]), + &buffer->cur().glyph_index(), + sizeof (buffer->info[0])); + buffer->next_glyphs (done); + } + while (buffer->idx < end && buffer->successful) + decompose_current_character (&c, might_short_circuit); - /* Second round, reorder (inplace) */ + if (buffer->idx == count || !buffer->successful) + break; - count = buffer->len; - for (unsigned int i = 0; i < count; i++) - { - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) - continue; + all_simple = false; - unsigned int end; - for (end = i + 1; end < count; end++) - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) - break; + /* Find all the marks now. */ + for (end = buffer->idx + 1; end < count; end++) + if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))) + break; - /* We are going to do a O(n^2). Only do this if the sequence is short. */ - if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) { - i = end; - continue; + /* idx to end is one non-simple cluster. */ + decompose_multi_char_cluster (&c, end, always_short_circuit); } - - buffer->sort (i, end, compare_combining_class); - - if (plan->shaper->reorder_marks) - plan->shaper->reorder_marks (plan, buffer, i, end); - - i = end; + while (buffer->idx < count && buffer->successful); + buffer->swap_buffers (); } - if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE || - mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED) - return; - - /* Third round, recompose */ - - /* As noted in the comment earlier, we don't try to combine - * ccc=0 chars with their previous Starter. */ + /* Second round, reorder (inplace) */ - buffer->clear_output (); - count = buffer->len; - unsigned int starter = 0; - buffer->next_glyph (); - while (buffer->idx < count && buffer->successful) + if (!all_simple) { - hb_codepoint_t composed, glyph; - if (/* We don't try to compose a non-mark character with it's preceding starter. - * This is both an optimization to avoid trying to compose every two neighboring - * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul - * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ - HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) + count = buffer->len; + for (unsigned int i = 0; i < count; i++) { - if (/* If there's anything between the starter and this char, they should have CCC - * smaller than this character's. */ - (starter == buffer->out_len - 1 || - info_cc (buffer->prev()) < info_cc (buffer->cur())) && - /* And compose. */ - c.compose (&c, - buffer->out_info[starter].codepoint, - buffer->cur().codepoint, - &composed) && - /* And the font has glyph for the composite. */ - font->get_nominal_glyph (composed, &glyph)) - { - /* Composes. */ - buffer->next_glyph (); /* Copy to out-buffer. */ - if (unlikely (!buffer->successful)) - return; - buffer->merge_out_clusters (starter, buffer->out_len); - buffer->out_len--; /* Remove the second composable. */ - /* Modify starter and carry on. */ - buffer->out_info[starter].codepoint = composed; - buffer->out_info[starter].glyph_index() = glyph; - _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) + continue; + + unsigned int end; + for (end = i + 1; end < count; end++) + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) + break; + /* We are going to do a O(n^2). Only do this if the sequence is short. */ + if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) { + i = end; continue; } - } - /* Blocked, or doesn't compose. */ - buffer->next_glyph (); + buffer->sort (i, end, compare_combining_class); - if (info_cc (buffer->prev()) == 0) - starter = buffer->out_len - 1; - } - buffer->swap_buffers (); + if (plan->shaper->reorder_marks) + plan->shaper->reorder_marks (plan, buffer, i, end); + i = end; + } + } if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ) { /* For all CGJ, check if it prevented any reordering at all. @@ -430,4 +409,63 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, _hb_glyph_info_unhide (&buffer->info[i]); } } + + + /* Third round, recompose */ + + if (!all_simple && + (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS || + mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT)) + { + /* As noted in the comment earlier, we don't try to combine + * ccc=0 chars with their previous Starter. */ + + buffer->clear_output (); + count = buffer->len; + unsigned int starter = 0; + buffer->next_glyph (); + while (buffer->idx < count && buffer->successful) + { + hb_codepoint_t composed, glyph; + if (/* We don't try to compose a non-mark character with it's preceding starter. + * This is both an optimization to avoid trying to compose every two neighboring + * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul + * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ + HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) + { + if (/* If there's anything between the starter and this char, they should have CCC + * smaller than this character's. */ + (starter == buffer->out_len - 1 || + info_cc (buffer->prev()) < info_cc (buffer->cur())) && + /* And compose. */ + c.compose (&c, + buffer->out_info[starter].codepoint, + buffer->cur().codepoint, + &composed) && + /* And the font has glyph for the composite. */ + font->get_nominal_glyph (composed, &glyph)) + { + /* Composes. */ + buffer->next_glyph (); /* Copy to out-buffer. */ + if (unlikely (!buffer->successful)) + return; + buffer->merge_out_clusters (starter, buffer->out_len); + buffer->out_len--; /* Remove the second composable. */ + /* Modify starter and carry on. */ + buffer->out_info[starter].codepoint = composed; + buffer->out_info[starter].glyph_index() = glyph; + _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); + + continue; + } + } + + /* Blocked, or doesn't compose. */ + buffer->next_glyph (); + + if (info_cc (buffer->prev()) == 0) + starter = buffer->out_len - 1; + } + buffer->swap_buffers (); + } } diff --git a/src/hb-ot-shape-normalize-private.hh b/src/hb-ot-shape-normalize.hh index c744e26..04f1a80 100644 --- a/src/hb-ot-shape-normalize-private.hh +++ b/src/hb-ot-shape-normalize.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_NORMALIZE_PRIVATE_HH -#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH +#ifndef HB_OT_SHAPE_NORMALIZE_HH +#define HB_OT_SHAPE_NORMALIZE_HH -#include "hb-private.hh" +#include "hb.hh" /* buffer var allocations, used during the normalization process */ @@ -38,10 +38,11 @@ struct hb_ot_shape_plan_t; enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_NONE, HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED, - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */ - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */ + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* Never composes base-to-base */ + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */ - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS + HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, /* See hb-ot-shape-normalize.cc for logic. */ + HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_AUTO }; HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper, @@ -66,4 +67,4 @@ struct hb_ot_shape_normalize_context_t }; -#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_NORMALIZE_HH */ diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh deleted file mode 100644 index d689826..0000000 --- a/src/hb-ot-shape-private.hh +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright © 2010 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): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_PRIVATE_HH -#define HB_OT_SHAPE_PRIVATE_HH - -#include "hb-private.hh" - -#include "hb-ot-map-private.hh" -#include "hb-ot-layout-private.hh" - - - -struct hb_ot_shape_plan_t -{ - hb_segment_properties_t props; - const struct hb_ot_complex_shaper_t *shaper; - hb_ot_map_t map; - const void *data; - hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask; - hb_mask_t kern_mask; - unsigned int has_frac : 1; - unsigned int has_kern : 1; - unsigned int has_mark : 1; - - inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const - { - unsigned int table_index; - switch (table_tag) { - case HB_OT_TAG_GSUB: table_index = 0; break; - case HB_OT_TAG_GPOS: table_index = 1; break; - default: return; - } - map.collect_lookups (table_index, lookups); - } - inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); } - inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); } - - void init (void) - { - memset (this, 0, sizeof (*this)); - map.init (); - } - void fini (void) { - map.fini (); - } -}; - -struct hb_ot_shape_planner_t -{ - /* In the order that they are filled in. */ - hb_face_t *face; - hb_segment_properties_t props; - const struct hb_ot_complex_shaper_t *shaper; - hb_ot_map_builder_t map; - - hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) : - face (master_plan->face_unsafe), - props (master_plan->props), - shaper (nullptr), - map (face, &props) {} - - inline void compile (hb_ot_shape_plan_t &plan, - const int *coords, - unsigned int num_coords) - { - plan.props = props; - plan.shaper = shaper; - map.compile (plan.map, coords, num_coords); - - plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m')); - plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); - plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); - plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m')); - - plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ? - HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n')); - - plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); - plan.has_kern = !!plan.kern_mask; - plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); - } - - private: - HB_DISALLOW_COPY_AND_ASSIGN (hb_ot_shape_planner_t); -}; - - -#endif /* HB_OT_SHAPE_PRIVATE_HH */ diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 36e0bf9..e9d97c9 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -26,62 +26,246 @@ * Google Author(s): Behdad Esfahbod */ -#define HB_SHAPER ot -#define hb_ot_shaper_face_data_t hb_ot_layout_t -#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t -#include "hb-shaper-impl-private.hh" - -#include "hb-ot-shape-private.hh" -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-fallback-private.hh" -#include "hb-ot-shape-normalize-private.hh" - -#include "hb-ot-layout-private.hh" -#include "hb-unicode-private.hh" -#include "hb-set-private.hh" - -#include "hb-ot-layout-gsubgpos-private.hh" -//#include "hb-aat-layout-private.hh" - -static hb_tag_t common_features[] = { - HB_TAG('c','c','m','p'), - HB_TAG('l','o','c','l'), - HB_TAG('m','a','r','k'), - HB_TAG('m','k','m','k'), - HB_TAG('r','l','i','g'), -}; +#include "hb-shaper-impl.hh" + +#include "hb-ot-shape.hh" +#include "hb-ot-shape-complex.hh" +#include "hb-ot-shape-fallback.hh" +#include "hb-ot-shape-normalize.hh" + +#include "hb-ot-face.hh" + +#include "hb-set.hh" + +#include "hb-aat-layout.hh" + + +/** + * SECTION:hb-ot-shape + * @title: hb-ot-shape + * @short_description: OpenType shaping support + * @include: hb-ot.h + * + * Support functions for OpenType shaping related queries. + **/ + + +static void +hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, + const hb_feature_t *user_features, + unsigned int num_user_features); + +static bool +_hb_apply_morx (hb_face_t *face) +{ + if (hb_options ().aat && + hb_aat_layout_has_substitution (face)) + return true; + + /* Ignore empty GSUB tables. */ + return (!hb_ot_layout_has_substitution (face) || + !hb_ot_layout_table_get_script_tags (face, + HB_OT_TAG_GSUB, + 0, nullptr, nullptr)) && + hb_aat_layout_has_substitution (face); +} + +hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face, + const hb_segment_properties_t *props) : + face (face), + props (*props), + map (face, props), + aat_map (face, props), + apply_morx (_hb_apply_morx (face)) +{ + shaper = hb_ot_shape_complex_categorize (this); + + script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE; + script_fallback_mark_positioning = shaper->fallback_position; + + if (apply_morx) + shaper = &_hb_ot_complex_shaper_default; +} + +void +hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, + const hb_ot_shape_plan_key_t &key) +{ + plan.props = props; + plan.shaper = shaper; + map.compile (plan.map, key); + if (apply_morx) + aat_map.compile (plan.aat_map); + + plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); + plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); + plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m')); + plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); + plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m')); + hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ? + HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'); + plan.kern_mask = plan.map.get_mask (kern_tag); + plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k')); + + plan.requested_kerning = !!plan.kern_mask; + plan.requested_tracking = !!plan.trak_mask; + bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX; + bool disable_gpos = plan.shaper->gpos_tag && + plan.shaper->gpos_tag != plan.map.chosen_script[1]; + + /* + * Decide who provides glyph classes. GDEF or Unicode. + */ + + if (!hb_ot_layout_has_glyph_classes (face)) + plan.fallback_glyph_classes = true; + + /* + * Decide who does substitutions. GSUB, morx, or fallback. + */ + + plan.apply_morx = apply_morx; + + /* + * Decide who does positioning. GPOS, kerx, kern, or fallback. + */ + + if (hb_options ().aat && hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face)) + plan.apply_gpos = true; + else if (hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + + if (!plan.apply_kerx && !has_gpos_kern) + { + /* Apparently Apple applies kerx if GPOS kern was not applied. */ + if (hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + else if (hb_ot_layout_has_kerning (face)) + plan.apply_kern = true; + } + + plan.zero_marks = script_zero_marks && + !plan.apply_kerx && + (!plan.apply_kern || !hb_ot_layout_has_machine_kerning (face)); + plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); + + plan.adjust_mark_positioning_when_zeroing = !plan.apply_gpos && + !plan.apply_kerx && + (!plan.apply_kern || !hb_ot_layout_has_cross_kerning (face)); + + plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing && + script_fallback_mark_positioning; + + /* Currently we always apply trak. */ + plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face); +} + +bool +hb_ot_shape_plan_t::init0 (hb_face_t *face, + const hb_shape_plan_key_t *key) +{ + map.init (); + aat_map.init (); + + hb_ot_shape_planner_t planner (face, + &key->props); + + hb_ot_shape_collect_features (&planner, + key->user_features, + key->num_user_features); + + planner.compile (*this, key->ot); + + if (shaper->data_create) + { + data = shaper->data_create (this); + if (unlikely (!data)) + return false; + } + + return true; +} + +void +hb_ot_shape_plan_t::fini () +{ + if (shaper->data_destroy) + shaper->data_destroy (const_cast<void *> (data)); + + map.fini (); + aat_map.fini (); +} + +void +hb_ot_shape_plan_t::substitute (hb_font_t *font, + hb_buffer_t *buffer) const +{ + if (unlikely (apply_morx)) + hb_aat_layout_substitute (this, font, buffer); + else + map.substitute (this, font, buffer); +} + +void +hb_ot_shape_plan_t::position (hb_font_t *font, + hb_buffer_t *buffer) const +{ + if (this->apply_gpos) + map.position (this, font, buffer); + else if (this->apply_kerx) + hb_aat_layout_position (this, font, buffer); + else if (this->apply_kern) + hb_ot_layout_kern (this, font, buffer); + else + _hb_ot_shape_fallback_kern (this, font, buffer); + if (this->apply_trak) + hb_aat_layout_track (this, font, buffer); +} -static hb_tag_t horizontal_features[] = { - HB_TAG('c','a','l','t'), - HB_TAG('c','l','i','g'), - HB_TAG('c','u','r','s'), - HB_TAG('k','e','r','n'), - HB_TAG('l','i','g','a'), - HB_TAG('r','c','l','t'), + +static const hb_ot_map_feature_t +common_features[] = +{ + {HB_TAG('c','c','m','p'), F_GLOBAL}, + {HB_TAG('l','o','c','l'), F_GLOBAL}, + {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('m','k','m','k'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('r','l','i','g'), F_GLOBAL}, }; +static const hb_ot_map_feature_t +horizontal_features[] = +{ + {HB_TAG('c','a','l','t'), F_GLOBAL}, + {HB_TAG('c','l','i','g'), F_GLOBAL}, + {HB_TAG('c','u','r','s'), F_GLOBAL}, + {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK}, + {HB_TAG('l','i','g','a'), F_GLOBAL}, + {HB_TAG('r','c','l','t'), F_GLOBAL}, +}; static void hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, - const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features) { hb_ot_map_builder_t *map = &planner->map; - map->add_global_bool_feature (HB_TAG('r','v','r','n')); + map->enable_feature (HB_TAG('r','v','r','n')); map->add_gsub_pause (nullptr); - switch (props->direction) { + switch (planner->props.direction) { case HB_DIRECTION_LTR: - map->add_global_bool_feature (HB_TAG ('l','t','r','a')); - map->add_global_bool_feature (HB_TAG ('l','t','r','m')); + map->enable_feature (HB_TAG ('l','t','r','a')); + map->enable_feature (HB_TAG ('l','t','r','m')); break; case HB_DIRECTION_RTL: - map->add_global_bool_feature (HB_TAG ('r','t','l','a')); - map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); + map->enable_feature (HB_TAG ('r','t','l','a')); + map->add_feature (HB_TAG ('r','t','l','m')); break; case HB_DIRECTION_TTB: case HB_DIRECTION_BTT: @@ -90,39 +274,62 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, break; } - map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); - map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); - map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); + /* Automatic fractions. */ + map->add_feature (HB_TAG ('f','r','a','c')); + map->add_feature (HB_TAG ('n','u','m','r')); + map->add_feature (HB_TAG ('d','n','o','m')); + + /* Random! */ + map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE); + + /* Tracking. We enable dummy feature here just to allow disabling + * AAT 'trak' table using features. + * https://github.com/harfbuzz/harfbuzz/issues/1303 */ + map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK); + + map->enable_feature (HB_TAG ('H','A','R','F')); if (planner->shaper->collect_features) planner->shaper->collect_features (planner); + map->enable_feature (HB_TAG ('B','U','Z','Z')); + for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) - map->add_global_bool_feature (common_features[i]); + map->add_feature (common_features[i]); - if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) + if (HB_DIRECTION_IS_HORIZONTAL (planner->props.direction)) for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) - map->add_feature (horizontal_features[i], 1, F_GLOBAL | - (horizontal_features[i] == HB_TAG('k','e','r','n') ? - F_HAS_FALLBACK : F_NONE)); + map->add_feature (horizontal_features[i]); else { /* We really want to find a 'vert' feature if there's any in the font, no * matter which script/langsys it is listed (or not) under. * See various bugs referenced from: * https://github.com/harfbuzz/harfbuzz/issues/63 */ - map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH); + map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH); } - if (planner->shaper->override_features) - planner->shaper->override_features (planner); - - for (unsigned int i = 0; i < num_user_features; i++) { + for (unsigned int i = 0; i < num_user_features; i++) + { const hb_feature_t *feature = &user_features[i]; - map->add_feature (feature->tag, feature->value, - (feature->start == 0 && feature->end == (unsigned int) -1) ? - F_GLOBAL : F_NONE); + map->add_feature (feature->tag, + (feature->start == HB_FEATURE_GLOBAL_START && + feature->end == HB_FEATURE_GLOBAL_END) ? F_GLOBAL : F_NONE, + feature->value); } + + if (planner->apply_morx) + { + hb_aat_map_builder_t *aat_map = &planner->aat_map; + for (unsigned int i = 0; i < num_user_features; i++) + { + const hb_feature_t *feature = &user_features[i]; + aat_map->add_feature (feature->tag, feature->value); + } + } + + if (planner->shaper->override_features) + planner->shaper->override_features (planner); } @@ -130,18 +337,17 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, * shaper face data */ -HB_SHAPER_DATA_ENSURE_DEFINE(ot, face) +struct hb_ot_face_data_t {}; -hb_ot_shaper_face_data_t * +hb_ot_face_data_t * _hb_ot_shaper_face_data_create (hb_face_t *face) { - return _hb_ot_layout_create (face); + return (hb_ot_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) +_hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data) { - _hb_ot_layout_destroy (data); } @@ -149,70 +355,21 @@ _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) * shaper font data */ -HB_SHAPER_DATA_ENSURE_DEFINE(ot, font) - -struct hb_ot_shaper_font_data_t {}; +struct hb_ot_font_data_t {}; -hb_ot_shaper_font_data_t * +hb_ot_font_data_t * _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED) { - return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; + return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) +_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED) { } /* - * shaper shape_plan data - */ - -hb_ot_shaper_shape_plan_data_t * -_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords) -{ - hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); - if (unlikely (!plan)) - return nullptr; - - plan->init (); - - hb_ot_shape_planner_t planner (shape_plan); - - planner.shaper = hb_ot_shape_complex_categorize (&planner); - - hb_ot_shape_collect_features (&planner, &shape_plan->props, - user_features, num_user_features); - - planner.compile (*plan, coords, num_coords); - - if (plan->shaper->data_create) { - plan->data = plan->shaper->data_create (plan); - if (unlikely (!plan->data)) - return nullptr; - } - - return plan; -} - -void -_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) -{ - if (plan->shaper->data_destroy) - plan->shaper->data_destroy (const_cast<void *> (plan->data)); - - plan->fini (); - - free (plan); -} - - -/* * shaper */ @@ -226,8 +383,6 @@ struct hb_ot_shape_context_t unsigned int num_user_features; /* Transient stuff */ - bool fallback_positioning; - bool fallback_glyph_classes; hb_direction_t target_direction; }; @@ -241,10 +396,53 @@ struct hb_ot_shape_context_t static void hb_set_unicode_props (hb_buffer_t *buffer) { + /* Implement enough of Unicode Graphemes here that shaping + * in reverse-direction wouldn't break graphemes. Namely, + * we mark all marks and ZWJ and ZWJ,Extended_Pictographic + * sequences as continuations. The foreach_grapheme() + * macro uses this bit. + * + * https://www.unicode.org/reports/tr29/#Regex_Definitions + */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) + { _hb_glyph_info_set_unicode_props (&info[i], buffer); + + /* Marks are already set as continuation by the above line. + * Handle Emoji_Modifier and ZWJ-continuation. */ + if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL && + hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu))) + { + _hb_glyph_info_set_continuation (&info[i]); + } + else if (unlikely (_hb_glyph_info_is_zwj (&info[i]))) + { + _hb_glyph_info_set_continuation (&info[i]); + if (i + 1 < count && + _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint)) + { + i++; + _hb_glyph_info_set_unicode_props (&info[i], buffer); + _hb_glyph_info_set_continuation (&info[i]); + } + } + /* Or part of the Other_Grapheme_Extend that is not marks. + * As of Unicode 11 that is just: + * + * 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER + * FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK + * E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG + * + * ZWNJ is special, we don't want to merge it as there's no need, and keeping + * it separate results in more granular clusters. Ignore Katakana for now. + * Tags are used for Emoji sub-region flag sequences: + * https://github.com/harfbuzz/harfbuzz/issues/1556 + */ + else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu))) + _hb_glyph_info_set_continuation (&info[i]); + } } static void @@ -252,8 +450,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) { if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || buffer->context_len[0] || - _hb_glyph_info_get_general_category (&buffer->info[0]) != - HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) + !_hb_glyph_info_is_unicode_mark (&buffer->info[0])) return; if (!font->has_glyph (0x25CCu)) @@ -272,7 +469,6 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) buffer->output_info (info); while (buffer->idx < buffer->len && buffer->successful) buffer->next_glyph (); - buffer->swap_buffers (); } @@ -282,26 +478,12 @@ hb_form_clusters (hb_buffer_t *buffer) if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) return; - /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */ - unsigned int base = 0; - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 1; i < count; i++) - { - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) && - !_hb_glyph_info_is_joiner (&info[i]))) - { - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_clusters (base, i); - else - buffer->unsafe_to_break (base, i); - base = i; - } - } if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_clusters (base, count); + foreach_grapheme (buffer, start, end) + buffer->merge_clusters (start, end); else - buffer->unsafe_to_break (base, count); + foreach_grapheme (buffer, start, end) + buffer->unsafe_to_break (start, end); } static void @@ -319,25 +501,17 @@ hb_ensure_native_direction (hb_buffer_t *buffer) (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) { - /* Same loop as hb_form_clusters(). - * Since form_clusters() merged clusters already, we don't merge. */ - unsigned int base = 0; - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 1; i < count; i++) - { - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) - { - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buffer->merge_clusters (base, i); - buffer->reverse_range (base, i); - base = i; - } - } if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buffer->merge_clusters (base, count); - buffer->reverse_range (base, count); + foreach_grapheme (buffer, start, end) + { + buffer->merge_clusters (start, end); + buffer->reverse_range (start, end); + } + else + foreach_grapheme (buffer, start, end) + /* form_clusters() merged clusters already, we don't merge. */ + buffer->reverse_range (start, end); buffer->reverse (); @@ -346,10 +520,12 @@ hb_ensure_native_direction (hb_buffer_t *buffer) } -/* Substitute */ +/* + * Substitute + */ static inline void -hb_ot_mirror_chars (hb_ot_shape_context_t *c) +hb_ot_mirror_chars (const hb_ot_shape_context_t *c) { if (HB_DIRECTION_IS_FORWARD (c->target_direction)) return; @@ -370,7 +546,7 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) +hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) { if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || !c->plan->has_frac) @@ -420,7 +596,7 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) +hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c) { hb_ot_map_t *map = &c->plan->map; hb_buffer_t *buffer = c->buffer; @@ -430,7 +606,7 @@ hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) +hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c) { hb_ot_map_t *map = &c->plan->map; hb_buffer_t *buffer = c->buffer; @@ -452,10 +628,8 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) } static void -hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) +hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer) { - hb_buffer_t *buffer = c->buffer; - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) || (buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES)) @@ -471,83 +645,29 @@ hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) } static void -hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) +hb_ot_hide_default_ignorables (hb_buffer_t *buffer, + hb_font_t *font) { - hb_buffer_t *buffer = c->buffer; - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)) return; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; - hb_glyph_position_t *pos = buffer->pos; - unsigned int i = 0; - for (i = 0; i < count; i++) - { - if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) - break; - } - - /* No default-ignorables found; return. */ - if (i == count) - return; - hb_codepoint_t space; + hb_codepoint_t invisible = buffer->invisible; if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && - c->font->get_nominal_glyph (' ', &space)) + (invisible || font->get_nominal_glyph (' ', &invisible))) { - /* Replace default-ignorables with a zero-advance space glyph. */ - for (/*continue*/; i < count; i++) + /* Replace default-ignorables with a zero-advance invisible glyph. */ + for (unsigned int i = 0; i < count; i++) { if (_hb_glyph_info_is_default_ignorable (&info[i])) - info[i].codepoint = space; + info[i].codepoint = invisible; } } else - { - /* Merge clusters and delete default-ignorables. - * NOTE! We can't use out-buffer as we have positioning data. */ - unsigned int j = i; - for (; i < count; i++) - { - if (_hb_glyph_info_is_default_ignorable (&info[i])) - { - /* Merge clusters. - * Same logic as buffer->delete_glyph(), but for in-place removal. */ - - unsigned int cluster = info[i].cluster; - if (i + 1 < count && cluster == info[i + 1].cluster) - continue; /* Cluster survives; do nothing. */ - - if (j) - { - /* Merge cluster backward. */ - if (cluster < info[j - 1].cluster) - { - unsigned int mask = info[i].mask; - unsigned int old_cluster = info[j - 1].cluster; - for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) - buffer->set_cluster (info[k - 1], cluster, mask); - } - continue; - } - - if (i + 1 < count) - buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */ - - continue; - } - - if (j != i) - { - info[j] = info[i]; - pos[j] = pos[i]; - } - j++; - } - buffer->len = j; - } + hb_ot_layout_delete_glyphs_inplace (buffer, _hb_glyph_info_is_default_ignorable); } @@ -564,10 +684,10 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer) } static inline void -hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) +hb_synthesize_glyph_classes (hb_buffer_t *buffer) { - unsigned int count = c->buffer->len; - hb_glyph_info_t *info = c->buffer->info; + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) { hb_ot_layout_glyph_props_flags_t klass; @@ -590,7 +710,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) } static inline void -hb_ot_substitute_default (hb_ot_shape_context_t *c) +hb_ot_substitute_default (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; @@ -603,8 +723,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) hb_ot_shape_setup_masks (c); /* This is unfortunate to go here, but necessary... */ - if (c->fallback_positioning) - _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); + if (c->plan->fallback_mark_positioning) + _hb_ot_shape_fallback_mark_position_recategorize_marks (c->plan, c->font, buffer); hb_ot_map_glyphs_fast (buffer); @@ -612,23 +732,20 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) } static inline void -hb_ot_substitute_complex (hb_ot_shape_context_t *c) +hb_ot_substitute_complex (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; hb_ot_layout_substitute_start (c->font, buffer); - if (!hb_ot_layout_has_glyph_classes (c->face)) - hb_synthesize_glyph_classes (c); + if (c->plan->fallback_glyph_classes) + hb_synthesize_glyph_classes (c->buffer); c->plan->substitute (c->font, buffer); - - /* XXX Call morx instead. */ - //hb_aat_layout_substitute (c->font, c->buffer); } static inline void -hb_ot_substitute (hb_ot_shape_context_t *c) +hb_ot_substitute_pre (const hb_ot_shape_context_t *c) { hb_ot_substitute_default (c); @@ -637,7 +754,21 @@ hb_ot_substitute (hb_ot_shape_context_t *c) hb_ot_substitute_complex (c); } -/* Position */ +static inline void +hb_ot_substitute_post (const hb_ot_shape_context_t *c) +{ + hb_ot_hide_default_ignorables (c->buffer, c->font); + if (c->plan->apply_morx) + hb_aat_layout_remove_deleted_glyphs (c->buffer); + + if (c->plan->shaper->postprocess_glyphs) + c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); +} + + +/* + * Position + */ static inline void adjust_mark_offsets (hb_glyph_position_t *pos) @@ -668,7 +799,7 @@ zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) } static inline void -hb_ot_position_default (hb_ot_shape_context_t *c) +hb_ot_position_default (const hb_ot_shape_context_t *c) { hb_direction_t direction = c->buffer->props.direction; unsigned int count = c->buffer->len; @@ -677,8 +808,8 @@ hb_ot_position_default (hb_ot_shape_context_t *c) if (HB_DIRECTION_IS_HORIZONTAL (direction)) { - for (unsigned int i = 0; i < count; i++) - pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint); + c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]), + &pos[0].x_advance, sizeof(pos[0])); /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ if (c->font->has_glyph_h_origin_func ()) for (unsigned int i = 0; i < count; i++) @@ -688,9 +819,10 @@ hb_ot_position_default (hb_ot_shape_context_t *c) } else { + c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]), + &pos[0].y_advance, sizeof(pos[0])); for (unsigned int i = 0; i < count; i++) { - pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint); c->font->subtract_glyph_v_origin (info[i].codepoint, &pos[i].x_offset, &pos[i].y_offset); @@ -701,23 +833,22 @@ hb_ot_position_default (hb_ot_shape_context_t *c) } static inline void -hb_ot_position_complex (hb_ot_shape_context_t *c) +hb_ot_position_complex (const hb_ot_shape_context_t *c) { unsigned int count = c->buffer->len; hb_glyph_info_t *info = c->buffer->info; hb_glyph_position_t *pos = c->buffer->pos; - /* If the font has no GPOS, AND, no fallback positioning will - * happen, AND, direction is forward, then when zeroing mark - * widths, we shift the mark with it, such that the mark - * is positioned hanging over the previous glyph. When + /* If the font has no GPOS and direction is forward, then when + * zeroing mark widths, we shift the mark with it, such that the + * mark is positioned hanging over the previous glyph. When * direction is backward we don't shift and it will end up * hanging over the next glyph after the final reordering. - * If fallback positinoing happens or GPOS is present, we don't - * care. + * + * Note: If fallback positinoing happens, we don't care about + * this as it will be overriden. */ - bool adjust_offsets_when_zeroing = c->fallback_positioning && - !c->plan->shaper->fallback_position && + bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing && HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */ @@ -731,36 +862,39 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) hb_ot_layout_position_start (c->font, c->buffer); - switch (c->plan->shaper->zero_width_marks) - { - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: - zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); - break; - - default: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: - break; - } - - if (likely (!c->fallback_positioning)) - c->plan->position (c->font, c->buffer); + if (c->plan->zero_marks) + switch (c->plan->shaper->zero_width_marks) + { + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: + zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); + break; + + default: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: + break; + } - switch (c->plan->shaper->zero_width_marks) - { - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: - zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); - break; + c->plan->position (c->font, c->buffer); - default: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: - break; - } + if (c->plan->zero_marks) + switch (c->plan->shaper->zero_width_marks) + { + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: + zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); + break; + + default: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: + break; + } - /* Finishing off GPOS has to follow a certain order. */ + /* Finish off. Has to follow a certain order. */ hb_ot_layout_position_finish_advances (c->font, c->buffer); - hb_ot_zero_width_default_ignorables (c); + hb_ot_zero_width_default_ignorables (c->buffer); + if (c->plan->apply_morx) + hb_aat_layout_zero_width_deleted_glyphs (c->buffer); hb_ot_layout_position_finish_offsets (c->font, c->buffer); /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ @@ -769,10 +903,14 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) c->font->subtract_glyph_h_origin (info[i].codepoint, &pos[i].x_offset, &pos[i].y_offset); + + if (c->plan->fallback_mark_positioning) + _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer, + adjust_offsets_when_zeroing); } static inline void -hb_ot_position (hb_ot_shape_context_t *c) +hb_ot_position (const hb_ot_shape_context_t *c) { c->buffer->clear_positions (); @@ -780,20 +918,10 @@ hb_ot_position (hb_ot_shape_context_t *c) hb_ot_position_complex (c); - if (c->fallback_positioning && c->plan->shaper->fallback_position) - _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); - if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) hb_buffer_reverse (c->buffer); - /* Visual fallback goes here. */ - - if (c->fallback_positioning) - _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); - _hb_buffer_deallocate_gsubgpos_vars (c->buffer); - - //hb_aat_layout_position (c->font, c->buffer); } static inline void @@ -829,22 +957,17 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) { c->buffer->deallocate_var_all (); c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) + if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) { c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, (unsigned) HB_BUFFER_MAX_LEN_MIN); } - if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) + if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) { c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, (unsigned) HB_BUFFER_MAX_OPS_MIN); } - bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan); - //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face); - c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face); - c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face); - /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; @@ -863,13 +986,9 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) if (c->plan->shaper->preprocess_text) c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); - hb_ot_substitute (c); + hb_ot_substitute_pre (c); hb_ot_position (c); - - hb_ot_hide_default_ignorables (c); - - if (c->plan->shaper->postprocess_glyphs) - c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); + hb_ot_substitute_post (c); hb_propagate_flags (c->buffer); @@ -890,7 +1009,7 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan, const hb_feature_t *features, unsigned int num_features) { - hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; + hb_ot_shape_context_t c = {&shape_plan->ot, font, font->face, buffer, features, num_features}; hb_ot_shape_internal (&c); return true; @@ -907,8 +1026,7 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, hb_tag_t table_tag, hb_set_t *lookup_indexes /* OUT */) { - /* XXX Does the first part always succeed? */ - HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); + shape_plan->ot.collect_lookups (table_tag, lookup_indexes); } diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh new file mode 100644 index 0000000..73a11e1 --- /dev/null +++ b/src/hb-ot-shape.hh @@ -0,0 +1,129 @@ +/* + * Copyright © 2010 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): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_HH +#define HB_OT_SHAPE_HH + +#include "hb.hh" + +#include "hb-ot-map.hh" +#include "hb-aat-map.hh" + + +struct hb_ot_shape_plan_key_t +{ + unsigned int variations_index[2]; + + void init (hb_face_t *face, + const int *coords, + unsigned int num_coords) + { + for (unsigned int table_index = 0; table_index < 2; table_index++) + hb_ot_layout_table_find_feature_variations (face, + table_tags[table_index], + coords, + num_coords, + &variations_index[table_index]); + } + + bool equal (const hb_ot_shape_plan_key_t *other) + { + return 0 == memcmp (this, other, sizeof (*this)); + } +}; + + +struct hb_shape_plan_key_t; + +struct hb_ot_shape_plan_t +{ + hb_segment_properties_t props; + const struct hb_ot_complex_shaper_t *shaper; + hb_ot_map_t map; + hb_aat_map_t aat_map; + const void *data; + hb_mask_t frac_mask, numr_mask, dnom_mask; + hb_mask_t rtlm_mask; + hb_mask_t kern_mask; + hb_mask_t trak_mask; + + bool requested_kerning : 1; + bool requested_tracking : 1; + bool has_frac : 1; + bool has_gpos_mark : 1; + bool zero_marks : 1; + bool fallback_glyph_classes : 1; + bool fallback_mark_positioning : 1; + bool adjust_mark_positioning_when_zeroing : 1; + + bool apply_gpos : 1; + bool apply_kerx : 1; + bool apply_kern : 1; + bool apply_morx : 1; + bool apply_trak : 1; + + void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const + { + unsigned int table_index; + switch (table_tag) { + case HB_OT_TAG_GSUB: table_index = 0; break; + case HB_OT_TAG_GPOS: table_index = 1; break; + default: return; + } + map.collect_lookups (table_index, lookups); + } + + HB_INTERNAL bool init0 (hb_face_t *face, + const hb_shape_plan_key_t *key); + HB_INTERNAL void fini (); + + HB_INTERNAL void substitute (hb_font_t *font, hb_buffer_t *buffer) const; + HB_INTERNAL void position (hb_font_t *font, hb_buffer_t *buffer) const; +}; + +struct hb_shape_plan_t; + +struct hb_ot_shape_planner_t +{ + /* In the order that they are filled in. */ + hb_face_t *face; + hb_segment_properties_t props; + hb_ot_map_builder_t map; + hb_aat_map_builder_t aat_map; + bool apply_morx : 1; + bool script_zero_marks : 1; + bool script_fallback_mark_positioning : 1; + const struct hb_ot_complex_shaper_t *shaper; + + HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face, + const hb_segment_properties_t *props); + + HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, + const hb_ot_shape_plan_key_t &key); +}; + + +#endif /* HB_OT_SHAPE_HH */ diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh new file mode 100644 index 0000000..04a2ee9 --- /dev/null +++ b/src/hb-ot-stat-table.hh @@ -0,0 +1,280 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#ifndef HB_OT_STAT_TABLE_HH +#define HB_OT_STAT_TABLE_HH + +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" + +/* + * STAT -- Style Attributes + * https://docs.microsoft.com/en-us/typography/opentype/spec/stat + */ +#define HB_OT_TAG_STAT HB_TAG('S','T','A','T') + + +namespace OT { + +enum +{ + OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001, /* If set, this axis value table + * provides axis value information + * that is applicable to other fonts + * within the same font family. This + * is used if the other fonts were + * released earlier and did not include + * information about values for some axis. + * If newer versions of the other + * fonts include the information + * themselves and are present, + * then this record is ignored. */ + ELIDABLE_AXIS_VALUE_NAME = 0x0002 /* If set, it indicates that the axis + * value represents the “normal” value + * for the axis and may be omitted when + * composing name strings. */ + // Reserved = 0xFFFC /* Reserved for future use — set to zero. */ +}; + +struct AxisValueFormat1 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 1. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed value; /* A numeric value for this attribute value. */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct AxisValueFormat2 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 2. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed nominalValue; /* A numeric value for this attribute value. */ + Fixed rangeMinValue; /* The minimum value for a range associated + * with the specified name ID. */ + Fixed rangeMaxValue; /* The maximum value for a range associated + * with the specified name ID. */ + public: + DEFINE_SIZE_STATIC (20); +}; + +struct AxisValueFormat3 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 3. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed value; /* A numeric value for this attribute value. */ + Fixed linkedValue; /* The numeric value for a style-linked mapping + * from this value. */ + public: + DEFINE_SIZE_STATIC (16); +}; + +struct AxisValueRecord +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis to which this value + * applies. Must be less than designAxisCount. */ + Fixed value; /* A numeric value for this attribute value. */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct AxisValueFormat4 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 4. */ + HBUINT16 axisCount; /* The total number of axes contributing to + * this axis-values combination. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + UnsizedArrayOf<AxisValueRecord> + axisValues; /* Array of AxisValue records that provide the + * combination of axis values, one for each + * contributing axis. */ + public: + DEFINE_SIZE_ARRAY (8, axisValues); +}; + +struct AxisValue +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (c->check_struct (this))) + return_trace (false); + + switch (u.format) + { + case 1: return_trace (likely (u.format1.sanitize (c))); + case 2: return_trace (likely (u.format2.sanitize (c))); + case 3: return_trace (likely (u.format3.sanitize (c))); + case 4: return_trace (likely (u.format4.sanitize (c))); + default: return_trace (true); + } + } + + protected: + union + { + HBUINT16 format; + AxisValueFormat1 format1; + AxisValueFormat2 format2; + AxisValueFormat3 format3; + AxisValueFormat4 format4; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct StatAxisRecord +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + Tag tag; /* A tag identifying the axis of design variation. */ + NameID nameID; /* The name ID for entries in the 'name' table that + * provide a display string for this axis. */ + HBUINT16 ordering; /* A value that applications can use to determine + * primary sorting of face names, or for ordering + * of descriptors when composing family or face names. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct STAT +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + majorVersion == 1 && + minorVersion > 0 && + designAxesOffset.sanitize (c, this, designAxisCount) && + offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets)))); + } + + protected: + HBUINT16 majorVersion; /* Major version number of the style attributes + * table — set to 1. */ + HBUINT16 minorVersion; /* Minor version number of the style attributes + * table — set to 2. */ + HBUINT16 designAxisSize; /* The size in bytes of each axis record. */ + HBUINT16 designAxisCount;/* The number of design axis records. In a + * font with an 'fvar' table, this value must be + * greater than or equal to the axisCount value + * in the 'fvar' table. In all fonts, must + * be greater than zero if axisValueCount + * is greater than zero. */ + LNNOffsetTo<UnsizedArrayOf<StatAxisRecord> > + designAxesOffset; + /* Offset in bytes from the beginning of + * the STAT table to the start of the design + * axes array. If designAxisCount is zero, + * set to zero; if designAxisCount is greater + * than zero, must be greater than zero. */ + HBUINT16 axisValueCount; /* The number of axis value tables. */ + LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue> > > + offsetToAxisValueOffsets; + /* Offset in bytes from the beginning of + * the STAT table to the start of the design + * axes value offsets array. If axisValueCount + * is zero, set to zero; if axisValueCount is + * greater than zero, must be greater than zero. */ + NameID elidedFallbackNameID; + /* Name ID used as fallback when projection of + * names into a particular font model produces + * a subfamily name containing only elidable + * elements. */ + public: + DEFINE_SIZE_STATIC (20); +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_STAT_TABLE_HH */ diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh new file mode 100644 index 0000000..b7090a0 --- /dev/null +++ b/src/hb-ot-tag-table.hh @@ -0,0 +1,2064 @@ +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-tag-table.py languagetags language-subtag-registry + * + * on files with these headers: + * + * <meta name="updated_at" content="2018-09-07 07:45 PM" /> + * File-Date: 2018-08-08 + */ + +#ifndef HB_OT_TAG_TABLE_HH +#define HB_OT_TAG_TABLE_HH + +static const LangTag ot_languages[] = { + {"aa", {HB_TAG('A','F','R',' ')}}, /* Afar */ + {"aae", {HB_TAG('S','Q','I',' ')}}, /* Arbëreshë Albanian -> Albanian */ + {"aao", {HB_TAG('A','R','A',' ')}}, /* Algerian Saharan Arabic -> Arabic */ + {"aat", {HB_TAG('S','Q','I',' ')}}, /* Arvanitika Albanian -> Albanian */ + {"ab", {HB_TAG('A','B','K',' ')}}, /* Abkhazian */ + {"abh", {HB_TAG('A','R','A',' ')}}, /* Tajiki Arabic -> Arabic */ + {"abq", {HB_TAG('A','B','A',' ')}}, /* Abaza */ + {"abv", {HB_TAG('A','R','A',' ')}}, /* Baharna Arabic -> Arabic */ + {"acf", {HB_TAG('F','A','N',' ')}}, /* Saint Lucian Creole French -> French Antillean */ + {"ach", {HB_TAG('A','C','H',' ')}}, /* Acoli -> Acholi */ + {"acm", {HB_TAG('A','R','A',' ')}}, /* Mesopotamian Arabic -> Arabic */ + {"acq", {HB_TAG('A','R','A',' ')}}, /* Ta'izzi-Adeni Arabic -> Arabic */ + {"acr", {HB_TAG('A','C','R',' ')}}, /* Achi */ + {"acw", {HB_TAG('A','R','A',' ')}}, /* Hijazi Arabic -> Arabic */ + {"acx", {HB_TAG('A','R','A',' ')}}, /* Omani Arabic -> Arabic */ + {"acy", {HB_TAG('A','R','A',' ')}}, /* Cypriot Arabic -> Arabic */ + {"ada", {HB_TAG('D','N','G',' ')}}, /* Adangme -> Dangme */ + {"adf", {HB_TAG('A','R','A',' ')}}, /* Dhofari Arabic -> Arabic */ + {"adp", {HB_TAG('D','Z','N',' ')}}, /* Adap (retired code) -> Dzongkha */ + {"ady", {HB_TAG('A','D','Y',' ')}}, /* Adyghe */ + {"aeb", {HB_TAG('A','R','A',' ')}}, /* Tunisian Arabic -> Arabic */ + {"aec", {HB_TAG('A','R','A',' ')}}, /* Saidi Arabic -> Arabic */ + {"af", {HB_TAG('A','F','K',' ')}}, /* Afrikaans */ + {"afb", {HB_TAG('A','R','A',' ')}}, /* Gulf Arabic -> Arabic */ + {"ahg", {HB_TAG('A','G','W',' ')}}, /* Qimant -> Agaw */ + {"aht", {HB_TAG('A','T','H',' ')}}, /* Ahtena -> Athapaskan */ + {"aii", {HB_TAG('S','W','A',' '), /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + HB_TAG('S','Y','R',' ')}}, /* Assyrian Neo-Aramaic -> Syriac */ + {"aio", {HB_TAG('A','I','O',' ')}}, /* Aiton */ + {"aiw", {HB_TAG('A','R','I',' ')}}, /* Aari */ + {"ajp", {HB_TAG('A','R','A',' ')}}, /* South Levantine Arabic -> Arabic */ + {"ak", {HB_TAG('A','K','A',' '), /* Akan [macrolanguage] */ + HB_TAG('T','W','I',' ')}}, /* Akan [macrolanguage] -> Twi */ + {"aln", {HB_TAG('S','Q','I',' ')}}, /* Gheg Albanian -> Albanian */ + {"als", {HB_TAG('S','Q','I',' ')}}, /* Tosk Albanian -> Albanian */ + {"alt", {HB_TAG('A','L','T',' ')}}, /* Southern Altai -> Altai */ + {"am", {HB_TAG('A','M','H',' ')}}, /* Amharic */ + {"amf", {HB_TAG('H','B','N',' ')}}, /* Hamer-Banna -> Hammer-Banna */ + {"amw", {HB_TAG('S','Y','R',' ')}}, /* Western Neo-Aramaic -> Syriac */ + {"an", {HB_TAG('A','R','G',' ')}}, /* Aragonese */ + {"ang", {HB_TAG('A','N','G',' ')}}, /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {"apc", {HB_TAG('A','R','A',' ')}}, /* North Levantine Arabic -> Arabic */ + {"apd", {HB_TAG('A','R','A',' ')}}, /* Sudanese Arabic -> Arabic */ + {"apj", {HB_TAG('A','T','H',' ')}}, /* Jicarilla Apache -> Athapaskan */ + {"apk", {HB_TAG('A','T','H',' ')}}, /* Kiowa Apache -> Athapaskan */ + {"apl", {HB_TAG('A','T','H',' ')}}, /* Lipan Apache -> Athapaskan */ + {"apm", {HB_TAG('A','T','H',' ')}}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {"apw", {HB_TAG('A','T','H',' ')}}, /* Western Apache -> Athapaskan */ + {"ar", {HB_TAG('A','R','A',' ')}}, /* Arabic [macrolanguage] */ + {"arb", {HB_TAG('A','R','A',' ')}}, /* Standard Arabic -> Arabic */ + {"arn", {HB_TAG('M','A','P',' ')}}, /* Mapudungun */ + {"arq", {HB_TAG('A','R','A',' ')}}, /* Algerian Arabic -> Arabic */ + {"ars", {HB_TAG('A','R','A',' ')}}, /* Najdi Arabic -> Arabic */ + {"ary", {HB_TAG('M','O','R',' ')}}, /* Moroccan Arabic -> Moroccan */ + {"arz", {HB_TAG('A','R','A',' ')}}, /* Egyptian Arabic -> Arabic */ + {"as", {HB_TAG('A','S','M',' ')}}, /* Assamese */ + {"ast", {HB_TAG('A','S','T',' ')}}, /* Asturian */ + {"ath", {HB_TAG('A','T','H',' ')}}, /* Athapascan [family] -> Athapaskan */ + {"atj", {HB_TAG('R','C','R',' ')}}, /* Atikamekw -> R-Cree */ + {"atv", {HB_TAG('A','L','T',' ')}}, /* Northern Altai -> Altai */ + {"auz", {HB_TAG('A','R','A',' ')}}, /* Uzbeki Arabic -> Arabic */ + {"av", {HB_TAG('A','V','R',' ')}}, /* Avaric -> Avar */ + {"avl", {HB_TAG('A','R','A',' ')}}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ + {"awa", {HB_TAG('A','W','A',' ')}}, /* Awadhi */ + {"ay", {HB_TAG('A','Y','M',' ')}}, /* Aymara [macrolanguage] */ + {"ayc", {HB_TAG('A','Y','M',' ')}}, /* Southern Aymara -> Aymara */ + {"ayh", {HB_TAG('A','R','A',' ')}}, /* Hadrami Arabic -> Arabic */ + {"ayl", {HB_TAG('A','R','A',' ')}}, /* Libyan Arabic -> Arabic */ + {"ayn", {HB_TAG('A','R','A',' ')}}, /* Sanaani Arabic -> Arabic */ + {"ayp", {HB_TAG('A','R','A',' ')}}, /* North Mesopotamian Arabic -> Arabic */ + {"ayr", {HB_TAG('A','Y','M',' ')}}, /* Central Aymara -> Aymara */ + {"az", {HB_TAG('A','Z','E',' ')}}, /* Azerbaijani [macrolanguage] */ + {"azb", {HB_TAG('A','Z','B',' ')}}, /* South Azerbaijani -> Torki */ + {"azj", {HB_TAG('A','Z','E',' ')}}, /* North Azerbaijani -> Azerbaijani */ + {"ba", {HB_TAG('B','S','H',' ')}}, /* Bashkir */ + {"bad", {HB_TAG('B','A','D','0')}}, /* Banda [family] */ + {"bai", {HB_TAG('B','M','L',' ')}}, /* Bamileke [family] */ + {"bal", {HB_TAG('B','L','I',' ')}}, /* Baluchi [macrolanguage] */ + {"ban", {HB_TAG('B','A','N',' ')}}, /* Balinese */ + {"bar", {HB_TAG('B','A','R',' ')}}, /* Bavarian */ + {"bbc", {HB_TAG('B','B','C',' ')}}, /* Batak Toba */ + {"bbz", {HB_TAG('A','R','A',' ')}}, /* Babalia Creole Arabic -> Arabic */ + {"bcc", {HB_TAG('B','L','I',' ')}}, /* Southern Balochi -> Baluchi */ + {"bci", {HB_TAG('B','A','U',' ')}}, /* Baoulé -> Baulé */ + {"bcl", {HB_TAG('B','I','K',' ')}}, /* Central Bikol -> Bikol */ + {"bcq", {HB_TAG('B','C','H',' ')}}, /* Bench */ + {"bcr", {HB_TAG('A','T','H',' ')}}, /* Babine -> Athapaskan */ + {"bdy", {HB_TAG('B','D','Y',' ')}}, /* Bandjalang */ + {"be", {HB_TAG('B','E','L',' ')}}, /* Belarusian -> Belarussian */ + {"bea", {HB_TAG('A','T','H',' ')}}, /* Beaver -> Athapaskan */ + {"beb", {HB_TAG('B','T','I',' ')}}, /* Bebele -> Beti */ + {"bem", {HB_TAG('B','E','M',' ')}}, /* Bemba (Zambia) */ + {"ber", {HB_TAG('B','B','R',' ')}}, /* Berber [family] */ + {"bfq", {HB_TAG('B','A','D',' ')}}, /* Badaga */ + {"bft", {HB_TAG('B','L','T',' ')}}, /* Balti */ + {"bfu", {HB_TAG('L','A','H',' ')}}, /* Gahri -> Lahuli */ + {"bfy", {HB_TAG('B','A','G',' ')}}, /* Bagheli -> Baghelkhandi */ + {"bg", {HB_TAG('B','G','R',' ')}}, /* Bulgarian */ + {"bgc", {HB_TAG('B','G','C',' ')}}, /* Haryanvi */ + {"bgn", {HB_TAG('B','L','I',' ')}}, /* Western Balochi -> Baluchi */ + {"bgp", {HB_TAG('B','L','I',' ')}}, /* Eastern Balochi -> Baluchi */ + {"bgq", {HB_TAG('B','G','Q',' ')}}, /* Bagri */ + {"bgr", {HB_TAG('Q','I','N',' ')}}, /* Bawm Chin -> Chin */ + {"bhb", {HB_TAG('B','H','I',' ')}}, /* Bhili */ + {"bhi", {HB_TAG('B','H','I',' ')}}, /* Bhilali -> Bhili */ + {"bhk", {HB_TAG('B','I','K',' ')}}, /* Albay Bicolano (retired code) -> Bikol */ + {"bho", {HB_TAG('B','H','O',' ')}}, /* Bhojpuri */ + {"bhr", {HB_TAG('M','L','G',' ')}}, /* Bara Malagasy -> Malagasy */ + {"bi", {HB_TAG('B','I','S',' ')}}, /* Bislama */ + {"bik", {HB_TAG('B','I','K',' ')}}, /* Bikol [macrolanguage] */ + {"bin", {HB_TAG('E','D','O',' ')}}, /* Edo */ + {"bjj", {HB_TAG('B','J','J',' ')}}, /* Kanauji */ + {"bjn", {HB_TAG('M','L','Y',' ')}}, /* Banjar -> Malay */ + {"bjq", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {"bjt", {HB_TAG('B','L','N',' ')}}, /* Balanta-Ganja -> Balante */ + {"bla", {HB_TAG('B','K','F',' ')}}, /* Siksika -> Blackfoot */ + {"ble", {HB_TAG('B','L','N',' ')}}, /* Balanta-Kentohe -> Balante */ + {"blk", {HB_TAG('B','L','K',' ')}}, /* Pa'o Karen */ + {"bln", {HB_TAG('B','I','K',' ')}}, /* Southern Catanduanes Bikol -> Bikol */ + {"bm", {HB_TAG('B','M','B',' ')}}, /* Bambara (Bamanankan) */ + {"bmm", {HB_TAG('M','L','G',' ')}}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {"bn", {HB_TAG('B','E','N',' ')}}, /* Bengali */ + {"bo", {HB_TAG('T','I','B',' ')}}, /* Tibetan */ + {"bpy", {HB_TAG('B','P','Y',' ')}}, /* Bishnupriya -> Bishnupriya Manipuri */ + {"bqi", {HB_TAG('L','R','C',' ')}}, /* Bakhtiari -> Luri */ + {"br", {HB_TAG('B','R','E',' ')}}, /* Breton */ + {"bra", {HB_TAG('B','R','I',' ')}}, /* Braj -> Braj Bhasha */ + {"brh", {HB_TAG('B','R','H',' ')}}, /* Brahui */ + {"brx", {HB_TAG('B','R','X',' ')}}, /* Bodo (India) */ + {"bs", {HB_TAG('B','O','S',' ')}}, /* Bosnian */ + {"bsk", {HB_TAG('B','S','K',' ')}}, /* Burushaski */ + {"btb", {HB_TAG('B','T','I',' ')}}, /* Beti (Cameroon) (retired code) */ + {"btj", {HB_TAG('M','L','Y',' ')}}, /* Bacanese Malay -> Malay */ + {"bto", {HB_TAG('B','I','K',' ')}}, /* Rinconada Bikol -> Bikol */ + {"bts", {HB_TAG('B','T','S',' ')}}, /* Batak Simalungun */ + {"bug", {HB_TAG('B','U','G',' ')}}, /* Buginese -> Bugis */ + {"bum", {HB_TAG('B','T','I',' ')}}, /* Bulu (Cameroon) -> Beti */ + {"bve", {HB_TAG('M','L','Y',' ')}}, /* Berau Malay -> Malay */ + {"bvu", {HB_TAG('M','L','Y',' ')}}, /* Bukit Malay -> Malay */ + {"bxk", {HB_TAG('L','U','H',' ')}}, /* Bukusu -> Luyia */ + {"bxp", {HB_TAG('B','T','I',' ')}}, /* Bebil -> Beti */ + {"bxr", {HB_TAG('R','B','U',' ')}}, /* Russia Buriat -> Russian Buriat */ + {"byn", {HB_TAG('B','I','L',' ')}}, /* Bilin -> Bilen */ + {"byv", {HB_TAG('B','Y','V',' ')}}, /* Medumba */ + {"bzc", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {"ca", {HB_TAG('C','A','T',' ')}}, /* Catalan */ + {"caf", {HB_TAG('C','R','R',' '), /* Southern Carrier -> Carrier */ + HB_TAG('A','T','H',' ')}}, /* Southern Carrier -> Athapaskan */ + {"cak", {HB_TAG('C','A','K',' ')}}, /* Kaqchikel */ + {"cbk", {HB_TAG('C','B','K',' ')}}, /* Chavacano -> Zamboanga Chavacano */ + {"cbl", {HB_TAG('Q','I','N',' ')}}, /* Bualkhaw Chin -> Chin */ + {"cco", {HB_TAG('C','C','H','N')}}, /* Comaltepec Chinantec -> Chinantec */ + {"ccq", {HB_TAG('A','R','K',' ')}}, /* Chaungtha (retired code) -> Rakhine */ + {"cdo", {HB_TAG('Z','H','S',' ')}}, /* Min Dong Chinese -> Chinese Simplified */ + {"ce", {HB_TAG('C','H','E',' ')}}, /* Chechen */ + {"ceb", {HB_TAG('C','E','B',' ')}}, /* Cebuano */ + {"cfm", {HB_TAG('H','A','L',' ')}}, /* Halam (Falam Chin) */ + {"cgg", {HB_TAG('C','G','G',' ')}}, /* Chiga */ + {"ch", {HB_TAG('C','H','A',' ')}}, /* Chamorro */ + {"chj", {HB_TAG('C','C','H','N')}}, /* Ojitlán Chinantec -> Chinantec */ + {"chk", {HB_TAG('C','H','K','0')}}, /* Chuukese */ + {"cho", {HB_TAG('C','H','O',' ')}}, /* Choctaw */ + {"chp", {HB_TAG('C','H','P',' '), /* Chipewyan */ + HB_TAG('S','A','Y',' '), /* Chipewyan -> Sayisi */ + HB_TAG('A','T','H',' ')}}, /* Chipewyan -> Athapaskan */ + {"chq", {HB_TAG('C','C','H','N')}}, /* Quiotepec Chinantec -> Chinantec */ + {"chr", {HB_TAG('C','H','R',' ')}}, /* Cherokee */ + {"chy", {HB_TAG('C','H','Y',' ')}}, /* Cheyenne */ + {"chz", {HB_TAG('C','C','H','N')}}, /* Ozumacín Chinantec -> Chinantec */ + {"ciw", {HB_TAG('O','J','B',' ')}}, /* Chippewa -> Ojibway */ + {"cja", {HB_TAG('C','J','A',' ')}}, /* Western Cham */ + {"cjm", {HB_TAG('C','J','M',' ')}}, /* Eastern Cham */ + {"cjy", {HB_TAG('Z','H','S',' ')}}, /* Jinyu Chinese -> Chinese Simplified */ + {"cka", {HB_TAG('Q','I','N',' ')}}, /* Khumi Awa Chin (retired code) -> Chin */ + {"ckb", {HB_TAG('K','U','R',' ')}}, /* Central Kurdish -> Kurdish */ + {"ckt", {HB_TAG('C','H','K',' ')}}, /* Chukot -> Chukchi */ + {"clc", {HB_TAG('A','T','H',' ')}}, /* Chilcotin -> Athapaskan */ + {"cld", {HB_TAG('S','Y','R',' ')}}, /* Chaldean Neo-Aramaic -> Syriac */ + {"cle", {HB_TAG('C','C','H','N')}}, /* Lealao Chinantec -> Chinantec */ + {"cmn", {HB_TAG('Z','H','S',' ')}}, /* Mandarin Chinese -> Chinese Simplified */ + {"cmr", {HB_TAG('Q','I','N',' ')}}, /* Mro-Khimi Chin -> Chin */ + {"cnb", {HB_TAG('Q','I','N',' ')}}, /* Chinbon Chin -> Chin */ + {"cnh", {HB_TAG('Q','I','N',' ')}}, /* Hakha Chin -> Chin */ + {"cnk", {HB_TAG('Q','I','N',' ')}}, /* Khumi Chin -> Chin */ + {"cnl", {HB_TAG('C','C','H','N')}}, /* Lalana Chinantec -> Chinantec */ + {"cnt", {HB_TAG('C','C','H','N')}}, /* Tepetotutla Chinantec -> Chinantec */ + {"cnw", {HB_TAG('Q','I','N',' ')}}, /* Ngawn Chin -> Chin */ + {"co", {HB_TAG('C','O','S',' ')}}, /* Corsican */ + {"coa", {HB_TAG('M','L','Y',' ')}}, /* Cocos Islands Malay -> Malay */ + {"cop", {HB_TAG('C','O','P',' ')}}, /* Coptic */ + {"coq", {HB_TAG('A','T','H',' ')}}, /* Coquille -> Athapaskan */ + {"cpa", {HB_TAG('C','C','H','N')}}, /* Palantla Chinantec -> Chinantec */ + {"cpe", {HB_TAG('C','P','P',' ')}}, /* English-based creoles and pidgins [family] -> Creoles */ + {"cpf", {HB_TAG('C','P','P',' ')}}, /* French-based creoles and pidgins [family] -> Creoles */ + {"cpp", {HB_TAG('C','P','P',' ')}}, /* Portuguese-based creoles and pidgins [family] -> Creoles */ + {"cpx", {HB_TAG('Z','H','S',' ')}}, /* Pu-Xian Chinese -> Chinese Simplified */ + {"cqd", {HB_TAG('H','M','N',' ')}}, /* Chuanqiandian Cluster Miao -> Hmong */ + {"cqu", {HB_TAG('Q','U','H',' ')}}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {"cr", {HB_TAG('C','R','E',' '), /* Cree [macrolanguage] */ + HB_TAG('Y','C','R',' ')}}, /* Cree [macrolanguage] -> Y-Cree */ + {"crh", {HB_TAG('C','R','T',' ')}}, /* Crimean Tatar */ + {"crj", {HB_TAG('E','C','R',' ')}}, /* Southern East Cree -> Eastern Cree */ + {"crk", {HB_TAG('W','C','R',' ')}}, /* Plains Cree -> West-Cree */ + {"crl", {HB_TAG('E','C','R',' ')}}, /* Northern East Cree -> Eastern Cree */ + {"crm", {HB_TAG('M','C','R',' '), /* Moose Cree */ + HB_TAG('L','C','R',' ')}}, /* Moose Cree -> L-Cree */ + {"crp", {HB_TAG('C','P','P',' ')}}, /* Creoles and pidgins [family] -> Creoles */ + {"crx", {HB_TAG('C','R','R',' '), /* Carrier */ + HB_TAG('A','T','H',' ')}}, /* Carrier -> Athapaskan */ + {"cs", {HB_TAG('C','S','Y',' ')}}, /* Czech */ + {"csa", {HB_TAG('C','C','H','N')}}, /* Chiltepec Chinantec -> Chinantec */ + {"csb", {HB_TAG('C','S','B',' ')}}, /* Kashubian */ + {"csh", {HB_TAG('Q','I','N',' ')}}, /* Asho Chin -> Chin */ + {"cso", {HB_TAG('C','C','H','N')}}, /* Sochiapam Chinantec -> Chinantec */ + {"csw", {HB_TAG('N','C','R',' '), /* Swampy Cree -> N-Cree */ + HB_TAG('N','H','C',' ')}}, /* Swampy Cree -> Norway House Cree */ + {"csy", {HB_TAG('Q','I','N',' ')}}, /* Siyin Chin -> Chin */ + {"ctc", {HB_TAG('A','T','H',' ')}}, /* Chetco -> Athapaskan */ + {"ctd", {HB_TAG('Q','I','N',' ')}}, /* Tedim Chin -> Chin */ + {"cte", {HB_TAG('C','C','H','N')}}, /* Tepinapa Chinantec -> Chinantec */ + {"ctg", {HB_TAG('C','T','G',' ')}}, /* Chittagonian */ + {"ctl", {HB_TAG('C','C','H','N')}}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {"cts", {HB_TAG('B','I','K',' ')}}, /* Northern Catanduanes Bikol -> Bikol */ + {"cu", {HB_TAG('C','S','L',' ')}}, /* Church Slavonic */ + {"cuc", {HB_TAG('C','C','H','N')}}, /* Usila Chinantec -> Chinantec */ + {"cuk", {HB_TAG('C','U','K',' ')}}, /* San Blas Kuna */ + {"cv", {HB_TAG('C','H','U',' ')}}, /* Chuvash */ + {"cvn", {HB_TAG('C','C','H','N')}}, /* Valle Nacional Chinantec -> Chinantec */ + {"cwd", {HB_TAG('D','C','R',' '), /* Woods Cree */ + HB_TAG('T','C','R',' ')}}, /* Woods Cree -> TH-Cree */ + {"cy", {HB_TAG('W','E','L',' ')}}, /* Welsh */ + {"czh", {HB_TAG('Z','H','S',' ')}}, /* Huizhou Chinese -> Chinese Simplified */ + {"czo", {HB_TAG('Z','H','S',' ')}}, /* Min Zhong Chinese -> Chinese Simplified */ + {"czt", {HB_TAG('Q','I','N',' ')}}, /* Zotung Chin -> Chin */ + {"da", {HB_TAG('D','A','N',' ')}}, /* Danish */ + {"dao", {HB_TAG('Q','I','N',' ')}}, /* Daai Chin -> Chin */ + {"dap", {HB_TAG('N','I','S',' ')}}, /* Nisi (India) (retired code) */ + {"dar", {HB_TAG('D','A','R',' ')}}, /* Dargwa */ + {"dax", {HB_TAG('D','A','X',' ')}}, /* Dayi */ + {"de", {HB_TAG('D','E','U',' ')}}, /* German */ + {"den", {HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + {"dgo", {HB_TAG('D','G','O',' ')}}, /* Dogri */ + {"dgr", {HB_TAG('A','T','H',' ')}}, /* Dogrib -> Athapaskan */ + {"dhd", {HB_TAG('M','A','W',' ')}}, /* Dhundari -> Marwari */ + {"dhg", {HB_TAG('D','H','G',' ')}}, /* Dhangu */ + {"dib", {HB_TAG('D','N','K',' ')}}, /* South Central Dinka -> Dinka */ + {"dik", {HB_TAG('D','N','K',' ')}}, /* Southwestern Dinka -> Dinka */ + {"din", {HB_TAG('D','N','K',' ')}}, /* Dinka [macrolanguage] */ + {"dip", {HB_TAG('D','N','K',' ')}}, /* Northeastern Dinka -> Dinka */ + {"diq", {HB_TAG('D','I','Q',' ')}}, /* Dimli */ + {"diw", {HB_TAG('D','N','K',' ')}}, /* Northwestern Dinka -> Dinka */ + {"dje", {HB_TAG('D','J','R',' ')}}, /* Zarma */ + {"djr", {HB_TAG('D','J','R','0')}}, /* Djambarrpuyngu */ + {"dks", {HB_TAG('D','N','K',' ')}}, /* Southeastern Dinka -> Dinka */ + {"dng", {HB_TAG('D','U','N',' ')}}, /* Dungan */ + {"dnj", {HB_TAG('D','N','J',' ')}}, /* Dan */ + {"doi", {HB_TAG('D','G','R',' ')}}, /* Dogri [macrolanguage] */ + {"drh", {HB_TAG('M','N','G',' ')}}, /* Darkhat (retired code) -> Mongolian */ + {"drw", {HB_TAG('D','R','I',' ')}}, /* Darwazi (retired code) -> Dari */ + {"dsb", {HB_TAG('L','S','B',' ')}}, /* Lower Sorbian */ + {"dty", {HB_TAG('N','E','P',' ')}}, /* Dotyali -> Nepali */ + {"duj", {HB_TAG('D','U','J',' ')}}, /* Dhuwal (retired code) */ + {"dup", {HB_TAG('M','L','Y',' ')}}, /* Duano -> Malay */ + {"dv", {HB_TAG('D','I','V',' '), /* Divehi (Dhivehi, Maldivian) */ + HB_TAG('D','H','V',' ')}}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {"dwu", {HB_TAG('D','U','J',' ')}}, /* Dhuwal */ + {"dwy", {HB_TAG('D','U','J',' ')}}, /* Dhuwaya -> Dhuwal */ + {"dyu", {HB_TAG('J','U','L',' ')}}, /* Dyula -> Jula */ + {"dz", {HB_TAG('D','Z','N',' ')}}, /* Dzongkha */ + {"ee", {HB_TAG('E','W','E',' ')}}, /* Ewe */ + {"efi", {HB_TAG('E','F','I',' ')}}, /* Efik */ + {"ekk", {HB_TAG('E','T','I',' ')}}, /* Standard Estonian -> Estonian */ + {"el", {HB_TAG('E','L','L',' ')}}, /* Modern Greek (1453-) -> Greek */ + {"emk", {HB_TAG('E','M','K',' '), /* Eastern Maninkakan */ + HB_TAG('M','N','K',' ')}}, /* Eastern Maninkakan -> Maninka */ + {"en", {HB_TAG('E','N','G',' ')}}, /* English */ + {"enb", {HB_TAG('K','A','L',' ')}}, /* Markweeta -> Kalenjin */ + {"enf", {HB_TAG('F','N','E',' ')}}, /* Forest Enets -> Forest Nenets */ + {"enh", {HB_TAG('T','N','E',' ')}}, /* Tundra Enets -> Tundra Nenets */ + {"eo", {HB_TAG('N','T','O',' ')}}, /* Esperanto */ + {"es", {HB_TAG('E','S','P',' ')}}, /* Spanish */ + {"esg", {HB_TAG('G','O','N',' ')}}, /* Aheri Gondi -> Gondi */ + {"esi", {HB_TAG('I','P','K',' ')}}, /* North Alaskan Inupiatun -> Inupiat */ + {"esk", {HB_TAG('I','P','K',' ')}}, /* Northwest Alaska Inupiatun -> Inupiat */ + {"esu", {HB_TAG('E','S','U',' ')}}, /* Central Yupik */ + {"et", {HB_TAG('E','T','I',' ')}}, /* Estonian [macrolanguage] */ + {"eto", {HB_TAG('B','T','I',' ')}}, /* Eton (Cameroon) -> Beti */ + {"eu", {HB_TAG('E','U','Q',' ')}}, /* Basque */ + {"eve", {HB_TAG('E','V','N',' ')}}, /* Even */ + {"evn", {HB_TAG('E','V','K',' ')}}, /* Evenki */ + {"ewo", {HB_TAG('B','T','I',' ')}}, /* Ewondo -> Beti */ + {"eyo", {HB_TAG('K','A','L',' ')}}, /* Keiyo -> Kalenjin */ + {"fa", {HB_TAG('F','A','R',' ')}}, /* Persian [macrolanguage] */ + {"fan", {HB_TAG('F','A','N','0')}}, /* Fang (Equatorial Guinea) */ + {"fat", {HB_TAG('F','A','T',' ')}}, /* Fanti */ + {"fbl", {HB_TAG('B','I','K',' ')}}, /* West Albay Bikol -> Bikol */ + {"ff", {HB_TAG('F','U','L',' ')}}, /* Fulah [macrolanguage] */ + {"ffm", {HB_TAG('F','U','L',' ')}}, /* Maasina Fulfulde -> Fulah */ + {"fi", {HB_TAG('F','I','N',' ')}}, /* Finnish */ + {"fil", {HB_TAG('P','I','L',' ')}}, /* Filipino */ + {"fj", {HB_TAG('F','J','I',' ')}}, /* Fijian */ + {"flm", {HB_TAG('H','A','L',' '), /* Halam (Falam Chin) (retired code) */ + HB_TAG('Q','I','N',' ')}}, /* Falam Chin (retired code) -> Chin */ + {"fmp", {HB_TAG('F','M','P',' ')}}, /* Fe'fe' */ + {"fo", {HB_TAG('F','O','S',' ')}}, /* Faroese */ + {"fon", {HB_TAG('F','O','N',' ')}}, /* Fon */ + {"fr", {HB_TAG('F','R','A',' ')}}, /* French */ + {"frc", {HB_TAG('F','R','C',' ')}}, /* Cajun French */ + {"frp", {HB_TAG('F','R','P',' ')}}, /* Arpitan */ + {"fub", {HB_TAG('F','U','L',' ')}}, /* Adamawa Fulfulde -> Fulah */ + {"fuc", {HB_TAG('F','U','L',' ')}}, /* Pulaar -> Fulah */ + {"fue", {HB_TAG('F','U','L',' ')}}, /* Borgu Fulfulde -> Fulah */ + {"fuf", {HB_TAG('F','T','A',' ')}}, /* Pular -> Futa */ + {"fuh", {HB_TAG('F','U','L',' ')}}, /* Western Niger Fulfulde -> Fulah */ + {"fui", {HB_TAG('F','U','L',' ')}}, /* Bagirmi Fulfulde -> Fulah */ + {"fuq", {HB_TAG('F','U','L',' ')}}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {"fur", {HB_TAG('F','R','L',' ')}}, /* Friulian */ + {"fuv", {HB_TAG('F','U','V',' ')}}, /* Nigerian Fulfulde */ + {"fy", {HB_TAG('F','R','I',' ')}}, /* Western Frisian -> Frisian */ + {"ga", {HB_TAG('I','R','I',' ')}}, /* Irish */ + {"gaa", {HB_TAG('G','A','D',' ')}}, /* Ga */ + {"gag", {HB_TAG('G','A','G',' ')}}, /* Gagauz */ + {"gan", {HB_TAG('Z','H','S',' ')}}, /* Gan Chinese -> Chinese Simplified */ + {"gax", {HB_TAG('O','R','O',' ')}}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {"gaz", {HB_TAG('O','R','O',' ')}}, /* West Central Oromo -> Oromo */ + {"gbm", {HB_TAG('G','A','W',' ')}}, /* Garhwali */ + {"gce", {HB_TAG('A','T','H',' ')}}, /* Galice -> Athapaskan */ + {"gd", {HB_TAG('G','A','E',' ')}}, /* Scottish Gaelic (Gaelic) */ + {"gda", {HB_TAG('R','A','J',' ')}}, /* Gade Lohar -> Rajasthani */ + {"gez", {HB_TAG('G','E','Z',' ')}}, /* Geez */ + {"ggo", {HB_TAG('G','O','N',' ')}}, /* Southern Gondi (retired code) -> Gondi */ + {"gih", {HB_TAG('G','I','H',' ')}}, /* Githabul */ + {"gil", {HB_TAG('G','I','L','0')}}, /* Kiribati (Gilbertese) */ + {"gju", {HB_TAG('R','A','J',' ')}}, /* Gujari -> Rajasthani */ + {"gkp", {HB_TAG('G','K','P',' ')}}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {"gl", {HB_TAG('G','A','L',' ')}}, /* Galician */ + {"gld", {HB_TAG('N','A','N',' ')}}, /* Nanai */ + {"glk", {HB_TAG('G','L','K',' ')}}, /* Gilaki */ + {"gn", {HB_TAG('G','U','A',' ')}}, /* Guarani [macrolanguage] */ + {"gnn", {HB_TAG('G','N','N',' ')}}, /* Gumatj */ + {"gno", {HB_TAG('G','O','N',' ')}}, /* Northern Gondi -> Gondi */ + {"gnw", {HB_TAG('G','U','A',' ')}}, /* Western Bolivian Guaraní -> Guarani */ + {"gog", {HB_TAG('G','O','G',' ')}}, /* Gogo */ + {"gom", {HB_TAG('K','O','K',' ')}}, /* Goan Konkani -> Konkani */ + {"gon", {HB_TAG('G','O','N',' ')}}, /* Gondi [macrolanguage] */ + {"grt", {HB_TAG('G','R','O',' ')}}, /* Garo */ + {"gru", {HB_TAG('S','O','G',' ')}}, /* Kistane -> Sodo Gurage */ + {"gsw", {HB_TAG('A','L','S',' ')}}, /* Alsatian */ + {"gu", {HB_TAG('G','U','J',' ')}}, /* Gujarati */ + {"guc", {HB_TAG('G','U','C',' ')}}, /* Wayuu */ + {"guf", {HB_TAG('G','U','F',' ')}}, /* Gupapuyngu */ + {"gug", {HB_TAG('G','U','A',' ')}}, /* Paraguayan Guaraní -> Guarani */ + {"gui", {HB_TAG('G','U','A',' ')}}, /* Eastern Bolivian Guaraní -> Guarani */ + {"guk", {HB_TAG('G','M','Z',' '), /* Gumuz */ + HB_TAG('G','U','K',' ')}}, /* Gumuz (SIL fonts) */ + {"gun", {HB_TAG('G','U','A',' ')}}, /* Mbyá Guaraní -> Guarani */ + {"guz", {HB_TAG('G','U','Z',' ')}}, /* Gusii */ + {"gv", {HB_TAG('M','N','X',' ')}}, /* Manx */ + {"gwi", {HB_TAG('A','T','H',' ')}}, /* Gwichʼin -> Athapaskan */ + {"ha", {HB_TAG('H','A','U',' ')}}, /* Hausa */ + {"haa", {HB_TAG('A','T','H',' ')}}, /* Han -> Athapaskan */ + {"hae", {HB_TAG('O','R','O',' ')}}, /* Eastern Oromo -> Oromo */ + {"hak", {HB_TAG('Z','H','S',' ')}}, /* Hakka Chinese -> Chinese Simplified */ + {"har", {HB_TAG('H','R','I',' ')}}, /* Harari */ + {"haw", {HB_TAG('H','A','W',' ')}}, /* Hawaiian */ + {"hay", {HB_TAG('H','A','Y',' ')}}, /* Haya */ + {"haz", {HB_TAG('H','A','Z',' ')}}, /* Hazaragi */ + {"he", {HB_TAG('I','W','R',' ')}}, /* Hebrew */ + {"hea", {HB_TAG('H','M','N',' ')}}, /* Northern Qiandong Miao -> Hmong */ + {"hi", {HB_TAG('H','I','N',' ')}}, /* Hindi */ + {"hil", {HB_TAG('H','I','L',' ')}}, /* Hiligaynon */ + {"hji", {HB_TAG('M','L','Y',' ')}}, /* Haji -> Malay */ + {"hlt", {HB_TAG('Q','I','N',' ')}}, /* Matu Chin -> Chin */ + {"hma", {HB_TAG('H','M','N',' ')}}, /* Southern Mashan Hmong -> Hmong */ + {"hmc", {HB_TAG('H','M','N',' ')}}, /* Central Huishui Hmong -> Hmong */ + {"hmd", {HB_TAG('H','M','N',' ')}}, /* Large Flowery Miao -> Hmong */ + {"hme", {HB_TAG('H','M','N',' ')}}, /* Eastern Huishui Hmong -> Hmong */ + {"hmg", {HB_TAG('H','M','N',' ')}}, /* Southwestern Guiyang Hmong -> Hmong */ + {"hmh", {HB_TAG('H','M','N',' ')}}, /* Southwestern Huishui Hmong -> Hmong */ + {"hmi", {HB_TAG('H','M','N',' ')}}, /* Northern Huishui Hmong -> Hmong */ + {"hmj", {HB_TAG('H','M','N',' ')}}, /* Ge -> Hmong */ + {"hml", {HB_TAG('H','M','N',' ')}}, /* Luopohe Hmong -> Hmong */ + {"hmm", {HB_TAG('H','M','N',' ')}}, /* Central Mashan Hmong -> Hmong */ + {"hmn", {HB_TAG('H','M','N',' ')}}, /* Hmong [macrolanguage] */ + {"hmp", {HB_TAG('H','M','N',' ')}}, /* Northern Mashan Hmong -> Hmong */ + {"hmq", {HB_TAG('H','M','N',' ')}}, /* Eastern Qiandong Miao -> Hmong */ + {"hms", {HB_TAG('H','M','N',' ')}}, /* Southern Qiandong Miao -> Hmong */ + {"hmw", {HB_TAG('H','M','N',' ')}}, /* Western Mashan Hmong -> Hmong */ + {"hmy", {HB_TAG('H','M','N',' ')}}, /* Southern Guiyang Hmong -> Hmong */ + {"hmz", {HB_TAG('H','M','N',' ')}}, /* Hmong Shua -> Hmong */ + {"hnd", {HB_TAG('H','N','D',' ')}}, /* Southern Hindko -> Hindko */ + {"hne", {HB_TAG('C','H','H',' ')}}, /* Chhattisgarhi -> Chattisgarhi */ + {"hnj", {HB_TAG('H','M','N',' ')}}, /* Hmong Njua -> Hmong */ + {"hno", {HB_TAG('H','N','D',' ')}}, /* Northern Hindko -> Hindko */ + {"ho", {HB_TAG('H','M','O',' ')}}, /* Hiri Motu */ + {"hoc", {HB_TAG('H','O',' ',' ')}}, /* Ho */ + {"hoi", {HB_TAG('A','T','H',' ')}}, /* Holikachuk -> Athapaskan */ + {"hoj", {HB_TAG('H','A','R',' ')}}, /* Hadothi -> Harauti */ + {"hr", {HB_TAG('H','R','V',' ')}}, /* Croatian */ + {"hrm", {HB_TAG('H','M','N',' ')}}, /* Horned Miao -> Hmong */ + {"hsb", {HB_TAG('U','S','B',' ')}}, /* Upper Sorbian */ + {"hsn", {HB_TAG('Z','H','S',' ')}}, /* Xiang Chinese -> Chinese Simplified */ + {"ht", {HB_TAG('H','A','I',' ')}}, /* Haitian (Haitian Creole) */ + {"hu", {HB_TAG('H','U','N',' ')}}, /* Hungarian */ + {"huj", {HB_TAG('H','M','N',' ')}}, /* Northern Guiyang Hmong -> Hmong */ + {"hup", {HB_TAG('A','T','H',' ')}}, /* Hupa -> Athapaskan */ + {"hy", {HB_TAG('H','Y','E','0'), /* Armenian -> Armenian East */ + HB_TAG('H','Y','E',' ')}}, /* Armenian */ + {"hyw", {HB_TAG('H','Y','E',' ')}}, /* Western Armenian -> Armenian */ + {"hz", {HB_TAG('H','E','R',' ')}}, /* Herero */ + {"ia", {HB_TAG('I','N','A',' ')}}, /* Interlingua (International Auxiliary Language Association) */ + {"iba", {HB_TAG('I','B','A',' ')}}, /* Iban */ + {"ibb", {HB_TAG('I','B','B',' ')}}, /* Ibibio */ + {"id", {HB_TAG('I','N','D',' ')}}, /* Indonesian */ + {"ida", {HB_TAG('L','U','H',' ')}}, /* Idakho-Isukha-Tiriki -> Luyia */ + {"ie", {HB_TAG('I','L','E',' ')}}, /* Interlingue */ + {"ig", {HB_TAG('I','B','O',' ')}}, /* Igbo */ + {"igb", {HB_TAG('E','B','I',' ')}}, /* Ebira */ + {"ii", {HB_TAG('Y','I','M',' ')}}, /* Sichuan Yi -> Yi Modern */ + {"ijc", {HB_TAG('I','J','O',' ')}}, /* Izon -> Ijo */ + {"ijo", {HB_TAG('I','J','O',' ')}}, /* Ijo [family] */ + {"ik", {HB_TAG('I','P','K',' ')}}, /* Inupiaq [macrolanguage] -> Inupiat */ + {"ike", {HB_TAG('I','N','U',' ')}}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {"ikt", {HB_TAG('I','N','U',' ')}}, /* Inuinnaqtun -> Inuktitut */ + {"ilo", {HB_TAG('I','L','O',' ')}}, /* Iloko -> Ilokano */ + {"in", {HB_TAG('I','N','D',' ')}}, /* Indonesian (retired code) */ + {"ing", {HB_TAG('A','T','H',' ')}}, /* Degexit'an -> Athapaskan */ + {"inh", {HB_TAG('I','N','G',' ')}}, /* Ingush */ + {"io", {HB_TAG('I','D','O',' ')}}, /* Ido */ + {"is", {HB_TAG('I','S','L',' ')}}, /* Icelandic */ + {"it", {HB_TAG('I','T','A',' ')}}, /* Italian */ + {"iu", {HB_TAG('I','N','U',' ')}}, /* Inuktitut [macrolanguage] */ + {"iw", {HB_TAG('I','W','R',' ')}}, /* Hebrew (retired code) */ + {"ja", {HB_TAG('J','A','N',' ')}}, /* Japanese */ + {"jak", {HB_TAG('M','L','Y',' ')}}, /* Jakun -> Malay */ + {"jam", {HB_TAG('J','A','M',' ')}}, /* Jamaican Creole English -> Jamaican Creole */ + {"jax", {HB_TAG('M','L','Y',' ')}}, /* Jambi Malay -> Malay */ + {"jbo", {HB_TAG('J','B','O',' ')}}, /* Lojban */ + {"jct", {HB_TAG('J','C','T',' ')}}, /* Krymchak */ + {"ji", {HB_TAG('J','I','I',' ')}}, /* Yiddish (retired code) */ + {"jv", {HB_TAG('J','A','V',' ')}}, /* Javanese */ + {"jw", {HB_TAG('J','A','V',' ')}}, /* Javanese (retired code) */ + {"ka", {HB_TAG('K','A','T',' ')}}, /* Georgian */ + {"kaa", {HB_TAG('K','R','K',' ')}}, /* Kara-Kalpak -> Karakalpak */ + {"kab", {HB_TAG('K','A','B','0')}}, /* Kabyle */ + {"kam", {HB_TAG('K','M','B',' ')}}, /* Kamba (Kenya) */ + {"kar", {HB_TAG('K','R','N',' ')}}, /* Karen [family] */ + {"kbd", {HB_TAG('K','A','B',' ')}}, /* Kabardian */ + {"kby", {HB_TAG('K','N','R',' ')}}, /* Manga Kanuri -> Kanuri */ + {"kca", {HB_TAG('K','H','K',' '), /* Khanty -> Khanty-Kazim */ + HB_TAG('K','H','S',' '), /* Khanty -> Khanty-Shurishkar */ + HB_TAG('K','H','V',' ')}}, /* Khanty -> Khanty-Vakhi */ + {"kde", {HB_TAG('K','D','E',' ')}}, /* Makonde */ + {"kdr", {HB_TAG('K','R','M',' ')}}, /* Karaim */ + {"kdt", {HB_TAG('K','U','Y',' ')}}, /* Kuy */ + {"kea", {HB_TAG('K','E','A',' ')}}, /* Kabuverdianu (Crioulo) */ + {"kek", {HB_TAG('K','E','K',' ')}}, /* Kekchi */ + {"kex", {HB_TAG('K','K','N',' ')}}, /* Kukna -> Kokni */ + {"kfa", {HB_TAG('K','O','D',' ')}}, /* Kodava -> Kodagu */ + {"kfr", {HB_TAG('K','A','C',' ')}}, /* Kachhi -> Kachchi */ + {"kfx", {HB_TAG('K','U','L',' ')}}, /* Kullu Pahari -> Kulvi */ + {"kfy", {HB_TAG('K','M','N',' ')}}, /* Kumaoni */ + {"kg", {HB_TAG('K','O','N','0')}}, /* Kongo [macrolanguage] */ + {"kha", {HB_TAG('K','S','I',' ')}}, /* Khasi */ + {"khb", {HB_TAG('X','B','D',' ')}}, /* Lü */ + {"khk", {HB_TAG('M','N','G',' ')}}, /* Halh Mongolian -> Mongolian */ + {"kht", {HB_TAG('K','H','N',' '), /* Khamti -> Khamti Shan (Microsoft fonts) */ + HB_TAG('K','H','T',' ')}}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */ + {"khw", {HB_TAG('K','H','W',' ')}}, /* Khowar */ + {"ki", {HB_TAG('K','I','K',' ')}}, /* Kikuyu (Gikuyu) */ + {"kiu", {HB_TAG('K','I','U',' ')}}, /* Kirmanjki */ + {"kj", {HB_TAG('K','U','A',' ')}}, /* Kuanyama */ + {"kjd", {HB_TAG('K','J','D',' ')}}, /* Southern Kiwai */ + {"kjh", {HB_TAG('K','H','A',' ')}}, /* Khakas -> Khakass */ + {"kjp", {HB_TAG('K','J','P',' ')}}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {"kjz", {HB_TAG('K','J','Z',' ')}}, /* Bumthangkha */ + {"kk", {HB_TAG('K','A','Z',' ')}}, /* Kazakh */ + {"kkz", {HB_TAG('A','T','H',' ')}}, /* Kaska -> Athapaskan */ + {"kl", {HB_TAG('G','R','N',' ')}}, /* Greenlandic */ + {"kln", {HB_TAG('K','A','L',' ')}}, /* Kalenjin [macrolanguage] */ + {"km", {HB_TAG('K','H','M',' ')}}, /* Khmer */ + {"kmb", {HB_TAG('M','B','N',' ')}}, /* Kimbundu -> Mbundu */ + {"kmr", {HB_TAG('K','U','R',' ')}}, /* Northern Kurdish -> Kurdish */ + {"kmw", {HB_TAG('K','M','O',' ')}}, /* Komo (Democratic Republic of Congo) */ + {"kmz", {HB_TAG('K','M','Z',' ')}}, /* Khorasani Turkish -> Khorasani Turkic */ + {"kn", {HB_TAG('K','A','N',' ')}}, /* Kannada */ + {"knc", {HB_TAG('K','N','R',' ')}}, /* Central Kanuri -> Kanuri */ + {"kng", {HB_TAG('K','O','N','0')}}, /* Koongo -> Kongo */ + {"knn", {HB_TAG('K','O','K',' ')}}, /* Konkani */ + {"ko", {HB_TAG('K','O','R',' ')}}, /* Korean */ + {"koi", {HB_TAG('K','O','P',' ')}}, /* Komi-Permyak */ + {"kok", {HB_TAG('K','O','K',' ')}}, /* Konkani [macrolanguage] */ + {"kos", {HB_TAG('K','O','S',' ')}}, /* Kosraean */ + {"koy", {HB_TAG('A','T','H',' ')}}, /* Koyukon -> Athapaskan */ + {"kpe", {HB_TAG('K','P','L',' ')}}, /* Kpelle [macrolanguage] */ + {"kpv", {HB_TAG('K','O','Z',' ')}}, /* Komi-Zyrian */ + {"kpy", {HB_TAG('K','Y','K',' ')}}, /* Koryak */ + {"kqs", {HB_TAG('K','I','S',' ')}}, /* Northern Kissi -> Kisii */ + {"kqy", {HB_TAG('K','R','T',' ')}}, /* Koorete */ + {"kr", {HB_TAG('K','N','R',' ')}}, /* Kanuri [macrolanguage] */ + {"krc", {HB_TAG('K','A','R',' '), /* Karachay-Balkar -> Karachay */ + HB_TAG('B','A','L',' ')}}, /* Karachay-Balkar -> Balkar */ + {"kri", {HB_TAG('K','R','I',' ')}}, /* Krio */ + {"krl", {HB_TAG('K','R','L',' ')}}, /* Karelian */ + {"krt", {HB_TAG('K','N','R',' ')}}, /* Tumari Kanuri -> Kanuri */ + {"kru", {HB_TAG('K','U','U',' ')}}, /* Kurukh */ + {"ks", {HB_TAG('K','S','H',' ')}}, /* Kashmiri */ + {"ksh", {HB_TAG('K','S','H','0')}}, /* Kölsch -> Ripuarian */ + {"kss", {HB_TAG('K','I','S',' ')}}, /* Southern Kisi -> Kisii */ + {"ksw", {HB_TAG('K','S','W',' ')}}, /* S’gaw Karen */ + {"ktb", {HB_TAG('K','E','B',' ')}}, /* Kambaata -> Kebena */ + {"ktu", {HB_TAG('K','O','N',' ')}}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {"ktw", {HB_TAG('A','T','H',' ')}}, /* Kato -> Athapaskan */ + {"ku", {HB_TAG('K','U','R',' ')}}, /* Kurdish [macrolanguage] */ + {"kum", {HB_TAG('K','U','M',' ')}}, /* Kumyk */ + {"kuu", {HB_TAG('A','T','H',' ')}}, /* Upper Kuskokwim -> Athapaskan */ + {"kv", {HB_TAG('K','O','M',' ')}}, /* Komi [macrolanguage] */ + {"kvb", {HB_TAG('M','L','Y',' ')}}, /* Kubu -> Malay */ + {"kvr", {HB_TAG('M','L','Y',' ')}}, /* Kerinci -> Malay */ + {"kw", {HB_TAG('C','O','R',' ')}}, /* Cornish */ + {"kwy", {HB_TAG('K','O','N','0')}}, /* San Salvador Kongo -> Kongo */ + {"kxc", {HB_TAG('K','M','S',' ')}}, /* Konso -> Komso */ + {"kxd", {HB_TAG('M','L','Y',' ')}}, /* Brunei -> Malay */ + {"kxu", {HB_TAG('K','U','I',' ')}}, /* Kui (India) */ + {"ky", {HB_TAG('K','I','R',' ')}}, /* Kirghiz (Kyrgyz) */ + {"kyu", {HB_TAG('K','Y','U',' ')}}, /* Western Kayah */ + {"la", {HB_TAG('L','A','T',' ')}}, /* Latin */ + {"lad", {HB_TAG('J','U','D',' ')}}, /* Ladino */ + {"lb", {HB_TAG('L','T','Z',' ')}}, /* Luxembourgish */ + {"lbe", {HB_TAG('L','A','K',' ')}}, /* Lak */ + {"lbj", {HB_TAG('L','D','K',' ')}}, /* Ladakhi */ + {"lbl", {HB_TAG('B','I','K',' ')}}, /* Libon Bikol -> Bikol */ + {"lce", {HB_TAG('M','L','Y',' ')}}, /* Loncong -> Malay */ + {"lcf", {HB_TAG('M','L','Y',' ')}}, /* Lubu -> Malay */ + {"ldi", {HB_TAG('K','O','N','0')}}, /* Laari -> Kongo */ + {"lez", {HB_TAG('L','E','Z',' ')}}, /* Lezghian -> Lezgi */ + {"lg", {HB_TAG('L','U','G',' ')}}, /* Ganda */ + {"li", {HB_TAG('L','I','M',' ')}}, /* Limburgish */ + {"lif", {HB_TAG('L','M','B',' ')}}, /* Limbu */ + {"lij", {HB_TAG('L','I','J',' ')}}, /* Ligurian */ + {"lis", {HB_TAG('L','I','S',' ')}}, /* Lisu */ + {"liw", {HB_TAG('M','L','Y',' ')}}, /* Col -> Malay */ + {"ljp", {HB_TAG('L','J','P',' ')}}, /* Lampung Api -> Lampung */ + {"lkb", {HB_TAG('L','U','H',' ')}}, /* Kabras -> Luyia */ + {"lki", {HB_TAG('L','K','I',' ')}}, /* Laki */ + {"lko", {HB_TAG('L','U','H',' ')}}, /* Khayo -> Luyia */ + {"lks", {HB_TAG('L','U','H',' ')}}, /* Kisa -> Luyia */ + {"lld", {HB_TAG('L','A','D',' ')}}, /* Ladin */ + {"lmn", {HB_TAG('L','A','M',' ')}}, /* Lambadi -> Lambani */ + {"lmo", {HB_TAG('L','M','O',' ')}}, /* Lombard */ + {"ln", {HB_TAG('L','I','N',' ')}}, /* Lingala */ + {"lo", {HB_TAG('L','A','O',' ')}}, /* Lao */ + {"lom", {HB_TAG('L','O','M',' ')}}, /* Loma (Liberia) */ + {"lrc", {HB_TAG('L','R','C',' ')}}, /* Northern Luri -> Luri */ + {"lri", {HB_TAG('L','U','H',' ')}}, /* Marachi -> Luyia */ + {"lrm", {HB_TAG('L','U','H',' ')}}, /* Marama -> Luyia */ + {"lsm", {HB_TAG('L','U','H',' ')}}, /* Saamia -> Luyia */ + {"lt", {HB_TAG('L','T','H',' ')}}, /* Lithuanian */ + {"ltg", {HB_TAG('L','V','I',' ')}}, /* Latgalian -> Latvian */ + {"lto", {HB_TAG('L','U','H',' ')}}, /* Tsotso -> Luyia */ + {"lts", {HB_TAG('L','U','H',' ')}}, /* Tachoni -> Luyia */ + {"lu", {HB_TAG('L','U','B',' ')}}, /* Luba-Katanga */ + {"lua", {HB_TAG('L','U','A',' ')}}, /* Luba-Lulua */ + {"luo", {HB_TAG('L','U','O',' ')}}, /* Luo (Kenya and Tanzania) */ + {"lus", {HB_TAG('M','I','Z',' ')}}, /* Lushai -> Mizo */ + {"luy", {HB_TAG('L','U','H',' ')}}, /* Luyia [macrolanguage] */ + {"luz", {HB_TAG('L','R','C',' ')}}, /* Southern Luri -> Luri */ + {"lv", {HB_TAG('L','V','I',' ')}}, /* Latvian [macrolanguage] */ + {"lvs", {HB_TAG('L','V','I',' ')}}, /* Standard Latvian -> Latvian */ + {"lwg", {HB_TAG('L','U','H',' ')}}, /* Wanga -> Luyia */ + {"lzh", {HB_TAG('Z','H','T',' ')}}, /* Literary Chinese -> Chinese Traditional */ + {"lzz", {HB_TAG('L','A','Z',' ')}}, /* Laz */ + {"mad", {HB_TAG('M','A','D',' ')}}, /* Madurese -> Madura */ + {"mag", {HB_TAG('M','A','G',' ')}}, /* Magahi */ + {"mai", {HB_TAG('M','T','H',' ')}}, /* Maithili */ + {"mak", {HB_TAG('M','K','R',' ')}}, /* Makasar */ + {"mam", {HB_TAG('M','A','M',' ')}}, /* Mam */ + {"man", {HB_TAG('M','N','K',' ')}}, /* Mandingo [macrolanguage] -> Maninka */ + {"max", {HB_TAG('M','L','Y',' ')}}, /* North Moluccan Malay -> Malay */ + {"mbo", {HB_TAG('M','B','O',' ')}}, /* Mbo (Cameroon) */ + {"mct", {HB_TAG('B','T','I',' ')}}, /* Mengisa -> Beti */ + {"mdf", {HB_TAG('M','O','K',' ')}}, /* Moksha */ + {"mdr", {HB_TAG('M','D','R',' ')}}, /* Mandar */ + {"mdy", {HB_TAG('M','L','E',' ')}}, /* Male (Ethiopia) */ + {"men", {HB_TAG('M','D','E',' ')}}, /* Mende (Sierra Leone) */ + {"meo", {HB_TAG('M','L','Y',' ')}}, /* Kedah Malay -> Malay */ + {"mer", {HB_TAG('M','E','R',' ')}}, /* Meru */ + {"mfa", {HB_TAG('M','F','A',' ')}}, /* Pattani Malay */ + {"mfb", {HB_TAG('M','L','Y',' ')}}, /* Bangka -> Malay */ + {"mfe", {HB_TAG('M','F','E',' ')}}, /* Morisyen */ + {"mg", {HB_TAG('M','L','G',' ')}}, /* Malagasy [macrolanguage] */ + {"mh", {HB_TAG('M','A','H',' ')}}, /* Marshallese */ + {"mhr", {HB_TAG('L','M','A',' ')}}, /* Eastern Mari -> Low Mari */ + {"mhv", {HB_TAG('A','R','K',' ')}}, /* Arakanese (retired code) -> Rakhine */ + {"mi", {HB_TAG('M','R','I',' ')}}, /* Maori */ + {"min", {HB_TAG('M','I','N',' ')}}, /* Minangkabau */ + {"mk", {HB_TAG('M','K','D',' ')}}, /* Macedonian */ + {"mku", {HB_TAG('M','N','K',' ')}}, /* Konyanka Maninka -> Maninka */ + {"mkw", {HB_TAG('M','K','W',' ')}}, /* Kituba (Congo) */ + {"ml", {HB_TAG('M','A','L',' '), /* Malayalam -> Malayalam Traditional */ + HB_TAG('M','L','R',' ')}}, /* Malayalam -> Malayalam Reformed */ + {"mlq", {HB_TAG('M','L','N',' '), /* Western Maninkakan -> Malinke */ + HB_TAG('M','N','K',' ')}}, /* Western Maninkakan -> Maninka */ + {"mmr", {HB_TAG('H','M','N',' ')}}, /* Western Xiangxi Miao -> Hmong */ + {"mn", {HB_TAG('M','N','G',' ')}}, /* Mongolian [macrolanguage] */ + {"mnc", {HB_TAG('M','C','H',' ')}}, /* Manchu */ + {"mni", {HB_TAG('M','N','I',' ')}}, /* Manipuri */ + {"mnk", {HB_TAG('M','N','D',' '), /* Mandinka */ + HB_TAG('M','N','K',' ')}}, /* Mandinka -> Maninka */ + {"mnp", {HB_TAG('Z','H','S',' ')}}, /* Min Bei Chinese -> Chinese Simplified */ + {"mns", {HB_TAG('M','A','N',' ')}}, /* Mansi */ + {"mnw", {HB_TAG('M','O','N',' ')}}, /* Mon */ + {"mo", {HB_TAG('M','O','L',' ')}}, /* Moldavian (retired code) */ + {"moh", {HB_TAG('M','O','H',' ')}}, /* Mohawk */ + {"mos", {HB_TAG('M','O','S',' ')}}, /* Mossi */ + {"mpe", {HB_TAG('M','A','J',' ')}}, /* Majang */ + {"mqg", {HB_TAG('M','L','Y',' ')}}, /* Kota Bangun Kutai Malay -> Malay */ + {"mr", {HB_TAG('M','A','R',' ')}}, /* Marathi */ + {"mrh", {HB_TAG('Q','I','N',' ')}}, /* Mara Chin -> Chin */ + {"mrj", {HB_TAG('H','M','A',' ')}}, /* Western Mari -> High Mari */ + {"ms", {HB_TAG('M','L','Y',' ')}}, /* Malay [macrolanguage] */ + {"msc", {HB_TAG('M','N','K',' ')}}, /* Sankaran Maninka -> Maninka */ + {"msh", {HB_TAG('M','L','G',' ')}}, /* Masikoro Malagasy -> Malagasy */ + {"msi", {HB_TAG('M','L','Y',' ')}}, /* Sabah Malay -> Malay */ + {"mt", {HB_TAG('M','T','S',' ')}}, /* Maltese */ + {"mtr", {HB_TAG('M','A','W',' ')}}, /* Mewari -> Marwari */ + {"mui", {HB_TAG('M','L','Y',' ')}}, /* Musi -> Malay */ + {"mup", {HB_TAG('R','A','J',' ')}}, /* Malvi -> Rajasthani */ + {"muq", {HB_TAG('H','M','N',' ')}}, /* Eastern Xiangxi Miao -> Hmong */ + {"mus", {HB_TAG('M','U','S',' ')}}, /* Creek -> Muscogee */ + {"mvb", {HB_TAG('A','T','H',' ')}}, /* Mattole -> Athapaskan */ + {"mve", {HB_TAG('M','A','W',' ')}}, /* Marwari (Pakistan) */ + {"mvf", {HB_TAG('M','N','G',' ')}}, /* Peripheral Mongolian -> Mongolian */ + {"mwk", {HB_TAG('M','N','K',' ')}}, /* Kita Maninkakan -> Maninka */ + {"mwl", {HB_TAG('M','W','L',' ')}}, /* Mirandese */ + {"mwr", {HB_TAG('M','A','W',' ')}}, /* Marwari [macrolanguage] */ + {"mww", {HB_TAG('M','W','W',' ')}}, /* Hmong Daw */ + {"my", {HB_TAG('B','R','M',' ')}}, /* Burmese */ + {"mym", {HB_TAG('M','E','N',' ')}}, /* Me'en */ + {"myn", {HB_TAG('M','Y','N',' ')}}, /* Mayan [family] */ + {"myq", {HB_TAG('M','N','K',' ')}}, /* Forest Maninka (retired code) -> Maninka */ + {"myv", {HB_TAG('E','R','Z',' ')}}, /* Erzya */ + {"mzn", {HB_TAG('M','Z','N',' ')}}, /* Mazanderani */ + {"na", {HB_TAG('N','A','U',' ')}}, /* Nauru -> Nauruan */ + {"nag", {HB_TAG('N','A','G',' ')}}, /* Naga Pidgin -> Naga-Assamese */ + {"nah", {HB_TAG('N','A','H',' ')}}, /* Nahuatl [family] */ + {"nan", {HB_TAG('Z','H','S',' ')}}, /* Min Nan Chinese -> Chinese Simplified */ + {"nap", {HB_TAG('N','A','P',' ')}}, /* Neapolitan */ + {"nb", {HB_TAG('N','O','R',' ')}}, /* Norwegian Bokmål -> Norwegian */ + {"nd", {HB_TAG('N','D','B',' ')}}, /* North Ndebele -> Ndebele */ + {"ndc", {HB_TAG('N','D','C',' ')}}, /* Ndau */ + {"nds", {HB_TAG('N','D','S',' ')}}, /* Low Saxon */ + {"ne", {HB_TAG('N','E','P',' ')}}, /* Nepali [macrolanguage] */ + {"new", {HB_TAG('N','E','W',' ')}}, /* Newari */ + {"ng", {HB_TAG('N','D','G',' ')}}, /* Ndonga */ + {"nga", {HB_TAG('N','G','A',' ')}}, /* Ngbaka */ + {"ngl", {HB_TAG('L','M','W',' ')}}, /* Lomwe */ + {"ngo", {HB_TAG('S','X','T',' ')}}, /* Ngoni -> Sutu */ + {"nhd", {HB_TAG('G','U','A',' ')}}, /* Chiripá -> Guarani */ + {"niq", {HB_TAG('K','A','L',' ')}}, /* Nandi -> Kalenjin */ + {"niu", {HB_TAG('N','I','U',' ')}}, /* Niuean */ + {"niv", {HB_TAG('G','I','L',' ')}}, /* Gilyak */ + {"njz", {HB_TAG('N','I','S',' ')}}, /* Nyishi -> Nisi */ + {"nl", {HB_TAG('N','L','D',' ')}}, /* Dutch */ + {"nle", {HB_TAG('L','U','H',' ')}}, /* East Nyala -> Luyia */ + {"nn", {HB_TAG('N','Y','N',' ')}}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {"no", {HB_TAG('N','O','R',' ')}}, /* Norwegian [macrolanguage] */ + {"nod", {HB_TAG('N','T','A',' ')}}, /* Northern Thai -> Northern Tai */ + {"noe", {HB_TAG('N','O','E',' ')}}, /* Nimadi */ + {"nog", {HB_TAG('N','O','G',' ')}}, /* Nogai */ + {"nov", {HB_TAG('N','O','V',' ')}}, /* Novial */ + {"npi", {HB_TAG('N','E','P',' ')}}, /* Nepali */ + {"nqo", {HB_TAG('N','K','O',' ')}}, /* N'Ko */ + {"nr", {HB_TAG('N','D','B',' ')}}, /* South Ndebele -> Ndebele */ + {"nsk", {HB_TAG('N','A','S',' ')}}, /* Naskapi */ + {"nso", {HB_TAG('N','S','O',' ')}}, /* Pedi -> Sotho, Northern */ + {"nv", {HB_TAG('N','A','V',' '), /* Navajo */ + HB_TAG('A','T','H',' ')}}, /* Navajo -> Athapaskan */ + {"ny", {HB_TAG('C','H','I',' ')}}, /* Chichewa (Chewa, Nyanja) */ + {"nyd", {HB_TAG('L','U','H',' ')}}, /* Nyore -> Luyia */ + {"nym", {HB_TAG('N','Y','M',' ')}}, /* Nyamwezi */ + {"nyn", {HB_TAG('N','K','L',' ')}}, /* Nyankole */ + {"nza", {HB_TAG('N','Z','A',' ')}}, /* Tigon Mbembe -> Mbembe Tigon */ + {"oc", {HB_TAG('O','C','I',' ')}}, /* Occitan (post 1500) */ + {"oj", {HB_TAG('O','J','B',' ')}}, /* Ojibwa [macrolanguage] -> Ojibway */ + {"ojb", {HB_TAG('O','J','B',' ')}}, /* Northwestern Ojibwa -> Ojibway */ + {"ojc", {HB_TAG('O','J','B',' ')}}, /* Central Ojibwa -> Ojibway */ + {"ojg", {HB_TAG('O','J','B',' ')}}, /* Eastern Ojibwa -> Ojibway */ + {"ojs", {HB_TAG('O','C','R',' ')}}, /* Severn Ojibwa -> Oji-Cree */ + {"ojw", {HB_TAG('O','J','B',' ')}}, /* Western Ojibwa -> Ojibway */ + {"oki", {HB_TAG('K','A','L',' ')}}, /* Okiek -> Kalenjin */ + {"okm", {HB_TAG('K','O','H',' ')}}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {"om", {HB_TAG('O','R','O',' ')}}, /* Oromo [macrolanguage] */ + {"or", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) [macrolanguage] */ + {"orc", {HB_TAG('O','R','O',' ')}}, /* Orma -> Oromo */ + {"orn", {HB_TAG('M','L','Y',' ')}}, /* Orang Kanaq -> Malay */ + {"ors", {HB_TAG('M','L','Y',' ')}}, /* Orang Seletar -> Malay */ + {"ory", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) */ + {"os", {HB_TAG('O','S','S',' ')}}, /* Ossetian */ + {"otw", {HB_TAG('O','J','B',' ')}}, /* Ottawa -> Ojibway */ + {"pa", {HB_TAG('P','A','N',' ')}}, /* Punjabi */ + {"pag", {HB_TAG('P','A','G',' ')}}, /* Pangasinan */ + {"pam", {HB_TAG('P','A','M',' ')}}, /* Pampanga -> Pampangan */ + {"pap", {HB_TAG('P','A','P','0')}}, /* Papiamento -> Papiamentu */ + {"pau", {HB_TAG('P','A','U',' ')}}, /* Palauan */ + {"pbt", {HB_TAG('P','A','S',' ')}}, /* Southern Pashto -> Pashto */ + {"pbu", {HB_TAG('P','A','S',' ')}}, /* Northern Pashto -> Pashto */ + {"pcc", {HB_TAG('P','C','C',' ')}}, /* Bouyei */ + {"pcd", {HB_TAG('P','C','D',' ')}}, /* Picard */ + {"pce", {HB_TAG('P','L','G',' ')}}, /* Ruching Palaung -> Palaung */ + {"pck", {HB_TAG('Q','I','N',' ')}}, /* Paite Chin -> Chin */ + {"pdc", {HB_TAG('P','D','C',' ')}}, /* Pennsylvania German */ + {"pel", {HB_TAG('M','L','Y',' ')}}, /* Pekal -> Malay */ + {"pes", {HB_TAG('F','A','R',' ')}}, /* Iranian Persian -> Persian */ + {"pga", {HB_TAG('A','R','A',' ')}}, /* Sudanese Creole Arabic -> Arabic */ + {"phk", {HB_TAG('P','H','K',' ')}}, /* Phake */ + {"pi", {HB_TAG('P','A','L',' ')}}, /* Pali */ + {"pih", {HB_TAG('P','I','H',' ')}}, /* Pitcairn-Norfolk -> Norfolk */ + {"pko", {HB_TAG('K','A','L',' ')}}, /* Pökoot -> Kalenjin */ + {"pl", {HB_TAG('P','L','K',' ')}}, /* Polish */ + {"pll", {HB_TAG('P','L','G',' ')}}, /* Shwe Palaung -> Palaung */ + {"plp", {HB_TAG('P','A','P',' ')}}, /* Palpa */ + {"plt", {HB_TAG('M','L','G',' ')}}, /* Plateau Malagasy -> Malagasy */ + {"pms", {HB_TAG('P','M','S',' ')}}, /* Piemontese */ + {"pnb", {HB_TAG('P','N','B',' ')}}, /* Western Panjabi */ + {"poh", {HB_TAG('P','O','H',' ')}}, /* Poqomchi' -> Pocomchi */ + {"pon", {HB_TAG('P','O','N',' ')}}, /* Pohnpeian */ + {"ppa", {HB_TAG('B','A','G',' ')}}, /* Pao (retired code) -> Baghelkhandi */ + {"pro", {HB_TAG('P','R','O',' ')}}, /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {"prs", {HB_TAG('D','R','I',' ')}}, /* Dari */ + {"ps", {HB_TAG('P','A','S',' ')}}, /* Pashto [macrolanguage] */ + {"pse", {HB_TAG('M','L','Y',' ')}}, /* Central Malay -> Malay */ + {"pst", {HB_TAG('P','A','S',' ')}}, /* Central Pashto -> Pashto */ + {"pt", {HB_TAG('P','T','G',' ')}}, /* Portuguese */ + {"pwo", {HB_TAG('P','W','O',' ')}}, /* Pwo Western Karen -> Western Pwo Karen */ + {"qu", {HB_TAG('Q','U','Z',' ')}}, /* Quechua [macrolanguage] */ + {"qub", {HB_TAG('Q','W','H',' ')}}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {"quc", {HB_TAG('Q','U','C',' ')}}, /* K’iche’ */ + {"qud", {HB_TAG('Q','V','I',' ')}}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {"quf", {HB_TAG('Q','U','Z',' ')}}, /* Lambayeque Quechua -> Quechua */ + {"qug", {HB_TAG('Q','V','I',' ')}}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {"quh", {HB_TAG('Q','U','H',' ')}}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {"quk", {HB_TAG('Q','U','Z',' ')}}, /* Chachapoyas Quechua -> Quechua */ + {"qul", {HB_TAG('Q','U','Z',' ')}}, /* North Bolivian Quechua -> Quechua */ + {"qup", {HB_TAG('Q','V','I',' ')}}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {"qur", {HB_TAG('Q','W','H',' ')}}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {"qus", {HB_TAG('Q','U','H',' ')}}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {"quw", {HB_TAG('Q','V','I',' ')}}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {"qux", {HB_TAG('Q','W','H',' ')}}, /* Yauyos Quechua -> Quechua (Peru) */ + {"quy", {HB_TAG('Q','U','Z',' ')}}, /* Ayacucho Quechua -> Quechua */ + {"quz", {HB_TAG('Q','U','Z',' ')}}, /* Cusco Quechua -> Quechua */ + {"qva", {HB_TAG('Q','W','H',' ')}}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {"qvc", {HB_TAG('Q','U','Z',' ')}}, /* Cajamarca Quechua -> Quechua */ + {"qve", {HB_TAG('Q','U','Z',' ')}}, /* Eastern Apurímac Quechua -> Quechua */ + {"qvh", {HB_TAG('Q','W','H',' ')}}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {"qvi", {HB_TAG('Q','V','I',' ')}}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {"qvj", {HB_TAG('Q','V','I',' ')}}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {"qvl", {HB_TAG('Q','W','H',' ')}}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {"qvm", {HB_TAG('Q','W','H',' ')}}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {"qvn", {HB_TAG('Q','W','H',' ')}}, /* North Junín Quechua -> Quechua (Peru) */ + {"qvo", {HB_TAG('Q','V','I',' ')}}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {"qvp", {HB_TAG('Q','W','H',' ')}}, /* Pacaraos Quechua -> Quechua (Peru) */ + {"qvs", {HB_TAG('Q','U','Z',' ')}}, /* San Martín Quechua -> Quechua */ + {"qvw", {HB_TAG('Q','W','H',' ')}}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {"qvz", {HB_TAG('Q','V','I',' ')}}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {"qwa", {HB_TAG('Q','W','H',' ')}}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {"qwc", {HB_TAG('Q','U','Z',' ')}}, /* Classical Quechua -> Quechua */ + {"qwh", {HB_TAG('Q','W','H',' ')}}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {"qws", {HB_TAG('Q','W','H',' ')}}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {"qxa", {HB_TAG('Q','W','H',' ')}}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {"qxc", {HB_TAG('Q','W','H',' ')}}, /* Chincha Quechua -> Quechua (Peru) */ + {"qxh", {HB_TAG('Q','W','H',' ')}}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {"qxl", {HB_TAG('Q','V','I',' ')}}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {"qxn", {HB_TAG('Q','W','H',' ')}}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxo", {HB_TAG('Q','W','H',' ')}}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxp", {HB_TAG('Q','U','Z',' ')}}, /* Puno Quechua -> Quechua */ + {"qxr", {HB_TAG('Q','V','I',' ')}}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {"qxt", {HB_TAG('Q','W','H',' ')}}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {"qxu", {HB_TAG('Q','U','Z',' ')}}, /* Arequipa-La Unión Quechua -> Quechua */ + {"qxw", {HB_TAG('Q','W','H',' ')}}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {"rag", {HB_TAG('L','U','H',' ')}}, /* Logooli -> Luyia */ + {"raj", {HB_TAG('R','A','J',' ')}}, /* Rajasthani [macrolanguage] */ + {"rar", {HB_TAG('R','A','R',' ')}}, /* Rarotongan */ + {"rbb", {HB_TAG('P','L','G',' ')}}, /* Rumai Palaung -> Palaung */ + {"rbl", {HB_TAG('B','I','K',' ')}}, /* Miraya Bikol -> Bikol */ + {"rej", {HB_TAG('R','E','J',' ')}}, /* Rejang */ + {"ria", {HB_TAG('R','I','A',' ')}}, /* Riang (India) */ + {"rif", {HB_TAG('R','I','F',' ')}}, /* Tarifit */ + {"rit", {HB_TAG('R','I','T',' ')}}, /* Ritarungo */ + {"rki", {HB_TAG('A','R','K',' ')}}, /* Rakhine */ + {"rkw", {HB_TAG('R','K','W',' ')}}, /* Arakwal */ + {"rm", {HB_TAG('R','M','S',' ')}}, /* Romansh */ + {"rmc", {HB_TAG('R','O','Y',' ')}}, /* Carpathian Romani -> Romany */ + {"rmf", {HB_TAG('R','O','Y',' ')}}, /* Kalo Finnish Romani -> Romany */ + {"rml", {HB_TAG('R','O','Y',' ')}}, /* Baltic Romani -> Romany */ + {"rmn", {HB_TAG('R','O','Y',' ')}}, /* Balkan Romani -> Romany */ + {"rmo", {HB_TAG('R','O','Y',' ')}}, /* Sinte Romani -> Romany */ + {"rmw", {HB_TAG('R','O','Y',' ')}}, /* Welsh Romani -> Romany */ + {"rmy", {HB_TAG('R','M','Y',' ')}}, /* Vlax Romani */ + {"rmz", {HB_TAG('A','R','K',' ')}}, /* Marma -> Rakhine */ + {"rn", {HB_TAG('R','U','N',' ')}}, /* Rundi */ + {"rnl", {HB_TAG('H','A','L',' ')}}, /* Ranglong -> Halam (Falam Chin) */ + {"ro", {HB_TAG('R','O','M',' ')}}, /* Romanian */ + {"rom", {HB_TAG('R','O','Y',' ')}}, /* Romany [macrolanguage] */ + {"rtm", {HB_TAG('R','T','M',' ')}}, /* Rotuman */ + {"ru", {HB_TAG('R','U','S',' ')}}, /* Russian */ + {"rue", {HB_TAG('R','S','Y',' ')}}, /* Rusyn */ + {"rup", {HB_TAG('R','U','P',' ')}}, /* Aromanian */ + {"rw", {HB_TAG('R','U','A',' ')}}, /* Kinyarwanda */ + {"rwr", {HB_TAG('M','A','W',' ')}}, /* Marwari (India) */ + {"sa", {HB_TAG('S','A','N',' ')}}, /* Sanskrit */ + {"sah", {HB_TAG('Y','A','K',' ')}}, /* Yakut -> Sakha */ + {"sam", {HB_TAG('P','A','A',' ')}}, /* Samaritan Aramaic -> Palestinian Aramaic */ + {"sas", {HB_TAG('S','A','S',' ')}}, /* Sasak */ + {"sat", {HB_TAG('S','A','T',' ')}}, /* Santali */ + {"sc", {HB_TAG('S','R','D',' ')}}, /* Sardinian [macrolanguage] */ + {"sck", {HB_TAG('S','A','D',' ')}}, /* Sadri */ + {"scn", {HB_TAG('S','C','N',' ')}}, /* Sicilian */ + {"sco", {HB_TAG('S','C','O',' ')}}, /* Scots */ + {"scs", {HB_TAG('S','C','S',' '), /* North Slavey */ + HB_TAG('S','L','A',' '), /* North Slavey -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* North Slavey -> Athapaskan */ + {"sd", {HB_TAG('S','N','D',' ')}}, /* Sindhi */ + {"sdc", {HB_TAG('S','R','D',' ')}}, /* Sassarese Sardinian -> Sardinian */ + {"sdh", {HB_TAG('K','U','R',' ')}}, /* Southern Kurdish -> Kurdish */ + {"sdn", {HB_TAG('S','R','D',' ')}}, /* Gallurese Sardinian -> Sardinian */ + {"se", {HB_TAG('N','S','M',' ')}}, /* Northern Sami */ + {"seh", {HB_TAG('S','N','A',' ')}}, /* Sena */ + {"sek", {HB_TAG('A','T','H',' ')}}, /* Sekani -> Athapaskan */ + {"sel", {HB_TAG('S','E','L',' ')}}, /* Selkup */ + {"sez", {HB_TAG('Q','I','N',' ')}}, /* Senthang Chin -> Chin */ + {"sfm", {HB_TAG('H','M','N',' ')}}, /* Small Flowery Miao -> Hmong */ + {"sg", {HB_TAG('S','G','O',' ')}}, /* Sango */ + {"sga", {HB_TAG('S','G','A',' ')}}, /* Old Irish (to 900) */ + {"sgc", {HB_TAG('K','A','L',' ')}}, /* Kipsigis -> Kalenjin */ + {"sgs", {HB_TAG('S','G','S',' ')}}, /* Samogitian */ + {"sgw", {HB_TAG('C','H','G',' '), /* Sebat Bet Gurage -> Chaha Gurage */ + HB_TAG('S','G','W',' ')}}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */ + {"shi", {HB_TAG('S','H','I',' ')}}, /* Tachelhit */ + {"shn", {HB_TAG('S','H','N',' ')}}, /* Shan */ + {"shu", {HB_TAG('A','R','A',' ')}}, /* Chadian Arabic -> Arabic */ + {"si", {HB_TAG('S','N','H',' ')}}, /* Sinhala (Sinhalese) */ + {"sid", {HB_TAG('S','I','D',' ')}}, /* Sidamo */ + {"sjd", {HB_TAG('K','S','M',' ')}}, /* Kildin Sami */ + {"sjo", {HB_TAG('S','I','B',' ')}}, /* Xibe -> Sibe */ + {"sk", {HB_TAG('S','K','Y',' ')}}, /* Slovak */ + {"skg", {HB_TAG('M','L','G',' ')}}, /* Sakalava Malagasy -> Malagasy */ + {"skr", {HB_TAG('S','R','K',' ')}}, /* Saraiki */ + {"sl", {HB_TAG('S','L','V',' ')}}, /* Slovenian */ + {"sm", {HB_TAG('S','M','O',' ')}}, /* Samoan */ + {"sma", {HB_TAG('S','S','M',' ')}}, /* Southern Sami */ + {"smj", {HB_TAG('L','S','M',' ')}}, /* Lule Sami */ + {"smn", {HB_TAG('I','S','M',' ')}}, /* Inari Sami */ + {"sms", {HB_TAG('S','K','S',' ')}}, /* Skolt Sami */ + {"sn", {HB_TAG('S','N','A','0')}}, /* Shona */ + {"snk", {HB_TAG('S','N','K',' ')}}, /* Soninke */ + {"so", {HB_TAG('S','M','L',' ')}}, /* Somali */ + {"sop", {HB_TAG('S','O','P',' ')}}, /* Songe */ + {"spv", {HB_TAG('O','R','I',' ')}}, /* Sambalpuri -> Odia (formerly Oriya) */ + {"spy", {HB_TAG('K','A','L',' ')}}, /* Sabaot -> Kalenjin */ + {"sq", {HB_TAG('S','Q','I',' ')}}, /* Albanian [macrolanguage] */ + {"sr", {HB_TAG('S','R','B',' ')}}, /* Serbian */ + {"src", {HB_TAG('S','R','D',' ')}}, /* Logudorese Sardinian -> Sardinian */ + {"sro", {HB_TAG('S','R','D',' ')}}, /* Campidanese Sardinian -> Sardinian */ + {"srr", {HB_TAG('S','R','R',' ')}}, /* Serer */ + {"srs", {HB_TAG('A','T','H',' ')}}, /* Sarsi -> Athapaskan */ + {"ss", {HB_TAG('S','W','Z',' ')}}, /* Swati */ + {"ssh", {HB_TAG('A','R','A',' ')}}, /* Shihhi Arabic -> Arabic */ + {"st", {HB_TAG('S','O','T',' ')}}, /* Southern Sotho -> Sotho, Southern */ + {"stq", {HB_TAG('S','T','Q',' ')}}, /* Saterfriesisch -> Saterland Frisian */ + {"stv", {HB_TAG('S','I','G',' ')}}, /* Silt'e -> Silte Gurage */ + {"su", {HB_TAG('S','U','N',' ')}}, /* Sundanese */ + {"suk", {HB_TAG('S','U','K',' ')}}, /* Sukuma */ + {"suq", {HB_TAG('S','U','R',' ')}}, /* Suri */ + {"sv", {HB_TAG('S','V','E',' ')}}, /* Swedish */ + {"sva", {HB_TAG('S','V','A',' ')}}, /* Svan */ + {"sw", {HB_TAG('S','W','K',' ')}}, /* Swahili [macrolanguage] */ + {"swb", {HB_TAG('C','M','R',' ')}}, /* Maore Comorian -> Comorian */ + {"swc", {HB_TAG('S','W','K',' ')}}, /* Congo Swahili -> Swahili */ + {"swh", {HB_TAG('S','W','K',' ')}}, /* Swahili */ + {"swv", {HB_TAG('M','A','W',' ')}}, /* Shekhawati -> Marwari */ + {"sxu", {HB_TAG('S','X','U',' ')}}, /* Upper Saxon */ + {"syc", {HB_TAG('S','Y','R',' ')}}, /* Classical Syriac -> Syriac */ + {"syl", {HB_TAG('S','Y','L',' ')}}, /* Sylheti */ + {"syr", {HB_TAG('S','Y','R',' ')}}, /* Syriac [macrolanguage] */ + {"szl", {HB_TAG('S','Z','L',' ')}}, /* Silesian */ + {"ta", {HB_TAG('T','A','M',' ')}}, /* Tamil */ + {"taa", {HB_TAG('A','T','H',' ')}}, /* Lower Tanana -> Athapaskan */ + {"tab", {HB_TAG('T','A','B',' ')}}, /* Tabassaran -> Tabasaran */ + {"taq", {HB_TAG('T','M','H',' ')}}, /* Tamasheq -> Tamashek */ + {"tau", {HB_TAG('A','T','H',' ')}}, /* Upper Tanana -> Athapaskan */ + {"tcb", {HB_TAG('A','T','H',' ')}}, /* Tanacross -> Athapaskan */ + {"tce", {HB_TAG('A','T','H',' ')}}, /* Southern Tutchone -> Athapaskan */ + {"tcp", {HB_TAG('Q','I','N',' ')}}, /* Tawr Chin -> Chin */ + {"tcy", {HB_TAG('T','U','L',' ')}}, /* Tulu -> Tumbuka */ + {"tcz", {HB_TAG('Q','I','N',' ')}}, /* Thado Chin -> Chin */ + {"tdd", {HB_TAG('T','D','D',' ')}}, /* Tai Nüa -> Dehong Dai */ + {"tdx", {HB_TAG('M','L','G',' ')}}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {"te", {HB_TAG('T','E','L',' ')}}, /* Telugu */ + {"tec", {HB_TAG('K','A','L',' ')}}, /* Terik -> Kalenjin */ + {"tem", {HB_TAG('T','M','N',' ')}}, /* Timne -> Temne */ + {"tet", {HB_TAG('T','E','T',' ')}}, /* Tetum */ + {"tfn", {HB_TAG('A','T','H',' ')}}, /* Tanaina -> Athapaskan */ + {"tg", {HB_TAG('T','A','J',' ')}}, /* Tajik -> Tajiki */ + {"tgj", {HB_TAG('N','I','S',' ')}}, /* Tagin -> Nisi */ + {"tgx", {HB_TAG('A','T','H',' ')}}, /* Tagish -> Athapaskan */ + {"th", {HB_TAG('T','H','A',' ')}}, /* Thai */ + {"tht", {HB_TAG('A','T','H',' ')}}, /* Tahltan -> Athapaskan */ + {"thv", {HB_TAG('T','M','H',' ')}}, /* Tahaggart Tamahaq -> Tamashek */ + {"thz", {HB_TAG('T','M','H',' ')}}, /* Tayart Tamajeq -> Tamashek */ + {"ti", {HB_TAG('T','G','Y',' ')}}, /* Tigrinya */ + {"tig", {HB_TAG('T','G','R',' ')}}, /* Tigre */ + {"tiv", {HB_TAG('T','I','V',' ')}}, /* Tiv */ + {"tk", {HB_TAG('T','K','M',' ')}}, /* Turkmen */ + {"tkg", {HB_TAG('M','L','G',' ')}}, /* Tesaka Malagasy -> Malagasy */ + {"tl", {HB_TAG('T','G','L',' ')}}, /* Tagalog */ + {"tmh", {HB_TAG('T','M','H',' ')}}, /* Tamashek [macrolanguage] */ + {"tmw", {HB_TAG('M','L','Y',' ')}}, /* Temuan -> Malay */ + {"tn", {HB_TAG('T','N','A',' ')}}, /* Tswana */ + {"tnf", {HB_TAG('D','R','I',' ')}}, /* Tangshewi (retired code) -> Dari */ + {"to", {HB_TAG('T','G','N',' ')}}, /* Tonga (Tonga Islands) -> Tongan */ + {"tod", {HB_TAG('T','O','D','0')}}, /* Toma */ + {"toi", {HB_TAG('T','N','G',' ')}}, /* Tonga (Zambia) */ + {"tol", {HB_TAG('A','T','H',' ')}}, /* Tolowa -> Athapaskan */ + {"tpi", {HB_TAG('T','P','I',' ')}}, /* Tok Pisin */ + {"tr", {HB_TAG('T','R','K',' ')}}, /* Turkish */ + {"tru", {HB_TAG('T','U','A',' '), /* Turoyo -> Turoyo Aramaic */ + HB_TAG('S','Y','R',' ')}}, /* Turoyo -> Syriac */ + {"ts", {HB_TAG('T','S','G',' ')}}, /* Tsonga */ + {"tsj", {HB_TAG('T','S','J',' ')}}, /* Tshangla */ + {"tt", {HB_TAG('T','A','T',' ')}}, /* Tatar */ + {"ttm", {HB_TAG('A','T','H',' ')}}, /* Northern Tutchone -> Athapaskan */ + {"ttq", {HB_TAG('T','M','H',' ')}}, /* Tawallammat Tamajaq -> Tamashek */ + {"tum", {HB_TAG('T','U','M',' ')}}, /* Tumbuka -> Tulu */ + {"tuu", {HB_TAG('A','T','H',' ')}}, /* Tututni -> Athapaskan */ + {"tuy", {HB_TAG('K','A','L',' ')}}, /* Tugen -> Kalenjin */ + {"tvl", {HB_TAG('T','V','L',' ')}}, /* Tuvalu */ + {"tw", {HB_TAG('T','W','I',' '), /* Twi */ + HB_TAG('A','K','A',' ')}}, /* Twi -> Akan */ + {"txc", {HB_TAG('A','T','H',' ')}}, /* Tsetsaut -> Athapaskan */ + {"txy", {HB_TAG('M','L','G',' ')}}, /* Tanosy Malagasy -> Malagasy */ + {"ty", {HB_TAG('T','H','T',' ')}}, /* Tahitian */ + {"tyv", {HB_TAG('T','U','V',' ')}}, /* Tuvinian -> Tuvin */ + {"tyz", {HB_TAG('T','Y','Z',' ')}}, /* Tày */ + {"tzm", {HB_TAG('T','Z','M',' ')}}, /* Central Atlas Tamazight -> Tamazight */ + {"tzo", {HB_TAG('T','Z','O',' ')}}, /* Tzotzil */ + {"ubl", {HB_TAG('B','I','K',' ')}}, /* Buhi'non Bikol -> Bikol */ + {"udm", {HB_TAG('U','D','M',' ')}}, /* Udmurt */ + {"ug", {HB_TAG('U','Y','G',' ')}}, /* Uyghur */ + {"uk", {HB_TAG('U','K','R',' ')}}, /* Ukrainian */ + {"umb", {HB_TAG('U','M','B',' ')}}, /* Umbundu */ + {"unr", {HB_TAG('M','U','N',' ')}}, /* Mundari */ + {"ur", {HB_TAG('U','R','D',' ')}}, /* Urdu */ + {"urk", {HB_TAG('M','L','Y',' ')}}, /* Urak Lawoi' -> Malay */ + {"uz", {HB_TAG('U','Z','B',' ')}}, /* Uzbek [macrolanguage] */ + {"uzn", {HB_TAG('U','Z','B',' ')}}, /* Northern Uzbek -> Uzbek */ + {"uzs", {HB_TAG('U','Z','B',' ')}}, /* Southern Uzbek -> Uzbek */ + {"ve", {HB_TAG('V','E','N',' ')}}, /* Venda */ + {"vec", {HB_TAG('V','E','C',' ')}}, /* Venetian */ + {"vi", {HB_TAG('V','I','T',' ')}}, /* Vietnamese */ + {"vkk", {HB_TAG('M','L','Y',' ')}}, /* Kaur -> Malay */ + {"vkt", {HB_TAG('M','L','Y',' ')}}, /* Tenggarong Kutai Malay -> Malay */ + {"vls", {HB_TAG('F','L','E',' ')}}, /* Vlaams -> Dutch (Flemish) */ + {"vmw", {HB_TAG('M','A','K',' ')}}, /* Makhuwa */ + {"vo", {HB_TAG('V','O','L',' ')}}, /* Volapük */ + {"vro", {HB_TAG('V','R','O',' ')}}, /* Võro */ + {"wa", {HB_TAG('W','L','N',' ')}}, /* Walloon */ + {"war", {HB_TAG('W','A','R',' ')}}, /* Waray (Philippines) -> Waray-Waray */ + {"wbm", {HB_TAG('W','A',' ',' ')}}, /* Wa */ + {"wbr", {HB_TAG('W','A','G',' ')}}, /* Wagdi */ + {"wlc", {HB_TAG('C','M','R',' ')}}, /* Mwali Comorian -> Comorian */ + {"wle", {HB_TAG('S','I','G',' ')}}, /* Wolane -> Silte Gurage */ + {"wlk", {HB_TAG('A','T','H',' ')}}, /* Wailaki -> Athapaskan */ + {"wni", {HB_TAG('C','M','R',' ')}}, /* Ndzwani Comorian -> Comorian */ + {"wo", {HB_TAG('W','L','F',' ')}}, /* Wolof */ + {"wry", {HB_TAG('M','A','W',' ')}}, /* Merwari -> Marwari */ + {"wsg", {HB_TAG('G','O','N',' ')}}, /* Adilabad Gondi -> Gondi */ + {"wtm", {HB_TAG('W','T','M',' ')}}, /* Mewati */ + {"wuu", {HB_TAG('Z','H','S',' ')}}, /* Wu Chinese -> Chinese Simplified */ + {"xal", {HB_TAG('K','L','M',' '), /* Kalmyk */ + HB_TAG('T','O','D',' ')}}, /* Kalmyk -> Todo */ + {"xan", {HB_TAG('S','E','K',' ')}}, /* Xamtanga -> Sekota */ + {"xh", {HB_TAG('X','H','S',' ')}}, /* Xhosa */ + {"xjb", {HB_TAG('X','J','B',' ')}}, /* Minjungbal -> Minjangbal */ + {"xkf", {HB_TAG('X','K','F',' ')}}, /* Khengkha */ + {"xmm", {HB_TAG('M','L','Y',' ')}}, /* Manado Malay -> Malay */ + {"xmv", {HB_TAG('M','L','G',' ')}}, /* Antankarana Malagasy -> Malagasy */ + {"xmw", {HB_TAG('M','L','G',' ')}}, /* Tsimihety Malagasy -> Malagasy */ + {"xnr", {HB_TAG('D','G','R',' ')}}, /* Kangri -> Dogri */ + {"xog", {HB_TAG('X','O','G',' ')}}, /* Soga */ + {"xpe", {HB_TAG('X','P','E',' ')}}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {"xsl", {HB_TAG('S','S','L',' '), /* South Slavey */ + HB_TAG('S','L','A',' '), /* South Slavey -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* South Slavey -> Athapaskan */ + {"xst", {HB_TAG('S','I','G',' ')}}, /* Silt'e (retired code) -> Silte Gurage */ + {"xwo", {HB_TAG('T','O','D',' ')}}, /* Written Oirat -> Todo */ + {"yao", {HB_TAG('Y','A','O',' ')}}, /* Yao */ + {"yap", {HB_TAG('Y','A','P',' ')}}, /* Yapese */ + {"ybd", {HB_TAG('A','R','K',' ')}}, /* Yangbye (retired code) -> Rakhine */ + {"ydd", {HB_TAG('J','I','I',' ')}}, /* Eastern Yiddish -> Yiddish */ + {"yi", {HB_TAG('J','I','I',' ')}}, /* Yiddish [macrolanguage] */ + {"yih", {HB_TAG('J','I','I',' ')}}, /* Western Yiddish -> Yiddish */ + {"yo", {HB_TAG('Y','B','A',' ')}}, /* Yoruba */ + {"yos", {HB_TAG('Q','I','N',' ')}}, /* Yos (retired code) -> Chin */ + {"yrk", {HB_TAG('T','N','E',' '), /* Nenets -> Tundra Nenets */ + HB_TAG('F','N','E',' ')}}, /* Nenets -> Forest Nenets */ + {"yue", {HB_TAG('Z','H','H',' ')}}, /* Yue Chinese -> Chinese, Hong Kong SAR */ + {"za", {HB_TAG('Z','H','A',' ')}}, /* Zhuang [macrolanguage] */ + {"zch", {HB_TAG('Z','H','A',' ')}}, /* Central Hongshuihe Zhuang -> Zhuang */ + {"zdj", {HB_TAG('C','M','R',' ')}}, /* Ngazidja Comorian -> Comorian */ + {"zea", {HB_TAG('Z','E','A',' ')}}, /* Zeeuws -> Zealandic */ + {"zeh", {HB_TAG('Z','H','A',' ')}}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {"zgb", {HB_TAG('Z','H','A',' ')}}, /* Guibei Zhuang -> Zhuang */ + {"zgh", {HB_TAG('Z','G','H',' ')}}, /* Standard Moroccan Tamazight */ + {"zgm", {HB_TAG('Z','H','A',' ')}}, /* Minz Zhuang -> Zhuang */ + {"zgn", {HB_TAG('Z','H','A',' ')}}, /* Guibian Zhuang -> Zhuang */ + {"zh", {HB_TAG('Z','H','S',' ')}}, /* Chinese [macrolanguage] -> Chinese Simplified */ + {"zhd", {HB_TAG('Z','H','A',' ')}}, /* Dai Zhuang -> Zhuang */ + {"zhn", {HB_TAG('Z','H','A',' ')}}, /* Nong Zhuang -> Zhuang */ + {"zlj", {HB_TAG('Z','H','A',' ')}}, /* Liujiang Zhuang -> Zhuang */ + {"zlm", {HB_TAG('M','L','Y',' ')}}, /* Malay */ + {"zln", {HB_TAG('Z','H','A',' ')}}, /* Lianshan Zhuang -> Zhuang */ + {"zlq", {HB_TAG('Z','H','A',' ')}}, /* Liuqian Zhuang -> Zhuang */ + {"zmi", {HB_TAG('M','L','Y',' ')}}, /* Negeri Sembilan Malay -> Malay */ + {"zne", {HB_TAG('Z','N','D',' ')}}, /* Zande */ + {"zom", {HB_TAG('Q','I','N',' ')}}, /* Zou -> Chin */ + {"zqe", {HB_TAG('Z','H','A',' ')}}, /* Qiubei Zhuang -> Zhuang */ + {"zsm", {HB_TAG('M','L','Y',' ')}}, /* Standard Malay -> Malay */ + {"zu", {HB_TAG('Z','U','L',' ')}}, /* Zulu */ + {"zum", {HB_TAG('L','R','C',' ')}}, /* Kumzari -> Luri */ + {"zyb", {HB_TAG('Z','H','A',' ')}}, /* Yongbei Zhuang -> Zhuang */ + {"zyg", {HB_TAG('Z','H','A',' ')}}, /* Yang Zhuang -> Zhuang */ + {"zyj", {HB_TAG('Z','H','A',' ')}}, /* Youjiang Zhuang -> Zhuang */ + {"zyn", {HB_TAG('Z','H','A',' ')}}, /* Yongnan Zhuang -> Zhuang */ + {"zza", {HB_TAG('Z','Z','A',' ')}}, /* Zazaki [macrolanguage] */ + {"zzj", {HB_TAG('Z','H','A',' ')}}, /* Zuojiang Zhuang -> Zhuang */ +}; + +static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, ""); + +/** + * hb_ot_tags_from_complex_language: + * @lang_str: a BCP 47 language tag to convert. + * @limit: a pointer to the end of the substring of @lang_str to consider for + * conversion. + * @count: maximum number of language tags to retrieve (IN) and actual number of + * language tags retrieved (OUT). If no tags are retrieved, it is not modified. + * @tags: array of size at least @language_count to store the language tag + * results + * + * Converts a multi-subtag BCP 47 language tag to language tags. + * + * Return value: Whether any language systems were retrieved. + **/ +static bool +hb_ot_tags_from_complex_language (const char *lang_str, + const char *limit, + unsigned int *count /* IN/OUT */, + hb_tag_t *tags /* OUT */) +{ + if (subtag_matches (lang_str, limit, "-fonnapa")) + { + /* Undetermined; North American Phonetic Alphabet */ + tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-polyton")) + { + /* Modern Greek (1453-); Polytonic Greek */ + tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-provenc")) + { + /* Occitan (post 1500); Provençal */ + tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-fonipa")) + { + /* Undetermined; International Phonetic Alphabet */ + tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-geok")) + { + /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syre")) + { + /* Undetermined; Syriac (Estrangelo variant) */ + tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syrj")) + { + /* Undetermined; Syriac (Western variant) */ + tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syrn")) + { + /* Undetermined; Syriac (Eastern variant) */ + tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + *count = 1; + return true; + } + switch (lang_str[0]) + { + case 'a': + if (0 == strcmp (&lang_str[1], "rt-lojban")) + { + /* Lojban */ + tags[0] = HB_TAG('J','B','O',' '); /* Lojban */ + *count = 1; + return true; + } + break; + case 'c': + if (lang_matches (&lang_str[1], "do-hant-hk")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hant-mo")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant-hk")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant-mo")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant-hk")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant-mo")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant-hk")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant-mo")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant-hk")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant-mo")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant-hk")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant-mo")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hans")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hant")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hans")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hans")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hans")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hans")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hans")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Dong Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Dong Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Dong Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Jinyu Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Jinyu Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Jinyu Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Mandarin Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Mandarin Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Mandarin Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Pu-Xian Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Pu-Xian Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Pu-Xian Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Huizhou Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Huizhou Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Huizhou Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Zhong Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Zhong Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Zhong Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'g': + if (lang_matches (&lang_str[1], "an-hant-hk")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant-mo")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hans")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "a-latg")) + { + /* Irish */ + tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Gan Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Gan Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Gan Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'h': + if (lang_matches (&lang_str[1], "ak-hant-hk")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hant-mo")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant-hk")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant-mo")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hans")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hant")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hans")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Hakka Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Hakka Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Hakka Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Xiang Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Xiang Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Xiang Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'i': + if (0 == strcmp (&lang_str[1], "-navajo")) + { + /* Navajo */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('N','A','V',' '), /* Navajo */ + HB_TAG('A','T','H',' '), /* Athapaskan */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strcmp (&lang_str[1], "-hak")) + { + /* Hakka */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "-lux")) + { + /* Luxembourgish */ + tags[0] = HB_TAG('L','T','Z',' '); /* Luxembourgish */ + *count = 1; + return true; + } + break; + case 'l': + if (lang_matches (&lang_str[1], "zh-hans")) + { + /* Literary Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + break; + case 'm': + if (lang_matches (&lang_str[1], "np-hant-hk")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant-mo")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hans")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Bei Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Bei Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Bei Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'n': + if (lang_matches (&lang_str[1], "an-hant-hk")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant-mo")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hans")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Nan Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Nan Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Nan Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "o-bok")) + { + /* Norwegian Bokmal */ + tags[0] = HB_TAG('N','O','R',' '); /* Norwegian */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "o-nyn")) + { + /* Norwegian Nynorsk */ + tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + *count = 1; + return true; + } + break; + case 'r': + if (0 == strncmp (&lang_str[1], "o-", 2) + && subtag_matches (lang_str, limit, "-md")) + { + /* Romanian; Moldova */ + tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */ + *count = 1; + return true; + } + break; + case 'w': + if (lang_matches (&lang_str[1], "uu-hant-hk")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hant-mo")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hans")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hant")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Wu Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Wu Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Wu Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'y': + if (lang_matches (&lang_str[1], "ue-hans")) + { + /* Yue Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + break; + case 'z': + if (lang_matches (&lang_str[1], "h-hant-hk")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hant-mo")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "h-min-nan")) + { + /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hans")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hant")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "h-min")) + { + /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + } + return false; +} + +/** + * hb_ot_ambiguous_tag_to_language + * @tag: A language tag. + * + * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to + * many language tags) and the best tag is not the alphabetically first, or if + * the best tag consists of multiple subtags. + * + * Return value: The #hb_language_t corresponding to the BCP 47 language tag, + * or #HB_LANGUAGE_INVALID if @tag is not ambiguous. + **/ +static hb_language_t +hb_ot_ambiguous_tag_to_language (hb_tag_t tag) +{ + switch (tag) + { + case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ + return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */ + case HB_TAG('A','R','A',' '): /* Arabic */ + return hb_language_from_string ("ar", -1); /* Arabic */ + case HB_TAG('A','R','K',' '): /* Rakhine */ + return hb_language_from_string ("rki", -1); /* Rakhine */ + case HB_TAG('A','T','H',' '): /* Athapaskan */ + return hb_language_from_string ("ath", -1); /* Athapascan */ + case HB_TAG('B','I','K',' '): /* Bikol */ + return hb_language_from_string ("bik", -1); /* Bikol */ + case HB_TAG('C','P','P',' '): /* Creoles */ + return hb_language_from_string ("crp", -1); /* Creoles and pidgins */ + case HB_TAG('C','R','R',' '): /* Carrier */ + return hb_language_from_string ("crx", -1); /* Carrier */ + case HB_TAG('D','N','K',' '): /* Dinka */ + return hb_language_from_string ("din", -1); /* Dinka */ + case HB_TAG('D','R','I',' '): /* Dari */ + return hb_language_from_string ("prs", -1); /* Dari */ + case HB_TAG('D','U','J',' '): /* Dhuwal */ + return hb_language_from_string ("dwu", -1); /* Dhuwal */ + case HB_TAG('D','Z','N',' '): /* Dzongkha */ + return hb_language_from_string ("dz", -1); /* Dzongkha */ + case HB_TAG('E','T','I',' '): /* Estonian */ + return hb_language_from_string ("et", -1); /* Estonian */ + case HB_TAG('G','O','N',' '): /* Gondi */ + return hb_language_from_string ("gon", -1); /* Gondi */ + case HB_TAG('H','M','N',' '): /* Hmong */ + return hb_language_from_string ("hmn", -1); /* Hmong */ + case HB_TAG('I','J','O',' '): /* Ijo */ + return hb_language_from_string ("ijo", -1); /* Ijo */ + case HB_TAG('I','N','U',' '): /* Inuktitut */ + return hb_language_from_string ("iu", -1); /* Inuktitut */ + case HB_TAG('I','P','K',' '): /* Inupiat */ + return hb_language_from_string ("ik", -1); /* Inupiaq */ + case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ + return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */ + case HB_TAG('I','R','T',' '): /* Irish Traditional */ + return hb_language_from_string ("ga-Latg", -1); /* Irish; Latin (Gaelic variant) */ + case HB_TAG('J','I','I',' '): /* Yiddish */ + return hb_language_from_string ("yi", -1); /* Yiddish */ + case HB_TAG('K','A','L',' '): /* Kalenjin */ + return hb_language_from_string ("kln", -1); /* Kalenjin */ + case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */ + return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + case HB_TAG('K','N','R',' '): /* Kanuri */ + return hb_language_from_string ("kr", -1); /* Kanuri */ + case HB_TAG('K','O','K',' '): /* Konkani */ + return hb_language_from_string ("kok", -1); /* Konkani */ + case HB_TAG('K','U','R',' '): /* Kurdish */ + return hb_language_from_string ("ku", -1); /* Kurdish */ + case HB_TAG('L','U','H',' '): /* Luyia */ + return hb_language_from_string ("luy", -1); /* Luyia */ + case HB_TAG('L','V','I',' '): /* Latvian */ + return hb_language_from_string ("lv", -1); /* Latvian */ + case HB_TAG('M','A','W',' '): /* Marwari */ + return hb_language_from_string ("mwr", -1); /* Marwari */ + case HB_TAG('M','L','G',' '): /* Malagasy */ + return hb_language_from_string ("mg", -1); /* Malagasy */ + case HB_TAG('M','L','Y',' '): /* Malay */ + return hb_language_from_string ("ms", -1); /* Malay */ + case HB_TAG('M','N','G',' '): /* Mongolian */ + return hb_language_from_string ("mn", -1); /* Mongolian */ + case HB_TAG('M','O','L',' '): /* Moldavian */ + return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */ + case HB_TAG('N','E','P',' '): /* Nepali */ + return hb_language_from_string ("ne", -1); /* Nepali */ + case HB_TAG('N','I','S',' '): /* Nisi */ + return hb_language_from_string ("njz", -1); /* Nyishi */ + case HB_TAG('N','O','R',' '): /* Norwegian */ + return hb_language_from_string ("no", -1); /* Norwegian */ + case HB_TAG('O','J','B',' '): /* Ojibway */ + return hb_language_from_string ("oj", -1); /* Ojibwa */ + case HB_TAG('O','R','O',' '): /* Oromo */ + return hb_language_from_string ("om", -1); /* Oromo */ + case HB_TAG('P','A','S',' '): /* Pashto */ + return hb_language_from_string ("ps", -1); /* Pashto */ + case HB_TAG('P','G','R',' '): /* Polytonic Greek */ + return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */ + case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */ + return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */ + case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */ + return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */ + case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */ + return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */ + case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */ + return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */ + case HB_TAG('R','A','J',' '): /* Rajasthani */ + return hb_language_from_string ("raj", -1); /* Rajasthani */ + case HB_TAG('R','O','Y',' '): /* Romany */ + return hb_language_from_string ("rom", -1); /* Romany */ + case HB_TAG('S','Q','I',' '): /* Albanian */ + return hb_language_from_string ("sq", -1); /* Albanian */ + case HB_TAG('S','Y','R',' '): /* Syriac */ + return hb_language_from_string ("syr", -1); /* Syriac */ + case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + return hb_language_from_string ("und-Syre", -1); /* Undetermined; Syriac (Estrangelo variant) */ + case HB_TAG('S','Y','R','J'): /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + return hb_language_from_string ("und-Syrj", -1); /* Undetermined; Syriac (Western variant) */ + case HB_TAG('S','Y','R','N'): /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + return hb_language_from_string ("und-Syrn", -1); /* Undetermined; Syriac (Eastern variant) */ + case HB_TAG('T','M','H',' '): /* Tamashek */ + return hb_language_from_string ("tmh", -1); /* Tamashek */ + case HB_TAG('T','N','E',' '): /* Tundra Nenets */ + return hb_language_from_string ("yrk", -1); /* Nenets */ + case HB_TAG('Z','H','H',' '): /* Chinese, Hong Kong SAR */ + return hb_language_from_string ("zh-HK", -1); /* Chinese; Hong Kong */ + case HB_TAG('Z','H','S',' '): /* Chinese Simplified */ + return hb_language_from_string ("zh-Hans", -1); /* Chinese; Han (Simplified variant) */ + case HB_TAG('Z','H','T',' '): /* Chinese Traditional */ + return hb_language_from_string ("zh-Hant", -1); /* Chinese; Han (Traditional variant) */ + default: + return HB_LANGUAGE_INVALID; + } +} + +#endif /* HB_OT_TAG_TABLE_HH */ + +/* == End of generated table == */ diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc index 991d8e7..d04e532 100644 --- a/src/hb-ot-tag.cc +++ b/src/hb-ot-tag.cc @@ -26,7 +26,7 @@ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ -#include "hb-private.hh" +#include "hb.hh" /* hb_script_t */ @@ -36,7 +36,8 @@ hb_ot_old_tag_from_script (hb_script_t script) { /* This seems to be accurate as of end of 2012. */ - switch ((hb_tag_t) script) { + switch ((hb_tag_t) script) + { case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; /* KATAKANA and HIRAGANA both map to 'kana' */ @@ -49,8 +50,6 @@ hb_ot_old_tag_from_script (hb_script_t script) case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' '); /* Unicode-5.1 additions */ case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' '); - /* Unicode-5.2 additions */ - /* Unicode-6.0 additions */ } /* Else, just change first char to lowercase and return */ @@ -114,6 +113,18 @@ hb_ot_new_tag_to_script (hb_tag_t tag) return HB_SCRIPT_UNKNOWN; } +void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2) +{ + unsigned int count = 2; + hb_tag_t tags[2]; + hb_ot_tags_from_script_and_language (script, HB_LANGUAGE_INVALID, &count, tags, nullptr, nullptr); + *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT; + *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT; +} + /* * Complete list at: * https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags @@ -122,28 +133,37 @@ hb_ot_new_tag_to_script (hb_tag_t tag) * So we just do that, and handle the exceptional cases in a switch. */ -void -hb_ot_tags_from_script (hb_script_t script, - hb_tag_t *script_tag_1, - hb_tag_t *script_tag_2) +static void +hb_ot_all_tags_from_script (hb_script_t script, + unsigned int *count /* IN/OUT */, + hb_tag_t *tags /* OUT */) { - hb_tag_t new_tag; + unsigned int i = 0; - *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT; - *script_tag_1 = hb_ot_old_tag_from_script (script); + hb_tag_t new_tag = hb_ot_new_tag_from_script (script); + if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) + { + tags[i++] = new_tag | '3'; + if (*count > i) + tags[i++] = new_tag; + } - new_tag = hb_ot_new_tag_from_script (script); - if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { - *script_tag_2 = *script_tag_1; - *script_tag_1 = new_tag; + if (*count > i) + { + hb_tag_t old_tag = hb_ot_old_tag_from_script (script); + if (old_tag != HB_OT_TAG_DEFAULT_SCRIPT) + tags[i++] = old_tag; } + + *count = i; } hb_script_t hb_ot_tag_to_script (hb_tag_t tag) { - if (unlikely ((tag & 0x000000FFu) == '2')) - return hb_ot_new_tag_to_script (tag); + unsigned char digit = tag & 0x000000FFu; + if (unlikely (digit == '2' || digit == '3')) + return hb_ot_new_tag_to_script (tag & 0xFFFFFF32); return hb_ot_old_tag_to_script (tag); } @@ -151,732 +171,6 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -typedef struct { - char language[4]; - hb_tag_t tag; -} LangTag; - -/* - * Complete list at: - * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags - * - * Generated by intersecting the OpenType language tag list from - * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from - * 2008-08-04, matching on name, and finally adjusted manually. - * - * Updated on 2012-12-07 with more research into remaining codes. - * - * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts, - * the new proposal from Microsoft, and latest ISO 639-3 names. - * - * Some items still missing. Those are commented out at the end. - * Keep sorted for bsearch. - * - * Updated as of 2015-05-06: OT1.7 on MS website has some newer - * items that we don't have here, eg. Zazaki. This is the new - * items in OpenType 1.7 (red items), most of which we have: - * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags - */ - -static const LangTag ot_languages[] = { - {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ - {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ - {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ - {"acf", HB_TAG('F','A','N',' ')}, /* French Antillean */ - {"ach", HB_TAG('A','C','H',' ')}, /* Acoli */ - {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ - {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */ - {"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */ - {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ - {"ahg", HB_TAG('A','G','W',' ')}, /* Agaw */ - {"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */ - {"aio", HB_TAG('A','I','O',' ')}, /* Aiton */ - {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ - {"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] */ - {"aka", HB_TAG('A','K','A',' ')}, /* Akan */ - {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */ - {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ - {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */ - {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic */ - {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ - {"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */ - {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ - {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic */ - {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ - {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic */ - {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ - {"ast", HB_TAG('A','S','T',' ')}, /* Asturian/Asturleonese/Bable/Leonese */ - {"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */ - {"atj", HB_TAG('R','C','R',' ')}, /* R-Cree */ - {"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */ - {"av", HB_TAG('A','V','R',' ')}, /* Avaric */ - {"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */ - {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ - {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ - {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani */ - {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani */ - {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ - {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolangauge] */ - {"ban", HB_TAG('B','A','N',' ')}, /* Balinese */ - {"bar", HB_TAG('B','A','R',' ')}, /* Bavarian */ - {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */ - {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */ - {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ - {"bdy", HB_TAG('B','D','Y',' ')}, /* Bandjalang */ - {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */ - {"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */ - {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */ - {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ - {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ - {"bfu", HB_TAG('L','A','H',' ')}, /* Lahuli */ - {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */ - {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ - {"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */ - {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ - {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin */ - {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ - {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */ - {"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */ - {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ - {"bik", HB_TAG('B','I','K',' ')}, /* Bikol [macrolanguage] */ - {"bin", HB_TAG('E','D','O',' ')}, /* Bini */ - {"bjj", HB_TAG('B','J','J',' ')}, /* Kanauji */ - {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */ - {"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */ - {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */ - {"blk", HB_TAG('B','L','K',' ')}, /* Pa'O/Pa'o Karen */ - {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol */ - {"bm", HB_TAG('B','M','B',' ')}, /* Bambara */ - {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ - {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ - {"bpy", HB_TAG('B','P','Y',' ')}, /* Bishnupriya */ - {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari */ - {"br", HB_TAG('B','R','E',' ')}, /* Breton */ - {"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */ - {"brh", HB_TAG('B','R','H',' ')}, /* Brahui */ - {"brx", HB_TAG('B','R','X',' ')}, /* Bodo (India) */ - {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ - {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */ - {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol */ - {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {"bug", HB_TAG('B','U','G',' ')}, /* Buginese */ - {"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */ - {"byn", HB_TAG('B','I','L',' ')}, /* Bilen */ - {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ - {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */ - {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin */ - {"cco", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ - {"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */ - {"cfm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin */ - {"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */ - {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ - {"chj", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ - {"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */ - {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {"chq", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */ - {"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */ - {"chz", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cja", HB_TAG('C','J','A',' ')}, /* Western Cham */ - {"cjm", HB_TAG('C','J','M',' ')}, /* Eastern Cham */ - {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin */ - {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */ - {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */ - {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic */ - {"cle", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin */ - {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin */ - {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin */ - {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin */ - {"cnl", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cnt", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin */ - {"cop", HB_TAG('C','O','P',' ')}, /* Coptic */ - {"cpa", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */ - {"cr", HB_TAG('C','R','E',' ')}, /* Cree */ - {"cre", HB_TAG('Y','C','R',' ')}, /* Y-Cree */ - {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ - {"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */ - {"crk", HB_TAG('W','C','R',' ')}, /* West-Cree */ - {"crl", HB_TAG('E','C','R',' ')}, /* [Northern] East Cree */ - {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ - {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ - {"csa", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */ - {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin */ - {"cso", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin */ - {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin */ - {"cte", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */ - {"ctl", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */ - {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */ - {"cuc", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cuk", HB_TAG('C','U','K',' ')}, /* San Blas Kuna */ - {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ - {"cvn", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin */ - {"da", HB_TAG('D','A','N',' ')}, /* Danish */ - {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin */ - {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */ - {"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */ - {"dax", HB_TAG('D','A','X',' ')}, /* Dayi */ - {"de", HB_TAG('D','E','U',' ')}, /* German */ - {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */ - {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */ - {"dhg", HB_TAG('D','H','G',' ')}, /* Dhangu */ - {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ - {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ - {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ - {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ - {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ - {"dnj", HB_TAG('D','N','J',' ')}, /* Dan */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */ - {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ - {"duj", HB_TAG('D','U','J',' ')}, /* Dhuwal */ - {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi/Divehi/Maldivian */ - {"dyu", HB_TAG('J','U','L',' ')}, /* Jula */ - {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ - {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ - {"efi", HB_TAG('E','F','I',' ')}, /* Efik */ - {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian */ - {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */ - {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan */ - {"en", HB_TAG('E','N','G',' ')}, /* English */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Nenets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Nenets */ - {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ - {"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */ - {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ - {"esu", HB_TAG('E','S','U',' ')}, /* Central Yupik */ - {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ - {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"eve", HB_TAG('E','V','N',' ')}, /* Even */ - {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ - {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ - {"fan", HB_TAG('F','A','N','0')}, /* Fang */ - {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ - {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ - {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ - {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ - {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ - {"flm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin [retired ISO639 code] */ - {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ - {"fon", HB_TAG('F','O','N',' ')}, /* Fon */ - {"fr", HB_TAG('F','R','A',' ')}, /* French */ - {"frc", HB_TAG('F','R','C',' ')}, /* Cajun French */ - {"frp", HB_TAG('F','R','P',' ')}, /* Arpitan/Francoprovençal */ - {"fuf", HB_TAG('F','T','A',' ')}, /* Futa */ - {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ - {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */ - {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ - {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ - {"gag", HB_TAG('G','A','G',' ')}, /* Gagauz */ - {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ - {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */ - {"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */ - {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi */ - {"gih", HB_TAG('G','I','H',' ')}, /* Githabul */ - {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ - {"gkp", HB_TAG('G','K','P',' ')}, /* Kpelle (Guinea) */ - {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ - {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ - {"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */ - {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ - {"gnn", HB_TAG('G','N','N',' ')}, /* Gumatj */ - {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi */ - {"gog", HB_TAG('G','O','G',' ')}, /* Gogo */ - {"gon", HB_TAG('G','O','N',' ')}, /* Gondi [macrolanguage] */ - {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ - {"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */ - {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ - {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ - {"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */ - {"guf", HB_TAG('G','U','F',' ')}, /* Gupapuyngu */ - {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ -/*{"guk", HB_TAG('G','U','K',' ')},*/ /* Gumuz (in SIL fonts) */ - {"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */ - {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ - {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ - {"har", HB_TAG('H','R','I',' ')}, /* Harari */ - {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */ - {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */ - {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */ - {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ - {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ - {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */ - {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin */ - {"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */ - {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */ - {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */ - {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */ - {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ - {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ - {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */ - {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ - {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"ht", HB_TAG('H','A','I',' ')}, /* Haitian/Haitian Creole */ - {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ - {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ - {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ - {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ - {"iba", HB_TAG('I','B','A',' ')}, /* Iban */ - {"ibb", HB_TAG('I','B','B',' ')}, /* Ibibio */ - {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ - {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue/Occidental */ - {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ - {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ - {"ii", HB_TAG('Y','I','M',' ')}, /* Yi Modern */ - {"ijc", HB_TAG('I','J','O',' ')}, /* Izon */ - {"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */ - {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] */ - {"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */ - {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ - {"io", HB_TAG('I','D','O',' ')}, /* Ido */ - {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ - {"it", HB_TAG('I','T','A',' ')}, /* Italian */ - {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ - {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ - {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English */ - {"jbo", HB_TAG('J','B','O',' ')}, /* Lojban */ - {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ - {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ - {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ - {"kat", HB_TAG('K','G','E',' ')}, /* Khutsuri Georgian */ - {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ - {"kde", HB_TAG('K','D','E',' ')}, /* Makonde */ - {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ - {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ - {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ - {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */ - {"kfa", HB_TAG('K','O','D',' ')}, /* Kodagu */ - {"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */ - {"kfx", HB_TAG('K','U','L',' ')}, /* Kulvi */ - {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {"kg", HB_TAG('K','O','N',' ')}, /* Kongo [macrolanguage] */ - {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ - {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ - {"kht", HB_TAG('K','H','N',' ')}, /* Khamti (Microsoft fonts) */ -/*{"kht", HB_TAG('K','H','T',' ')},*/ /* Khamti (OpenType spec and SIL fonts) */ - {"khw", HB_TAG('K','H','W',' ')}, /* Khowar */ - {"ki", HB_TAG('K','I','K',' ')}, /* Gikuyu/Kikuyu */ - {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */ - {"kjd", HB_TAG('K','J','D',' ')}, /* Southern Kiwai */ - {"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */ - {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen */ - {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ - {"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */ - {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */ - {"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */ - {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu */ - {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ - {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ - {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ - {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ - {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {"kok", HB_TAG('K','O','K',' ')}, /* Konkani [macrolanguage] */ - {"kon", HB_TAG('K','O','N','0')}, /* Kongo */ - {"kos", HB_TAG('K','O','S',' ')}, /* Kosraean */ - {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ - {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ - {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ - {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ - {"krl", HB_TAG('K','R','L',' ')}, /* Karelian */ - {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ - {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ - {"ksh", HB_TAG('K','S','H','0')}, /* Ripuarian, Kölsch */ -/*{"ksw", HB_TAG('K','R','N',' ')},*/ /* S'gaw Karen (Microsoft fonts?) */ - {"ksw", HB_TAG('K','S','W',' ')}, /* S'gaw Karen (OpenType spec and SIL fonts) */ - {"ktb", HB_TAG('K','E','B',' ')}, /* Kebena */ - {"ktu", HB_TAG('K','O','N',' ')}, /* Kikongo */ - {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ - {"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */ - {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ - {"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */ - {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ - {"kxc", HB_TAG('K','M','S',' ')}, /* Komso */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */ - {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz/Kyrgyz */ - {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {"la", HB_TAG('L','A','T',' ')}, /* Latin */ - {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ - {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ - {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ - {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ - {"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */ - {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ - {"li", HB_TAG('L','I','M',' ')}, /* Limburgan/Limburger/Limburgish */ - {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ - {"lij", HB_TAG('L','I','J',' ')}, /* Ligurian */ - {"lis", HB_TAG('L','I','S',' ')}, /* Lisu */ - {"ljp", HB_TAG('L','J','P',' ')}, /* Lampung Api */ - {"lki", HB_TAG('L','K','I',' ')}, /* Laki */ - {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ - {"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */ - {"lmo", HB_TAG('L','M','O',' ')}, /* Lombard */ - {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ - {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ - {"lom", HB_TAG('L','O','M',' ')}, /* Loma */ - {"lrc", HB_TAG('L','R','C',' ')}, /* Northern Luri */ - {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ - {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ - {"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */ - {"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */ - {"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */ - {"luy", HB_TAG('L','U','H',' ')}, /* Luyia/Oluluyia [macrolanguage] */ - {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri */ - {"lv", HB_TAG('L','V','I',' ')}, /* Latvian */ - {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ - {"mad", HB_TAG('M','A','D',' ')}, /* Madurese */ - {"mag", HB_TAG('M','A','G',' ')}, /* Magahi */ - {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ - {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ - {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ - {"man", HB_TAG('M','N','K',' ')}, /* Manding/Mandingo [macrolanguage] */ - {"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */ - {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ - {"mdr", HB_TAG('M','D','R',' ')}, /* Mandar */ - {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ - {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ - {"mer", HB_TAG('M','E','R',' ')}, /* Meru */ - {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ - {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ - {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ - {"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */ - {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ - {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ - {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka */ - {"mkw", HB_TAG('M','K','W',' ')}, /* Kituba (Congo) */ - {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */ - {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan */ - {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ - {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ - {"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */ - {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ - {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ - {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ - {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */ - {"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */ - {"mos", HB_TAG('M','O','S',' ')}, /* Mossi */ - {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ - {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ - {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin */ - {"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */ - {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ - {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */ - {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ - {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari */ - {"mus", HB_TAG('M','U','S',' ')}, /* Creek */ - {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ - {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan */ - {"mwl", HB_TAG('M','W','L',' ')}, /* Mirandese */ - {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ - {"mym", HB_TAG('M','E','N',' ')}, /* Me'en */ - {"myn", HB_TAG('M','Y','N',' ')}, /* Mayan */ - {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) */ - {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ - {"mzn", HB_TAG('M','Z','N',' ')}, /* Mazanderani */ - {"na", HB_TAG('N','A','U',' ')}, /* Nauru */ - {"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */ - {"nah", HB_TAG('N','A','H',' ')}, /* Nahuatl [family] */ - {"nap", HB_TAG('N','A','P',' ')}, /* Neapolitan */ - {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */ - {"nco", HB_TAG('S','I','B',' ')}, /* Sibe */ - {"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */ - {"ndc", HB_TAG('N','D','C',' ')}, /* Ndau */ - {"nds", HB_TAG('N','D','S',' ')}, /* Low German/Low Saxon */ - {"ne", HB_TAG('N','E','P',' ')}, /* Nepali */ - {"new", HB_TAG('N','E','W',' ')}, /* Newari */ - {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ - {"nga", HB_TAG('N','G','A',' ')}, /* Ngabaka */ - {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Sutu */ - {"niu", HB_TAG('N','I','U',' ')}, /* Niuean */ - {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ - {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ - {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */ - {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ - {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai */ - {"noe", HB_TAG('N','O','E',' ')}, /* Nimadi */ - {"nog", HB_TAG('N','O','G',' ')}, /* Nogai */ - {"nov", HB_TAG('N','O','V',' ')}, /* Novial */ - {"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */ - {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */ - {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ - {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */ - {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ - {"ny", HB_TAG('C','H','I',' ')}, /* Chewa/Chichwa/Nyanja */ - {"nym", HB_TAG('N','Y','M',' ')}, /* Nyamwezi */ - {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ - {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ - {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] */ - {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */ - {"okm", HB_TAG('K','O','H',' ')}, /* Korean Old Hangul */ - {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ - {"or", HB_TAG('O','R','I',' ')}, /* Oriya */ - {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ - {"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */ - {"pag", HB_TAG('P','A','G',' ')}, /* Pangasinan */ - {"pam", HB_TAG('P','A','M',' ')}, /* Kapampangan/Pampanga */ - {"pap", HB_TAG('P','A','P','0')}, /* Papiamento */ - {"pau", HB_TAG('P','A','U',' ')}, /* Palauan */ - {"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */ - {"pcd", HB_TAG('P','C','D',' ')}, /* Picard */ - {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */ - {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin */ - {"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */ - {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */ - {"phk", HB_TAG('P','H','K',' ')}, /* Phake */ - {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ - {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk */ - {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ - {"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa */ - {"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */ - {"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */ - {"poh", HB_TAG('P','O','H',' ')}, /* Pocomchi */ - {"pon", HB_TAG('P','O','N',' ')}, /* Pohnpeian */ - {"prs", HB_TAG('D','R','I',' ')}, /* Afghan Persian/Dari */ - {"ps", HB_TAG('P','A','S',' ')}, /* Pashto/Pushto [macrolanguage] */ - {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ - {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen */ - {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ - {"quc", HB_TAG('Q','U','C',' ')}, /* K'iche'/Quiché */ - {"quh", HB_TAG('Q','U','H',' ')}, /* Quechua (Bolivia) */ - {"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */ - {"qvi", HB_TAG('Q','V','I',' ')}, /* Quechua (Ecuador) */ - {"qwh", HB_TAG('Q','W','H',' ')}, /* Quechua (Peru) */ - {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */ - {"rar", HB_TAG('R','A','R',' ')}, /* Rarotongan */ - {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */ - {"rej", HB_TAG('R','E','J',' ')}, /* Rejang */ - {"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */ - {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ - {"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */ - {"rit", HB_TAG('R','I','T',' ')}, /* Ritarungo */ - {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ - {"rkw", HB_TAG('R','K','W',' ')}, /* Arakwal */ - {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ - {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ - {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ - {"rtm", HB_TAG('R','T','M',' ')}, /* Rotuman */ - {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ - {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ - {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */ - {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ - {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ - {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */ - {"sam", HB_TAG('P','A','A',' ')}, /* Palestinian Aramaic */ - {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */ - {"sat", HB_TAG('S','A','T',' ')}, /* Santali */ - {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ - {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ - {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */ - {"sco", HB_TAG('S','C','O',' ')}, /* Scots */ - {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */ - {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ - {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ - {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ - {"sel", HB_TAG('S','E','L',' ')}, /* Selkup */ - {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin */ - {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ - {"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */ - {"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */ - {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage */ -/*{"sgw", HB_TAG('S','G','W',' ')},*/ /* Sebat Bet Gurage (in SIL fonts) */ - {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {"shn", HB_TAG('S','H','N',' ')}, /* Shan */ - {"si", HB_TAG('S','N','H',' ')}, /* Sinhala */ - {"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */ - {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ - {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ - {"skr", HB_TAG('S','R','K',' ')}, /* Seraiki */ - {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ - {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ - {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ - {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ - {"sn", HB_TAG('S','N','A','0')}, /* Shona */ - {"snk", HB_TAG('S','N','K',' ')}, /* Soninke */ - {"so", HB_TAG('S','M','L',' ')}, /* Somali */ - {"sop", HB_TAG('S','O','P',' ')}, /* Songe */ - {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ - {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ - {"srr", HB_TAG('S','R','R',' ')}, /* Serer */ - {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ - {"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */ - {"stq", HB_TAG('S','T','Q',' ')}, /* Saterfriesisch */ - {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e */ - {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ - {"suk", HB_TAG('S','U','K',' ')}, /* Sukama */ - {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ - {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ - {"sva", HB_TAG('S','V','A',' ')}, /* Svan */ - {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ - {"swb", HB_TAG('C','M','R',' ')}, /* Comorian */ - {"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */ - {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */ - {"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */ - {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac */ - {"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */ - {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */ - {"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */ - {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ - {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */ - {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin */ - {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */ - {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin */ - {"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */ - {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ - {"tem", HB_TAG('T','M','N',' ')}, /* Temne */ - {"tet", HB_TAG('T','E','T',' ')}, /* Tetum */ - {"tg", HB_TAG('T','A','J',' ')}, /* Tajik */ - {"th", HB_TAG('T','H','A',' ')}, /* Thai */ - {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ - {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ - {"tiv", HB_TAG('T','I','V',' ')}, /* Tiv */ - {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ - {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ - {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek */ - {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */ - {"tod", HB_TAG('T','O','D','0')}, /* Toma */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga */ - {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ - {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */ - {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ - {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ - {"tum", HB_TAG('T','U','M',' ')}, /* Tumbuka */ - {"tvl", HB_TAG('T','V','L',' ')}, /* Tuvalu */ - {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ - {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ - {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */ - {"tyz", HB_TAG('T','Y','Z',' ')}, /* Tày */ - {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight */ - {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */ - {"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */ - {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ - {"umb", HB_TAG('U','M','B',' ')}, /* Umbundu */ - {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ - {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ - {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ - {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek */ - {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */ - {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ - {"vec", HB_TAG('V','E','C',' ')}, /* Venetian */ - {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ - {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */ - {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ - {"vro", HB_TAG('V','R','O',' ')}, /* Võro */ - {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ - {"war", HB_TAG('W','A','R',' ')}, /* Waray (Philippines) */ - {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ - {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ - {"wle", HB_TAG('S','I','G',' ')}, /* Wolane */ - {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ - {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */ - {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */ - {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {"xan", HB_TAG('S','E','K',' ')}, /* Sekota */ - {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ - {"xjb", HB_TAG('X','J','B',' ')}, /* Minjangbal */ - {"xog", HB_TAG('X','O','G',' ')}, /* Soga */ - {"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */ - {"xpe", HB_TAG('X','P','E',' ')}, /* Kpelle (Liberia) */ - {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ - {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */ - {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */ - {"yao", HB_TAG('Y','A','O',' ')}, /* Yao */ - {"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */ - {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ - {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ - {"yos", HB_TAG('Q','I','N',' ')}, /* Yos, deprecated by IANA in favor of Zou [zom] */ - {"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */ - {"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */ - {"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */ - {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */ - {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ - {"zom", HB_TAG('Q','I','N',' ')}, /* Zou */ - {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ - {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */ - {"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */ - - /* The corresponding languages IDs for the following IDs are unclear, - * overlap, or are architecturally weird. Needs more research. */ - -/*{"chp", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */ -/*{"cwd", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ -/*{"emk", HB_TAG('E','M','K',' ')},*/ /* Eastern Maninkakan */ -/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */ -/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */ -/*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */ -/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */ -/*{"hy?", HB_TAG('H','Y','E','0')},*/ /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */ -/*{"ga-Latg?/" HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */ -/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */ -/*{"ka-Geok?", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */ -/*{"kca", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */ -/*{"kca", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */ -/*{"kca", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */ -/*{"kqs, kss", HB_TAG('K','I','S',' ')},*/ /* Kisii */ -/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ -/*{"mlq", HB_TAG('M','L','N',' ')},*/ /* Malinke */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Sotho, Northern */ -/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */ -/*{"csw", HB_TAG('N','C','R',' ')},*/ /* N-Cree */ -/*{"csw", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */ -/*{"el-polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */ -/*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh", HB_TAG('Q','I','N',' ')},*/ /* Chin */ -/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ -/*{"zh-Latn-pinyin", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ -}; - -typedef struct { - char language[11]; - hb_tag_t tag; -} LangTagLong; -static const LangTagLong ot_languages_zh[] = { - /* Store longest-first, if one is a prefix of another. */ - {"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */ - {"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ - {"zh-mo", HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */ - {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */ - {"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */ - {"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */ - {"zh-hant-hk",HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ - {"zh-hant-mo",HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */ - {"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */ -}; - static int lang_compare_first_component (const void *pa, const void *pb) @@ -895,6 +189,21 @@ lang_compare_first_component (const void *pa, return strncmp (a, b, MAX (da, db)); } +static bool +subtag_matches (const char *lang_str, + const char *limit, + const char *subtag) +{ + do { + const char *s = strstr (lang_str, subtag); + if (!s || s >= limit) + return false; + if (!ISALNUM (s[strlen (subtag)])) + return true; + lang_str = s + strlen (subtag); + } while (true); +} + static hb_bool_t lang_matches (const char *lang_str, const char *spec) { @@ -904,106 +213,186 @@ lang_matches (const char *lang_str, const char *spec) (lang_str[len] == '\0' || lang_str[len] == '-'); } +typedef struct { + char language[4]; + hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; +} LangTag; + +#include "hb-ot-tag-table.hh" + +/* The corresponding languages IDs for the following IDs are unclear, + * overlap, or are architecturally weird. Needs more research. */ + +/*{"??", {HB_TAG('B','C','R',' ')}},*/ /* Bible Cree */ +/*{"zh?", {HB_TAG('C','H','N',' ')}},*/ /* Chinese (seen in Microsoft fonts) */ +/*{"ar-Syrc?", {HB_TAG('G','A','R',' ')}},*/ /* Garshuni */ +/*{"??", {HB_TAG('N','G','R',' ')}},*/ /* Nagari */ +/*{"??", {HB_TAG('Y','I','C',' ')}},*/ /* Yi Classic */ +/*{"zh?", {HB_TAG('Z','H','P',' ')}},*/ /* Chinese Phonetic */ + hb_tag_t hb_ot_tag_from_language (hb_language_t language) { - const char *lang_str, *s; + unsigned int count = 1; + hb_tag_t tags[1]; + hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags); + return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE; +} - if (language == HB_LANGUAGE_INVALID) - return HB_OT_TAG_DEFAULT_LANGUAGE; +static void +hb_ot_tags_from_language (const char *lang_str, + const char *limit, + unsigned int *count, + hb_tag_t *tags) +{ + const char *s; - lang_str = hb_language_to_string (language); + /* Check for matches of multiple subtags. */ + if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) + return; - s = strstr (lang_str, "x-hbot"); - if (s) { - char tag[4]; - int i; - s += 6; - for (i = 0; i < 4 && ISALNUM (s[i]); i++) - tag[i] = TOUPPER (s[i]); - if (i) { - for (; i < 4; i++) - tag[i] = ' '; - return HB_TAG (tag[0], tag[1], tag[2], tag[3]); + /* Find a language matching in the first component. */ + s = strchr (lang_str, '-'); + { + const LangTag *lang_tag; + if (s && limit - lang_str >= 6) + { + const char *extlang_end = strchr (s + 1, '-'); + /* If there is an extended language tag, use it. */ + if (3 == (extlang_end ? extlang_end - s - 1 : strlen (s + 1)) && + ISALPHA (s[1])) + lang_str = s + 1; + } + lang_tag = (LangTag *) bsearch (lang_str, ot_languages, + ARRAY_LENGTH (ot_languages), sizeof (LangTag), + lang_compare_first_component); + if (lang_tag) + { + unsigned int i; + for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++) + tags[i] = lang_tag->tags[i]; + *count = i; + return; } } - /* - * "fonipa" is a variant tag in BCP-47, meaning the International Phonetic Alphabet. - * It can be applied to any language. - */ - if (strstr (lang_str, "-fonipa")) { - return HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ - } - - /* - * "fonnapa" is a variant tag in BCP-47, meaning the North American Phonetic Alphabet - * also known as Americanist Phonetic Notation. It can be applied to any language. - */ - if (strstr (lang_str, "-fonnapa")) { - return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + if (!s) + s = lang_str + strlen (lang_str); + if (s - lang_str == 3) { + /* Assume it's ISO-639-3 and upper-case and use it. */ + tags[0] = hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u; + *count = 1; + return; } - /* - * "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syre")) { - return HB_TAG('S','Y','R','E'); /* Estrangela Syriac */ - } + *count = 0; +} - /* - * "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syrj")) { - return HB_TAG('S','Y','R','J'); /* Western Syriac */ +static bool +parse_private_use_subtag (const char *private_use_subtag, + unsigned int *count, + hb_tag_t *tags, + const char *prefix, + unsigned char (*normalize) (unsigned char)) +{ + if (private_use_subtag && count && tags && *count) + { + const char *s = strstr (private_use_subtag, prefix); + if (s) + { + char tag[4]; + int i; + s += strlen (prefix); + for (i = 0; i < 4 && ISALNUM (s[i]); i++) + tag[i] = normalize (s[i]); + if (i) + { + for (; i < 4; i++) + tag[i] = ' '; + tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]); + if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT) + tags[0] ^= ~0xDFDFDFDF; + *count = 1; + return false; + } + } } + return true; +} - /* - * "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syrn")) { - return HB_TAG('S','Y','R','N'); /* Eastern Syriac */ - } +/** + * hb_ot_tags_from_script_and_language: + * @script: an #hb_script_t to convert. + * @language: an #hb_language_t to convert. + * @script_count: (allow-none): maximum number of script tags to retrieve (IN) + * and actual number of script tags retrieved (OUT) + * @script_tags: (out) (allow-none): array of size at least @script_count to store the + * script tag results + * @language_count: (allow-none): maximum number of language tags to retrieve + * (IN) and actual number of language tags retrieved (OUT) + * @language_tags: (out) (allow-none): array of size at least @language_count to store + * the language tag results + * + * Converts an #hb_script_t and an #hb_language_t to script and language tags. + * + * Since: 2.0.0 + **/ +void +hb_ot_tags_from_script_and_language (hb_script_t script, + hb_language_t language, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */, + unsigned int *language_count /* IN/OUT */, + hb_tag_t *language_tags /* OUT */) +{ + bool needs_script = true; - /* Find a language matching in the first component */ + if (language == HB_LANGUAGE_INVALID) { - const LangTag *lang_tag; - lang_tag = (LangTag *) bsearch (lang_str, ot_languages, - ARRAY_LENGTH (ot_languages), sizeof (LangTag), - lang_compare_first_component); - if (lang_tag) - return lang_tag->tag; + if (language_count && language_tags && *language_count) + *language_count = 0; } - - /* Otherwise, check the Chinese ones */ - if (0 == lang_compare_first_component (lang_str, "zh")) + else { - unsigned int i; + const char *lang_str, *s, *limit, *private_use_subtag; + bool needs_language; - for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) + lang_str = hb_language_to_string (language); + limit = nullptr; + private_use_subtag = nullptr; + if (lang_str[0] == 'x' && lang_str[1] == '-') { - const LangTagLong *lang_tag; - lang_tag = &ot_languages_zh[i]; - if (lang_matches (lang_str, lang_tag->language)) - return lang_tag->tag; + private_use_subtag = lang_str; + } else { + for (s = lang_str + 1; *s; s++) + { + if (s[-1] == '-' && s[1] == '-') + { + if (s[0] == 'x') + { + private_use_subtag = s; + if (!limit) + limit = s - 1; + break; + } else if (!limit) + { + limit = s - 1; + } + } + } + if (!limit) + limit = s; } - /* Otherwise just return 'ZHS ' */ - return HB_TAG('Z','H','S',' '); - } + needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER); + needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER); - s = strchr (lang_str, '-'); - if (!s) - s = lang_str + strlen (lang_str); - if (s - lang_str == 3) { - /* Assume it's ISO-639-3 and upper-case and use it. */ - return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u; + if (needs_language && language_count && language_tags && *language_count) + hb_ot_tags_from_language (lang_str, limit, language_count, language_tags); } - return HB_OT_TAG_DEFAULT_LANGUAGE; + if (needs_script && script_count && script_tags && *script_count) + hb_ot_all_tags_from_script (script, script_count, script_tags); } /** @@ -1023,36 +412,16 @@ hb_ot_tag_to_language (hb_tag_t tag) if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) return nullptr; - /* struct LangTag has only room for 3-letter language tags. */ - switch (tag) { - case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ - return hb_language_from_string ("und-fonnapa", -1); - case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ - return hb_language_from_string ("und-fonipa", -1); - case HB_TAG('S','Y','R',' '): /* Syriac [macrolanguage] */ - return hb_language_from_string ("syr", -1); - case HB_TAG('S','Y','R','E'): /* Estrangela Syriac */ - return hb_language_from_string ("und-Syre", -1); - case HB_TAG('S','Y','R','J'): /* Western Syriac */ - return hb_language_from_string ("und-Syrj", -1); - case HB_TAG('S','Y','R','N'): /* Eastern Syriac */ - return hb_language_from_string ("und-Syrn", -1); + { + hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag); + if (disambiguated_tag != HB_LANGUAGE_INVALID) + return disambiguated_tag; } for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tag == tag) + if (ot_languages[i].tags[0] == tag) return hb_language_from_string (ot_languages[i].language, -1); - /* If tag starts with ZH, it's Chinese */ - if ((tag & 0xFFFF0000u) == 0x5A480000u) { - switch (tag) { - case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */ - case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */ - case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */ - default: break; /* Fall through */ - } - } - /* Else return a custom language in the form of "x-hbotABCD" */ { unsigned char buf[11] = "x-hbot"; @@ -1067,9 +436,74 @@ hb_ot_tag_to_language (hb_tag_t tag) } } +/** + * hb_ot_tags_to_script_and_language: + * @script_tag: a script tag + * @language_tag: a language tag + * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT). + * @language: (allow-none): the #hb_language_t corresponding to @script_tag and + * @language_tag (OUT). + * + * Converts a script tag and a language tag to an #hb_script_t and an + * #hb_language_t. + * + * Since: 2.0.0 + **/ +void +hb_ot_tags_to_script_and_language (hb_tag_t script_tag, + hb_tag_t language_tag, + hb_script_t *script /* OUT */, + hb_language_t *language /* OUT */) +{ + hb_script_t script_out = hb_ot_tag_to_script (script_tag); + if (script) + *script = script_out; + if (language) + { + unsigned int script_count = 1; + hb_tag_t primary_script_tag[1]; + hb_ot_tags_from_script_and_language (script_out, + HB_LANGUAGE_INVALID, + &script_count, + primary_script_tag, + nullptr, nullptr); + *language = hb_ot_tag_to_language (language_tag); + if (script_count == 0 || primary_script_tag[0] != script_tag) + { + unsigned char *buf; + const char *lang_str = hb_language_to_string (*language); + size_t len = strlen (lang_str); + buf = (unsigned char *) malloc (len + 11); + if (unlikely (!buf)) + { + *language = nullptr; + } + else + { + memcpy (buf, lang_str, len); + if (lang_str[0] != 'x' || lang_str[1] != '-') { + buf[len++] = '-'; + buf[len++] = 'x'; + } + buf[len++] = '-'; + buf[len++] = 'h'; + buf[len++] = 'b'; + buf[len++] = 's'; + buf[len++] = 'c'; + buf[len++] = script_tag >> 24; + buf[len++] = (script_tag >> 16) & 0xFF; + buf[len++] = (script_tag >> 8) & 0xFF; + buf[len++] = script_tag & 0xFF; + *language = hb_language_from_string ((char *) buf, len); + free (buf); + } + } + } +} + #ifdef MAIN static inline void -test_langs_sorted (void) +test_langs_sorted () { for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++) { @@ -1084,7 +518,7 @@ test_langs_sorted (void) } int -main (void) +main () { test_langs_sorted (); return 0; diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh index ad063d3..c4a192d 100644 --- a/src/hb-ot-var-avar-table.hh +++ b/src/hb-ot-var-avar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_AVAR_TABLE_HH #define HB_OT_VAR_AVAR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * avar -- Axis Variations @@ -42,7 +42,7 @@ namespace OT { struct AxisValueMap { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -59,7 +59,7 @@ struct AxisValueMap struct SegmentMaps : ArrayOf<AxisValueMap> { - inline int map (int value) const + int map (int value) const { /* The following special-cases are not part of OpenType, which requires * that at least -1, 0, and +1 must be mapped. But we include these as @@ -93,14 +93,15 @@ struct SegmentMaps : ArrayOf<AxisValueMap> (value - arrayZ[i-1].fromCoord) + denom/2) / denom; } - DEFINE_SIZE_ARRAY (2, arrayZ); + public: + DEFINE_SIZE_ARRAY (2, *this); }; struct avar { - static const hb_tag_t tableTag = HB_OT_TAG_avar; + static constexpr hb_tag_t tableTag = HB_OT_TAG_avar; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!(version.sanitize (c) && @@ -108,7 +109,7 @@ struct avar c->check_struct (this)))) return_trace (false); - const SegmentMaps *map = axisSegmentMapsZ; + const SegmentMaps *map = &firstAxisSegmentMaps; unsigned int count = axisCount; for (unsigned int i = 0; i < count; i++) { @@ -120,11 +121,11 @@ struct avar return_trace (true); } - inline void map_coords (int *coords, unsigned int coords_length) const + void map_coords (int *coords, unsigned int coords_length) const { unsigned int count = MIN<unsigned int> (coords_length, axisCount); - const SegmentMaps *map = axisSegmentMapsZ; + const SegmentMaps *map = &firstAxisSegmentMaps; for (unsigned int i = 0; i < count; i++) { coords[i] = map->map (coords[i]); @@ -139,7 +140,7 @@ struct avar HBUINT16 axisCount; /* The number of variation axes in the font. This * must be the same number as axisCount in the * 'fvar' table. */ - SegmentMaps axisSegmentMapsZ[VAR]; + SegmentMaps firstAxisSegmentMaps; public: DEFINE_SIZE_MIN (8); diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh index 82d2996..78cb3c8 100644 --- a/src/hb-ot-var-fvar-table.hh +++ b/src/hb-ot-var-fvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_FVAR_TABLE_HH #define HB_OT_VAR_FVAR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * fvar -- Font Variations @@ -42,29 +42,40 @@ namespace OT { struct InstanceRecord { - inline bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const + friend struct fvar; + + hb_array_t<const Fixed> get_coordinates (unsigned int axis_count) const + { return coordinatesZ.as_array (axis_count); } + + bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (coordinates, coordinates[0].static_size, axis_count)); + c->check_array (coordinatesZ.arrayZ, axis_count)); } protected: NameID subfamilyNameID;/* The name ID for entries in the 'name' table * that provide subfamily names for this instance. */ - HBUINT16 reserved; /* Reserved for future use — set to 0. */ - Fixed coordinates[VAR];/* The coordinates array for this instance. */ + HBUINT16 flags; /* Reserved for future use — set to 0. */ + UnsizedArrayOf<Fixed> + coordinatesZ; /* The coordinates array for this instance. */ //NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name' // * table that provide PostScript names for this // * instance. */ public: - DEFINE_SIZE_ARRAY (4, coordinates); + DEFINE_SIZE_UNBOUNDED (4); }; struct AxisRecord { - inline bool sanitize (hb_sanitize_context_t *c) const + enum + { + AXIS_FLAG_HIDDEN = 0x0001, + }; + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -75,7 +86,7 @@ struct AxisRecord Fixed minValue; /* The minimum coordinate value for the axis. */ Fixed defaultValue; /* The default coordinate value for the axis. */ Fixed maxValue; /* The maximum coordinate value for the axis. */ - HBUINT16 reserved; /* Reserved for future use — set to 0. */ + HBUINT16 flags; /* Axis flags. */ NameID axisNameID; /* The name ID for entries in the 'name' table that * provide a display name for this axis. */ @@ -85,50 +96,80 @@ struct AxisRecord struct fvar { - static const hb_tag_t tableTag = HB_OT_TAG_fvar; + static constexpr hb_tag_t tableTag = HB_OT_TAG_fvar; - inline bool sanitize (hb_sanitize_context_t *c) const + bool has_data () const { return version.to_int (); } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && likely (version.major == 1) && c->check_struct (this) && + axisSize == 20 && /* Assumed in our code. */ instanceSize >= axisCount * 4 + 4 && - axisSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */ - instanceSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */ - c->check_range (this, things) && - c->check_range (&StructAtOffset<char> (this, things), - axisCount * axisSize + instanceCount * instanceSize)); + get_axes ().sanitize (c) && + c->check_range (get_instance (0), instanceCount, instanceSize)); } - inline unsigned int get_axis_count (void) const - { return axisCount; } + unsigned int get_axis_count () const { return axisCount; } + + void get_axis_deprecated (unsigned int axis_index, + hb_ot_var_axis_t *info) const + { + const AxisRecord &axis = get_axes ()[axis_index]; + info->tag = axis.axisTag; + info->name_id = axis.axisNameID; + info->default_value = axis.defaultValue / 65536.; + /* Ensure order, to simplify client math. */ + info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.); + info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.); + } - inline bool get_axis (unsigned int index, hb_ot_var_axis_t *info) const + void get_axis_info (unsigned int axis_index, + hb_ot_var_axis_info_t *info) const { - if (unlikely (index >= axisCount)) - return false; + const AxisRecord &axis = get_axes ()[axis_index]; + info->axis_index = axis_index; + info->tag = axis.axisTag; + info->name_id = axis.axisNameID; + info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags; + info->default_value = axis.defaultValue / 65536.; + /* Ensure order, to simplify client math. */ + info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.); + info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.); + info->reserved = 0; + } - if (info) + unsigned int get_axes_deprecated (unsigned int start_offset, + unsigned int *axes_count /* IN/OUT */, + hb_ot_var_axis_t *axes_array /* OUT */) const + { + if (axes_count) { - const AxisRecord &axis = get_axes ()[index]; - info->tag = axis.axisTag; - info->name_id = axis.axisNameID; - info->default_value = axis.defaultValue / 65536.; - /* Ensure order, to simplify client math. */ - info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.); - info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.); - } + /* TODO Rewrite as hb_array_t<>::sub-array() */ + unsigned int count = axisCount; + start_offset = MIN (start_offset, count); - return true; + count -= start_offset; + axes_array += start_offset; + + count = MIN (count, *axes_count); + *axes_count = count; + + for (unsigned int i = 0; i < count; i++) + get_axis_deprecated (start_offset + i, axes_array + i); + } + return axisCount; } - inline unsigned int get_axis_infos (unsigned int start_offset, - unsigned int *axes_count /* IN/OUT */, - hb_ot_var_axis_t *axes_array /* OUT */) const + unsigned int get_axis_infos (unsigned int start_offset, + unsigned int *axes_count /* IN/OUT */, + hb_ot_var_axis_info_t *axes_array /* OUT */) const { if (axes_count) { + /* TODO Rewrite as hb_array_t<>::sub-array() */ unsigned int count = axisCount; start_offset = MIN (start_offset, count); @@ -139,32 +180,48 @@ struct fvar *axes_count = count; for (unsigned int i = 0; i < count; i++) - get_axis (start_offset + i, axes_array + i); + get_axis_info (start_offset + i, axes_array + i); } return axisCount; } - inline bool find_axis (hb_tag_t tag, unsigned int *index, hb_ot_var_axis_t *info) const + bool find_axis_deprecated (hb_tag_t tag, + unsigned int *axis_index, + hb_ot_var_axis_t *info) const { const AxisRecord *axes = get_axes (); unsigned int count = get_axis_count (); for (unsigned int i = 0; i < count; i++) if (axes[i].axisTag == tag) { - if (index) - *index = i; - return get_axis (i, info); + if (axis_index) + *axis_index = i; + get_axis_deprecated (i, info); + return true; } - if (index) - *index = HB_OT_VAR_NO_AXIS_INDEX; + if (axis_index) + *axis_index = HB_OT_VAR_NO_AXIS_INDEX; return false; } - inline int normalize_axis_value (unsigned int axis_index, float v) const + bool find_axis_info (hb_tag_t tag, + hb_ot_var_axis_info_t *info) const { - hb_ot_var_axis_t axis; - if (!get_axis (axis_index, &axis)) - return 0; + const AxisRecord *axes = get_axes (); + unsigned int count = get_axis_count (); + for (unsigned int i = 0; i < count; i++) + if (axes[i].axisTag == tag) + { + get_axis_info (i, info); + return true; + } + return false; + } + + int normalize_axis_value (unsigned int axis_index, float v) const + { + hb_ot_var_axis_info_t axis; + get_axis_info (axis_index, &axis); v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */ @@ -174,20 +231,65 @@ struct fvar v = (v - axis.default_value) / (axis.default_value - axis.min_value); else v = (v - axis.default_value) / (axis.max_value - axis.default_value); - return (int) (v * 16384. + (v >= 0. ? .5 : -.5)); + return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f)); + } + + unsigned int get_instance_count () const { return instanceCount; } + + hb_ot_name_id_t get_instance_subfamily_name_id (unsigned int instance_index) const + { + const InstanceRecord *instance = get_instance (instance_index); + if (unlikely (!instance)) return HB_OT_NAME_ID_INVALID; + return instance->subfamilyNameID; + } + + hb_ot_name_id_t get_instance_postscript_name_id (unsigned int instance_index) const + { + const InstanceRecord *instance = get_instance (instance_index); + if (unlikely (!instance)) return HB_OT_NAME_ID_INVALID; + if (instanceSize >= axisCount * 4 + 6) + return StructAfter<NameID> (instance->get_coordinates (axisCount)); + return HB_OT_NAME_ID_INVALID; + } + + unsigned int get_instance_coords (unsigned int instance_index, + unsigned int *coords_length, /* IN/OUT */ + float *coords /* OUT */) const + { + const InstanceRecord *instance = get_instance (instance_index); + if (unlikely (!instance)) + { + if (coords_length) + *coords_length = 0; + return 0; + } + + if (coords_length && *coords_length) + { + hb_array_t<const Fixed> instanceCoords = instance->get_coordinates (axisCount) + .sub_array (0, *coords_length); + for (unsigned int i = 0; i < instanceCoords.length; i++) + coords[i] = instanceCoords.arrayZ[i].to_float (); + } + return axisCount; } protected: - inline const AxisRecord * get_axes (void) const - { return &StructAtOffset<AxisRecord> (this, things); } + hb_array_t<const AxisRecord> get_axes () const + { return hb_array (&(this+firstAxis), axisCount); } - inline const InstanceRecord * get_instances (void) const - { return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); } + const InstanceRecord *get_instance (unsigned int i) const + { + if (unlikely (i >= instanceCount)) return nullptr; + return &StructAtOffset<InstanceRecord> (&StructAfter<InstanceRecord> (get_axes ()), + i * instanceSize); + } protected: FixedVersion<>version; /* Version of the fvar table * initially set to 0x00010000u */ - Offset16 things; /* Offset in bytes from the beginning of the table + OffsetTo<AxisRecord> + firstAxis; /* Offset in bytes from the beginning of the table * to the start of the AxisRecord array. */ HBUINT16 reserved; /* This field is permanently reserved. Set to 2. */ HBUINT16 axisCount; /* The number of variation axes in the font (the diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 2b384db..a8d9fe3 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_HVAR_TABLE_HH #define HB_OT_VAR_HVAR_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" namespace OT { @@ -35,11 +35,13 @@ namespace OT { struct DeltaSetIndexMap { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (mapData, get_width (), mapCount)); + c->check_range (mapDataZ.arrayZ, + mapCount, + get_width ())); } unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ @@ -55,7 +57,7 @@ struct DeltaSetIndexMap unsigned int u = 0; { /* Fetch it. */ unsigned int w = get_width (); - const HBUINT8 *p = mapData + w * v; + const HBUINT8 *p = mapDataZ.arrayZ + w * v; for (; w; w--) u = (u << 8) + *p++; } @@ -71,20 +73,19 @@ struct DeltaSetIndexMap } protected: - inline unsigned int get_width (void) const - { return ((format >> 4) & 3) + 1; } + unsigned int get_width () const { return ((format >> 4) & 3) + 1; } - inline unsigned int get_inner_bitcount (void) const - { return (format & 0xF) + 1; } + unsigned int get_inner_bitcount () const { return (format & 0xF) + 1; } protected: HBUINT16 format; /* A packed field that describes the compressed * representation of delta-set indices. */ HBUINT16 mapCount; /* The number of mapping entries. */ - HBUINT8 mapData[VAR]; /* The delta-set index mapping data. */ + UnsizedArrayOf<HBUINT8> + mapDataZ; /* The delta-set index mapping data. */ public: - DEFINE_SIZE_ARRAY (4, mapData); + DEFINE_SIZE_ARRAY (4, mapDataZ); }; @@ -99,10 +100,10 @@ struct DeltaSetIndexMap struct HVARVVAR { - static const hb_tag_t HVARTag = HB_OT_TAG_HVAR; - static const hb_tag_t VVARTag = HB_OT_TAG_VVAR; + static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR; + static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && @@ -113,15 +114,14 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } - inline float get_advance_var (hb_codepoint_t glyph, - int *coords, unsigned int coord_count) const + float get_advance_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count) const { unsigned int varidx = (this+advMap).map (glyph); return (this+varStore).get_delta (varidx, coords, coord_count); } - inline bool has_sidebearing_deltas (void) const - { return lsbMap && rsbMap; } + bool has_sidebearing_deltas () const { return lsbMap && rsbMap; } protected: FixedVersion<>version; /* Version of the metrics variation table @@ -140,12 +140,12 @@ struct HVARVVAR }; struct HVAR : HVARVVAR { - static const hb_tag_t tableTag = HB_OT_TAG_HVAR; + static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR; }; struct VVAR : HVARVVAR { - static const hb_tag_t tableTag = HB_OT_TAG_VVAR; + static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (static_cast<const HVARVVAR *> (this)->sanitize (c) && diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh index dfde782..0dd63e5 100644 --- a/src/hb-ot-var-mvar-table.hh +++ b/src/hb-ot-var-mvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_MVAR_TABLE_HH #define HB_OT_VAR_MVAR_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" namespace OT { @@ -35,7 +35,7 @@ namespace OT { struct VariationValueRecord { - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -58,9 +58,9 @@ struct VariationValueRecord struct MVAR { - static const hb_tag_t tableTag = HB_OT_TAG_MVAR; + static constexpr hb_tag_t tableTag = HB_OT_TAG_MVAR; - inline bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && @@ -68,14 +68,16 @@ struct MVAR c->check_struct (this) && valueRecordSize >= VariationValueRecord::static_size && varStore.sanitize (c, this) && - c->check_array (values, valueRecordSize, valueRecordCount)); + c->check_range (valuesZ.arrayZ, + valueRecordCount, + valueRecordSize)); } - inline float get_var (hb_tag_t tag, - int *coords, unsigned int coord_count) const + float get_var (hb_tag_t tag, + const int *coords, unsigned int coord_count) const { const VariationValueRecord *record; - record = (VariationValueRecord *) bsearch (&tag, values, + record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ, valueRecordCount, valueRecordSize, tag_compare); if (!record) @@ -85,7 +87,7 @@ struct MVAR } protected: - static inline int tag_compare (const void *pa, const void *pb) + static int tag_compare (const void *pa, const void *pb) { const hb_tag_t *a = (const hb_tag_t *) pa; const Tag *b = (const Tag *) pb; @@ -101,11 +103,12 @@ protected: HBUINT16 valueRecordCount;/* The number of value records — may be zero. */ OffsetTo<VariationStore> varStore; /* Offset to item variation store table. */ - HBUINT8 values[VAR]; /* Array of value records. The records must be + UnsizedArrayOf<HBUINT8> + valuesZ; /* Array of value records. The records must be * in binary order of their valueTag field. */ public: - DEFINE_SIZE_ARRAY (12, values); + DEFINE_SIZE_ARRAY (12, valuesZ); }; } /* namespace OT */ diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc index f0612a6..e327fb7 100644 --- a/src/hb-ot-var.cc +++ b/src/hb-ot-var.cc @@ -24,39 +24,35 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-face.hh" #include "hb-ot-var-avar-table.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-mvar-table.hh" #include "hb-ot-var.h" + +/** + * SECTION:hb-ot-var + * @title: hb-ot-var + * @short_description: OpenType Font Variations + * @include: hb-ot.h + * + * Functions for fetching information about OpenType Variable Fonts. + **/ + + /* * fvar/avar */ -static inline const OT::fvar& -_get_fvar (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::fvar); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->fvar.get ()); -} -static inline const OT::avar& -_get_avar (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::avar); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->avar.get ()); -} /** * hb_ot_var_has_data: * @face: #hb_face_t to test * * This function allows to verify the presence of OpenType variation data on the face. - * Alternatively, use hb_ot_var_get_axis_count(). * * Return value: true if face has a `fvar' table and false otherwise * @@ -65,7 +61,7 @@ _get_avar (hb_face_t *face) hb_bool_t hb_ot_var_has_data (hb_face_t *face) { - return &_get_fvar (face) != &Null(OT::fvar); + return face->table.fvar->has_data (); } /** @@ -76,14 +72,14 @@ hb_ot_var_has_data (hb_face_t *face) unsigned int hb_ot_var_get_axis_count (hb_face_t *face) { - const OT::fvar &fvar = _get_fvar (face); - return fvar.get_axis_count (); + return face->table.fvar->get_axis_count (); } /** * hb_ot_var_get_axes: * * Since: 1.4.2 + * Deprecated: 2.2.0 **/ unsigned int hb_ot_var_get_axes (hb_face_t *face, @@ -91,14 +87,14 @@ hb_ot_var_get_axes (hb_face_t *face, unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */) { - const OT::fvar &fvar = _get_fvar (face); - return fvar.get_axis_infos (start_offset, axes_count, axes_array); + return face->table.fvar->get_axes_deprecated (start_offset, axes_count, axes_array); } /** * hb_ot_var_find_axis: * * Since: 1.4.2 + * Deprecated: 2.2.0 **/ hb_bool_t hb_ot_var_find_axis (hb_face_t *face, @@ -106,8 +102,68 @@ hb_ot_var_find_axis (hb_face_t *face, unsigned int *axis_index, hb_ot_var_axis_t *axis_info) { - const OT::fvar &fvar = _get_fvar (face); - return fvar.find_axis (axis_tag, axis_index, axis_info); + return face->table.fvar->find_axis_deprecated (axis_tag, axis_index, axis_info); +} + +/** + * hb_ot_var_get_axis_infos: + * + * Since: 2.2.0 + **/ +HB_EXTERN unsigned int +hb_ot_var_get_axis_infos (hb_face_t *face, + unsigned int start_offset, + unsigned int *axes_count /* IN/OUT */, + hb_ot_var_axis_info_t *axes_array /* OUT */) +{ + return face->table.fvar->get_axis_infos (start_offset, axes_count, axes_array); +} + +/** + * hb_ot_var_find_axis_info: + * + * Since: 2.2.0 + **/ +HB_EXTERN hb_bool_t +hb_ot_var_find_axis_info (hb_face_t *face, + hb_tag_t axis_tag, + hb_ot_var_axis_info_t *axis_info) +{ + return face->table.fvar->find_axis_info (axis_tag, axis_info); +} + + +/* + * Named instances. + */ + +unsigned int +hb_ot_var_get_named_instance_count (hb_face_t *face) +{ + return face->table.fvar->get_instance_count (); +} + +hb_ot_name_id_t +hb_ot_var_named_instance_get_subfamily_name_id (hb_face_t *face, + unsigned int instance_index) +{ + return face->table.fvar->get_instance_subfamily_name_id (instance_index); +} + +hb_ot_name_id_t +hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face, + unsigned int instance_index) +{ + return face->table.fvar->get_instance_postscript_name_id (instance_index); +} + +unsigned int +hb_ot_var_named_instance_get_design_coords (hb_face_t *face, + unsigned int instance_index, + unsigned int *coords_length, /* IN/OUT */ + float *coords /* OUT */) +{ + return face->table.fvar->get_instance_coords (instance_index, coords_length, coords); } @@ -126,17 +182,16 @@ hb_ot_var_normalize_variations (hb_face_t *face, for (unsigned int i = 0; i < coords_length; i++) coords[i] = 0; - const OT::fvar &fvar = _get_fvar (face); + const OT::fvar &fvar = *face->table.fvar; for (unsigned int i = 0; i < variations_length; i++) { - unsigned int axis_index; - if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, nullptr) && - axis_index < coords_length) - coords[axis_index] = fvar.normalize_axis_value (axis_index, variations[i].value); + hb_ot_var_axis_info_t info; + if (hb_ot_var_find_axis_info (face, variations[i].tag, &info) && + info.axis_index < coords_length) + coords[info.axis_index] = fvar.normalize_axis_value (info.axis_index, variations[i].value); } - const OT::avar &avar = _get_avar (face); - avar.map_coords (coords, coords_length); + face->table.avar->map_coords (coords, coords_length); } /** @@ -150,10 +205,9 @@ hb_ot_var_normalize_coords (hb_face_t *face, const float *design_coords, /* IN */ int *normalized_coords /* OUT */) { - const OT::fvar &fvar = _get_fvar (face); + const OT::fvar &fvar = *face->table.fvar; for (unsigned int i = 0; i < coords_length; i++) normalized_coords[i] = fvar.normalize_axis_value (i, design_coords[i]); - const OT::avar &avar = _get_avar (face); - avar.map_coords (normalized_coords, coords_length); + face->table.avar->map_coords (normalized_coords, coords_length); } diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h index a2c0c5f..cf6f0c9 100644 --- a/src/hb-ot-var.h +++ b/src/hb-ot-var.h @@ -47,44 +47,85 @@ HB_BEGIN_DECLS * fvar / avar */ +HB_EXTERN hb_bool_t +hb_ot_var_has_data (hb_face_t *face); + + +/* + * Variation axes. + */ + + +HB_EXTERN unsigned int +hb_ot_var_get_axis_count (hb_face_t *face); + /** - * hb_ot_var_axis_t: + * hb_ot_var_axis_flags_t: + * @HB_OT_VAR_AXIS_FLAG_HIDDEN: The axis should not be exposed directly in user interfaces. * - * Since: 1.4.2 + * Since: 2.2.0 */ -typedef struct hb_ot_var_axis_t { - hb_tag_t tag; - unsigned int name_id; - float min_value; - float default_value; - float max_value; -} hb_ot_var_axis_t; +typedef enum { /*< flags >*/ + HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u, -HB_EXTERN hb_bool_t -hb_ot_var_has_data (hb_face_t *face); + _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= 0x7FFFFFFFu /*< skip >*/ +} hb_ot_var_axis_flags_t; /** - * HB_OT_VAR_NO_AXIS_INDEX: + * hb_ot_var_axis_info_t: * - * Since: 1.4.2 + * Since: 2.2.0 */ -#define HB_OT_VAR_NO_AXIS_INDEX 0xFFFFFFFFu +typedef struct hb_ot_var_axis_info_t +{ + unsigned int axis_index; + hb_tag_t tag; + hb_ot_name_id_t name_id; + hb_ot_var_axis_flags_t flags; + float min_value; + float default_value; + float max_value; + /*< private >*/ + unsigned int reserved; +} hb_ot_var_axis_info_t; HB_EXTERN unsigned int -hb_ot_var_get_axis_count (hb_face_t *face); +hb_ot_var_get_axis_infos (hb_face_t *face, + unsigned int start_offset, + unsigned int *axes_count /* IN/OUT */, + hb_ot_var_axis_info_t *axes_array /* OUT */); + +HB_EXTERN hb_bool_t +hb_ot_var_find_axis_info (hb_face_t *face, + hb_tag_t axis_tag, + hb_ot_var_axis_info_t *axis_info); + + +/* + * Named instances. + */ HB_EXTERN unsigned int -hb_ot_var_get_axes (hb_face_t *face, - unsigned int start_offset, - unsigned int *axes_count /* IN/OUT */, - hb_ot_var_axis_t *axes_array /* OUT */); +hb_ot_var_get_named_instance_count (hb_face_t *face); -HB_EXTERN hb_bool_t -hb_ot_var_find_axis (hb_face_t *face, - hb_tag_t axis_tag, - unsigned int *axis_index, - hb_ot_var_axis_t *axis_info); +HB_EXTERN hb_ot_name_id_t +hb_ot_var_named_instance_get_subfamily_name_id (hb_face_t *face, + unsigned int instance_index); +HB_EXTERN hb_ot_name_id_t +hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face, + unsigned int instance_index); + +HB_EXTERN unsigned int +hb_ot_var_named_instance_get_design_coords (hb_face_t *face, + unsigned int instance_index, + unsigned int *coords_length, /* IN/OUT */ + float *coords /* OUT */); + + +/* + * Conversions. + */ HB_EXTERN void hb_ot_var_normalize_variations (hb_face_t *face, diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh new file mode 100644 index 0000000..0202fcc --- /dev/null +++ b/src/hb-ot-vorg-table.hh @@ -0,0 +1,181 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_VORG_TABLE_HH +#define HB_OT_VORG_TABLE_HH + +#include "hb-open-type.hh" + +/* + * VORG -- Vertical Origin Table + * https://docs.microsoft.com/en-us/typography/opentype/spec/vorg + */ +#define HB_OT_TAG_VORG HB_TAG('V','O','R','G') + +namespace OT { + +struct VertOriginMetric +{ + int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + GlyphID glyph; + FWORD vertOriginY; + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct VORG +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG; + + bool has_data () const { return version.to_int (); } + + int get_y_origin (hb_codepoint_t glyph) const + { + unsigned int i; + if (!vertYOrigins.bfind (glyph, &i)) + return defaultVertOriginY; + return vertYOrigins[i].vertOriginY; + } + + bool _subset (const hb_subset_plan_t *plan HB_UNUSED, + const VORG *vorg_table, + const hb_vector_t<VertOriginMetric> &subset_metrics, + unsigned int dest_sz, + void *dest) const + { + hb_serialize_context_t c (dest, dest_sz); + + VORG *subset_table = c.start_serialize<VORG> (); + if (unlikely (!c.extend_min (*subset_table))) + return false; + + subset_table->version.major.set (1); + subset_table->version.minor.set (0); + + subset_table->defaultVertOriginY.set (vorg_table->defaultVertOriginY); + subset_table->vertYOrigins.len.set (subset_metrics.length); + + bool success = true; + if (subset_metrics.length > 0) + { + unsigned int size = VertOriginMetric::static_size * subset_metrics.length; + VertOriginMetric *metrics = c.allocate_size<VertOriginMetric> (size); + if (likely (metrics != nullptr)) + memcpy (metrics, &subset_metrics[0], size); + else + success = false; + } + c.end_serialize (); + + return success; + } + + bool subset (hb_subset_plan_t *plan) const + { + hb_blob_t *vorg_blob = hb_sanitize_context_t().reference_table<VORG> (plan->source); + const VORG *vorg_table = vorg_blob->as<VORG> (); + + /* count the number of glyphs to be included in the subset table */ + hb_vector_t<VertOriginMetric> subset_metrics; + subset_metrics.init (); + unsigned int glyph = 0; + unsigned int i = 0; + while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len)) + { + if (plan->glyphs[glyph] > vertYOrigins[i].glyph) + i++; + else if (plan->glyphs[glyph] < vertYOrigins[i].glyph) + glyph++; + else + { + VertOriginMetric *metrics = subset_metrics.push (); + metrics->glyph.set (glyph); + metrics->vertOriginY.set (vertYOrigins[i].vertOriginY); + glyph++; + i++; + } + } + + /* alloc the new table */ + unsigned int dest_sz = VORG::min_size + VertOriginMetric::static_size * subset_metrics.length; + void *dest = (void *) malloc (dest_sz); + if (unlikely (!dest)) + { + subset_metrics.fini (); + hb_blob_destroy (vorg_blob); + return false; + } + + /* serialize the new table */ + if (!_subset (plan, vorg_table, subset_metrics, dest_sz, dest)) + { + subset_metrics.fini (); + free (dest); + hb_blob_destroy (vorg_blob); + return false; + } + + hb_blob_t *result = hb_blob_create ((const char *)dest, + dest_sz, + HB_MEMORY_MODE_READONLY, + dest, + free); + bool success = plan->add_table (HB_OT_TAG_VORG, result); + hb_blob_destroy (result); + subset_metrics.fini (); + hb_blob_destroy (vorg_blob); + return success; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + version.major == 1 && + vertYOrigins.sanitize (c)); + } + + protected: + FixedVersion<> version; /* Version of VORG table. Set to 0x00010000u. */ + FWORD defaultVertOriginY; /* The default vertical origin. */ + SortedArrayOf<VertOriginMetric> + vertYOrigins; /* The array of vertical origins. */ + + public: + DEFINE_SIZE_ARRAY(8, vertYOrigins); +}; +} /* namespace OT */ + +#endif /* HB_OT_VORG_TABLE_HH */ diff --git a/src/hb-ot.h b/src/hb-ot.h index 2120a3e..db78469 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -30,10 +30,12 @@ #include "hb.h" +#include "hb-ot-color.h" +#include "hb-ot-deprecated.h" #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" -#include "hb-ot-tag.h" +#include "hb-ot-name.h" #include "hb-ot-shape.h" #include "hb-ot-var.h" diff --git a/src/hb-private.hh b/src/hb-private.hh deleted file mode 100644 index 32e3354..0000000 --- a/src/hb-private.hh +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * Copyright © 2007,2008,2009 Red Hat, Inc. - * 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. - * - * Red Hat Author(s): Behdad Esfahbod - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_PRIVATE_HH -#define HB_PRIVATE_HH - -#define _GNU_SOURCE 1 - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "hb.h" -#define HB_H_IN -#ifdef HAVE_OT -#include "hb-ot.h" -#define HB_OT_H_IN -#endif - -#include <math.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdarg.h> - -#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) -#include <intrin.h> -#endif - -#define HB_PASTE1(a,b) a##b -#define HB_PASTE(a,b) HB_PASTE1(a,b) - -/* Compile-time custom allocator support. */ - -#if defined(hb_malloc_impl) \ - && defined(hb_calloc_impl) \ - && defined(hb_realloc_impl) \ - && defined(hb_free_impl) -extern "C" void* hb_malloc_impl(size_t size); -extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); -extern "C" void* hb_realloc_impl(void *ptr, size_t size); -extern "C" void hb_free_impl(void *ptr); -#define malloc hb_malloc_impl -#define calloc hb_calloc_impl -#define realloc hb_realloc_impl -#define free hb_free_impl -#endif - - -/* Compiler attributes */ - - -#if __cplusplus < 201103L - -#ifndef nullptr -#define nullptr NULL -#endif - -// Static assertions -#ifndef static_assert -#define static_assert(e, msg) \ - HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1] -#endif // static_assert - -#ifdef __GNUC__ -#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) -#define thread_local __thread -#endif -#else -#define thread_local -#endif - -#endif // __cplusplus < 201103L - -#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__) -#define likely(expr) (__builtin_expect (!!(expr), 1)) -#define unlikely(expr) (__builtin_expect (!!(expr), 0)) -#else -#define likely(expr) (expr) -#define unlikely(expr) (expr) -#endif - -#if !defined(__GNUC__) && !defined(__clang__) -#undef __attribute__ -#define __attribute__(x) -#endif - -#if __GNUC__ >= 3 -#define HB_PURE_FUNC __attribute__((pure)) -#define HB_CONST_FUNC __attribute__((const)) -#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) -#else -#define HB_PURE_FUNC -#define HB_CONST_FUNC -#define HB_PRINTF_FUNC(format_idx, arg_idx) -#endif -#if __GNUC__ >= 4 -#define HB_UNUSED __attribute__((unused)) -#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */ -#define HB_UNUSED __pragma(warning(suppress: 4100 4101)) -#else -#define HB_UNUSED -#endif - -#ifndef HB_INTERNAL -# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC) -# define HB_INTERNAL __attribute__((__visibility__("hidden"))) -# else -# define HB_INTERNAL -# define HB_NO_VISIBILITY 1 -# endif -#endif - -#if __GNUC__ >= 3 -#define HB_FUNC __PRETTY_FUNCTION__ -#elif defined(_MSC_VER) -#define HB_FUNC __FUNCSIG__ -#else -#define HB_FUNC __func__ -#endif - -#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140) -/* https://github.com/harfbuzz/harfbuzz/issues/630 */ -#define __restrict -#endif - -/* - * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411 - * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch - * cases that fall through without a break or return statement. HB_FALLTHROUGH - * is only needed on cases that have code: - * - * switch (foo) { - * case 1: // These cases have no code. No fallthrough annotations are needed. - * case 2: - * case 3: - * foo = 4; // This case has code, so a fallthrough annotation is needed: - * HB_FALLTHROUGH; - * default: - * return foo; - * } - */ -#if defined(__clang__) && __cplusplus >= 201103L - /* clang's fallthrough annotations are only available starting in C++11. */ -# define HB_FALLTHROUGH [[clang::fallthrough]] -#elif __GNUC__ >= 7 - /* GNU fallthrough attribute is available from GCC7 */ -# define HB_FALLTHROUGH __attribute__((fallthrough)) -#elif defined(_MSC_VER) - /* - * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): - * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx - */ -# include <sal.h> -# define HB_FALLTHROUGH __fallthrough -#else -# define HB_FALLTHROUGH /* FALLTHROUGH */ -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) - /* We need Windows Vista for both Uniscribe backend and for - * MemoryBarrier. We don't support compiling on Windows XP, - * though we run on it fine. */ -# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 -# undef _WIN32_WINNT -# endif -# ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 -# endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 -# endif -# ifndef STRICT -# define STRICT 1 -# endif - -# if defined(_WIN32_WCE) - /* Some things not defined on Windows CE. */ -# define vsnprintf _vsnprintf -# define getenv(Name) nullptr -# if _WIN32_WCE < 0x800 -# define setlocale(Category, Locale) "C" -static int errno = 0; /* Use something better? */ -# endif -# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -# define getenv(Name) nullptr -# endif -# if defined(_MSC_VER) && _MSC_VER < 1900 -# define snprintf _snprintf -# endif -#endif - -#if HAVE_ATEXIT -/* atexit() is only safe to be called from shared libraries on certain - * platforms. Whitelist. - * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */ -# if defined(__linux) && defined(__GLIBC_PREREQ) -# if __GLIBC_PREREQ(2,3) -/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */ -# define HB_USE_ATEXIT 1 -# endif -# elif defined(_MSC_VER) || defined(__MINGW32__) -/* For MSVC: - * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx - * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx - * mingw32 headers say atexit is safe to use in shared libraries. - */ -# define HB_USE_ATEXIT 1 -# elif defined(__ANDROID__) -/* This is available since Android NKD r8 or r8b: - * https://issuetracker.google.com/code/p/android/issues/detail?id=6455 - */ -# define HB_USE_ATEXIT 1 -# elif defined(__APPLE__) -/* For macOS and related platforms, the atexit man page indicates - * that it will be invoked when the library is unloaded, not only - * at application exit. - */ -# define HB_USE_ATEXIT 1 -# endif -#endif -#ifdef HB_NO_ATEXIT -# undef HB_USE_ATEXIT -#endif - -/* Basics */ - -#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; } - -static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) -{ return (a + (b - 1)) / 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 HB_STMT_START do -#define HB_STMT_END while (0) - -template <unsigned int cond> class hb_assert_constant_t; -template <> class hb_assert_constant_t<1> {}; - -#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>)) - -/* Lets assert int types. Saves trouble down the road. */ - -static_assert ((sizeof (int8_t) == 1), ""); -static_assert ((sizeof (uint8_t) == 1), ""); -static_assert ((sizeof (int16_t) == 2), ""); -static_assert ((sizeof (uint16_t) == 2), ""); -static_assert ((sizeof (int32_t) == 4), ""); -static_assert ((sizeof (uint32_t) == 4), ""); -static_assert ((sizeof (int64_t) == 8), ""); -static_assert ((sizeof (uint64_t) == 8), ""); - -static_assert ((sizeof (hb_codepoint_t) == 4), ""); -static_assert ((sizeof (hb_position_t) == 4), ""); -static_assert ((sizeof (hb_mask_t) == 4), ""); -static_assert ((sizeof (hb_var_int_t) == 4), ""); - - -/* We like our types POD */ - -#define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; } -#define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type) -#define ASSERT_TYPE_POD(_type) _ASSERT_TYPE_POD0 (__LINE__, _type) - -#ifdef __GNUC__ -# define _ASSERT_INSTANCE_POD1(_line, _instance) \ - HB_STMT_START { \ - typedef __typeof__(_instance) _type_##_line; \ - _ASSERT_TYPE_POD1 (_line, _type_##_line); \ - } HB_STMT_END -#else -# define _ASSERT_INSTANCE_POD1(_line, _instance) typedef int _assertion_on_line_##_line##_not_tested -#endif -# define _ASSERT_INSTANCE_POD0(_line, _instance) _ASSERT_INSTANCE_POD1 (_line, _instance) -# define ASSERT_INSTANCE_POD(_instance) _ASSERT_INSTANCE_POD0 (__LINE__, _instance) - -/* Check _assertion in a method environment */ -#define _ASSERT_POD1(_line) \ - HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \ - { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ } -# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line) -# define ASSERT_POD() _ASSERT_POD0 (__LINE__) - - - -/* Tiny functions */ - -/* - * Void! - */ -typedef const struct _hb_void_t *hb_void_t; -#define HB_VOID ((const _hb_void_t *) nullptr) - -/* Return the number of 1 bits in v. */ -template <typename T> -static inline HB_CONST_FUNC unsigned int -_hb_popcount (T v) -{ -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__) - if (sizeof (T) <= sizeof (unsigned int)) - return __builtin_popcount (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return __builtin_popcountl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return __builtin_popcountll (v); -#endif - - if (sizeof (T) <= 4) - { - /* "HACKMEM 169" */ - uint32_t y; - y = (v >> 1) &033333333333; - y = v - y - ((y >>1) & 033333333333); - return (((y + (y >> 3)) & 030707070707) % 077); - } - - if (sizeof (T) == 8) - { - unsigned int shift = 32; - return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift)); - } - - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift)); - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - -/* Returns the number of bits needed to store number */ -template <typename T> -static inline HB_CONST_FUNC unsigned int -_hb_bit_storage (T v) -{ - if (unlikely (!v)) return 0; - -#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) - if (sizeof (T) <= sizeof (unsigned int)) - return sizeof (unsigned int) * 8 - __builtin_clz (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return sizeof (unsigned long) * 8 - __builtin_clzl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return sizeof (unsigned long long) * 8 - __builtin_clzll (v); -#endif - -#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) - if (sizeof (T) <= sizeof (unsigned int)) - { - unsigned long where; - _BitScanReverse (&where, v); - return 1 + where; - } -# if _WIN64 - if (sizeof (T) <= 8) - { - unsigned long where; - _BitScanReverse64 (&where, v); - return 1 + where; - } -# endif -#endif - - if (sizeof (T) <= 4) - { - /* "bithacks" */ - const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; - const unsigned int S[] = {1, 2, 4, 8, 16}; - unsigned int r = 0; - for (int i = 4; i >= 0; i--) - if (v & b[i]) - { - v >>= S[i]; - r |= S[i]; - } - return r + 1; - } - if (sizeof (T) <= 8) - { - /* "bithacks" */ - const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL}; - const unsigned int S[] = {1, 2, 4, 8, 16, 32}; - unsigned int r = 0; - for (int i = 5; i >= 0; i--) - if (v & b[i]) - { - v >>= S[i]; - r |= S[i]; - } - return r + 1; - } - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift : - _hb_bit_storage<uint64_t> ((uint64_t) v); - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - -/* Returns the number of zero bits in the least significant side of v */ -template <typename T> -static inline HB_CONST_FUNC unsigned int -_hb_ctz (T v) -{ - if (unlikely (!v)) return 0; - -#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) - if (sizeof (T) <= sizeof (unsigned int)) - return __builtin_ctz (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return __builtin_ctzl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return __builtin_ctzll (v); -#endif - -#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) - if (sizeof (T) <= sizeof (unsigned int)) - { - unsigned long where; - _BitScanForward (&where, v); - return where; - } -# if _WIN64 - if (sizeof (T) <= 8) - { - unsigned long where; - _BitScanForward64 (&where, v); - return where; - } -# endif -#endif - - if (sizeof (T) <= 4) - { - /* "bithacks" */ - unsigned int c = 32; - v &= - (int32_t) v; - if (v) c--; - if (v & 0x0000FFFF) c -= 16; - if (v & 0x00FF00FF) c -= 8; - if (v & 0x0F0F0F0F) c -= 4; - if (v & 0x33333333) c -= 2; - if (v & 0x55555555) c -= 1; - return c; - } - if (sizeof (T) <= 8) - { - /* "bithacks" */ - unsigned int c = 64; - v &= - (int64_t) (v); - if (v) c--; - if (v & 0x00000000FFFFFFFFULL) c -= 32; - if (v & 0x0000FFFF0000FFFFULL) c -= 16; - if (v & 0x00FF00FF00FF00FFULL) c -= 8; - if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4; - if (v & 0x3333333333333333ULL) c -= 2; - if (v & 0x5555555555555555ULL) c -= 1; - return c; - } - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) : - _hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift; - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - -static inline bool -_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size) -{ - return (size > 0) && (count >= ((unsigned int) -1) / size); -} - -static inline unsigned int -_hb_ceil_to_4 (unsigned int v) -{ - return ((v - 1) | 3) + 1; -} - - - -/* - * - * Utility types - * - */ - -#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -/* - * Static pools - */ - -/* Global nul-content Null pool. Enlarge as necessary. */ - -#define HB_NULL_POOL_SIZE 264 -static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE."); - -#ifdef HB_NO_VISIBILITY -static -#else -extern HB_INTERNAL -#endif -void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] -#ifdef HB_NO_VISIBILITY -= {} -#endif -; -/* Generic nul-content Null objects. */ -template <typename Type> -static inline Type const & Null (void) { - static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); - return *reinterpret_cast<Type const *> (_hb_NullPool); -} -#define Null(Type) Null<Type>() - -/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ -#define DEFINE_NULL_DATA(Namespace, Type, data) \ -} /* Close namespace. */ \ -static const char _Null##Type[sizeof (Namespace::Type) + 1] = data; /* +1 is for nul-termination in data */ \ -template <> \ -/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \ - return *reinterpret_cast<const Namespace::Type *> (_Null##Type); \ -} \ -namespace Namespace { \ -/* The following line really exists such that we end in a place needing semicolon */ \ -static_assert (Namespace::Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small. Enlarge.") - - -/* Global writable pool. Enlarge as necessary. */ - -/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool - * for correct operation. It only exist to catch and divert program logic bugs instead of - * causing bad memory access. So, races there are not actually introducing incorrectness - * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */ -#ifdef HB_NO_VISIBILITY -static -#else -extern HB_INTERNAL -#endif -/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)] -#ifdef HB_NO_VISIBILITY -= {} -#endif -; -/* CRAP pool: Common Region for Access Protection. */ -template <typename Type> -static inline Type& Crap (void) { - static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); - Type *obj = reinterpret_cast<Type *> (_hb_CrapPool); - *obj = Null(Type); - return *obj; -} -#define Crap(Type) Crap<Type>() - -template <typename Type> -struct CrapOrNull { - static inline Type & get (void) { return Crap(Type); } -}; -template <typename Type> -struct CrapOrNull<const Type> { - static inline Type const & get (void) { return Null(Type); } -}; -#define CrapOrNull(Type) CrapOrNull<Type>::get () - - - -/* arrays and maps */ - - -#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr} -template <typename Type, unsigned int StaticSize=8> -struct hb_vector_t -{ - unsigned int len; - unsigned int allocated; - bool successful; - Type *arrayZ; - Type static_array[StaticSize]; - - void init (void) - { - len = 0; - allocated = ARRAY_LENGTH (static_array); - successful = true; - arrayZ = static_array; - } - - inline Type& operator [] (unsigned int i) - { - if (unlikely (i >= len)) - return Crap (Type); - return arrayZ[i]; - } - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= len)) - return Null(Type); - return arrayZ[i]; - } - - inline Type *push (void) - { - if (unlikely (!resize (len + 1))) - return &Crap(Type); - return &arrayZ[len - 1]; - } - inline Type *push (const Type& v) - { - Type *p = push (); - *p = v; - return p; - } - - /* Allocate for size but don't adjust len. */ - inline bool alloc (unsigned int size) - { - if (unlikely (!successful)) - return false; - - if (likely (size <= allocated)) - return true; - - /* Reallocate */ - - unsigned int new_allocated = allocated; - while (size >= new_allocated) - new_allocated += (new_allocated >> 1) + 8; - - Type *new_array = nullptr; - - if (arrayZ == static_array) - { - new_array = (Type *) calloc (new_allocated, sizeof (Type)); - if (new_array) - memcpy (new_array, arrayZ, len * sizeof (Type)); - } - else - { - bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type)); - if (likely (!overflows)) - new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type)); - } - - if (unlikely (!new_array)) - { - successful = false; - return false; - } - - arrayZ = new_array; - allocated = new_allocated; - - return true; - } - - inline bool resize (int size_) - { - unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; - if (!alloc (size)) - return false; - - if (size > len) - memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ)); - - len = size; - return true; - } - - inline void pop (void) - { - if (!len) return; - len--; - } - - inline void remove (unsigned int i) - { - if (unlikely (i >= len)) - return; - memmove (static_cast<void *> (&arrayZ[i]), - static_cast<void *> (&arrayZ[i + 1]), - (len - i - 1) * sizeof (Type)); - len--; - } - - inline void shrink (int size_) - { - unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; - if (size < len) - len = size; - } - - template <typename T> - inline Type *find (T v) { - for (unsigned int i = 0; i < len; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; - } - template <typename T> - inline const Type *find (T v) const { - for (unsigned int i = 0; i < len; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; - } - - inline void qsort (int (*cmp)(const void*, const void*)) - { - ::qsort (arrayZ, len, sizeof (Type), cmp); - } - - inline void qsort (void) - { - ::qsort (arrayZ, len, sizeof (Type), Type::cmp); - } - - inline void qsort (unsigned int start, unsigned int end) - { - ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp); - } - - template <typename T> - inline Type *lsearch (const T &x) - { - for (unsigned int i = 0; i < len; i++) - if (0 == this->arrayZ[i].cmp (&x)) - return &arrayZ[i]; - return nullptr; - } - - template <typename T> - inline Type *bsearch (const T &x) - { - unsigned int i; - return bfind (x, &i) ? &arrayZ[i] : nullptr; - } - template <typename T> - inline const Type *bsearch (const T &x) const - { - unsigned int i; - return bfind (x, &i) ? &arrayZ[i] : nullptr; - } - template <typename T> - inline bool bfind (const T &x, unsigned int *i) const - { - int min = 0, max = (int) this->len - 1; - while (min <= max) - { - int mid = (min + max) / 2; - int c = this->arrayZ[mid].cmp (&x); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - { - *i = mid; - return true; - } - } - if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0)) - max++; - *i = max; - return false; - } - - inline void fini (void) - { - if (arrayZ != static_array) - free (arrayZ); - arrayZ = nullptr; - allocated = len = 0; - } -}; - -template <typename Type> -struct hb_auto_t : Type -{ - hb_auto_t (void) { Type::init (); } - ~hb_auto_t (void) { Type::fini (); } - private: /* Hide */ - void init (void) {} - void fini (void) {} -}; -template <typename Type> -struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {}; - - -#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT} -template <typename item_t, typename lock_t> -struct hb_lockable_set_t -{ - hb_vector_t <item_t, 1> items; - - inline void init (void) { items.init (); } - - template <typename T> - inline item_t *replace_or_insert (T v, lock_t &l, bool replace) - { - l.lock (); - item_t *item = items.find (v); - if (item) { - if (replace) { - item_t old = *item; - *item = v; - l.unlock (); - old.fini (); - } - else { - item = nullptr; - l.unlock (); - } - } else { - item = items.push (v); - l.unlock (); - } - return item; - } - - template <typename T> - inline void remove (T v, lock_t &l) - { - l.lock (); - item_t *item = items.find (v); - if (item) { - item_t old = *item; - *item = items[items.len - 1]; - items.pop (); - l.unlock (); - old.fini (); - } else { - l.unlock (); - } - } - - template <typename T> - inline bool find (T v, item_t *i, lock_t &l) - { - l.lock (); - item_t *item = items.find (v); - if (item) - *i = *item; - l.unlock (); - return !!item; - } - - template <typename T> - inline item_t *find_or_insert (T v, lock_t &l) - { - l.lock (); - item_t *item = items.find (v); - if (!item) { - item = items.push (v); - } - l.unlock (); - return item; - } - - inline void fini (lock_t &l) - { - if (!items.len) { - /* No need for locking. */ - items.fini (); - return; - } - l.lock (); - while (items.len) { - item_t old = items[items.len - 1]; - items.pop (); - l.unlock (); - old.fini (); - l.lock (); - } - items.fini (); - l.unlock (); - } - -}; - - -/* ASCII tag/character handling */ - -static inline bool ISALPHA (unsigned char c) -{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -static inline bool ISALNUM (unsigned char c) -{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } -static inline bool ISSPACE (unsigned char c) -{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } -static inline unsigned char TOUPPER (unsigned char c) -{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } -static inline unsigned char TOLOWER (unsigned char c) -{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } - - -/* HB_NDEBUG disables some sanity checks that are very safe to disable and - * should be disabled in production systems. If NDEBUG is defined, enable - * HB_NDEBUG; but if it's desirable that normal assert()s (which are very - * light-weight) to be enabled, then HB_DEBUG can be defined to disable - * the costlier checks. */ -#ifdef NDEBUG -#define HB_NDEBUG 1 -#endif - - -/* Misc */ - -template <typename T> class hb_assert_unsigned_t; -template <> class hb_assert_unsigned_t<unsigned char> {}; -template <> class hb_assert_unsigned_t<unsigned short> {}; -template <> class hb_assert_unsigned_t<unsigned int> {}; -template <> class hb_assert_unsigned_t<unsigned long> {}; - -template <typename T> static inline bool -hb_in_range (T u, T lo, T hi) -{ - /* The sizeof() is here to force template instantiation. - * I'm sure there are better ways to do this but can't think of - * one right now. Declaring a variable won't work as HB_UNUSED - * is unusable on some platforms and unused types are less likely - * to generate a warning than unused variables. */ - static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), ""); - - /* The casts below are important as if T is smaller than int, - * the subtract results will become a signed int! */ - return (T)(u - lo) <= (T)(hi - lo); -} - -template <typename T> static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); -} - -template <typename T> static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); -} - - -/* Enable bitwise ops on enums marked as flags_t */ -/* To my surprise, looks like the function resolver is happy to silently cast - * one enum to another... So this doesn't provide the type-checking that I - * originally had in mind... :(. - * - * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163 - */ -#ifdef _MSC_VER -# pragma warning(disable:4200) -# pragma warning(disable:4800) -#endif -#define HB_MARK_AS_FLAG_T(T) \ - extern "C++" { \ - static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ - static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ - static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ - static inline T operator ~ (T r) { return T (~(unsigned int) r); } \ - static inline T& operator |= (T &l, T r) { l = l | r; return l; } \ - static inline T& operator &= (T& l, T r) { l = l & r; return l; } \ - static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ - } - - -/* Useful for set-operations on small enums. - * For example, for testing "x ∈ {x1, x2, x3}" use: - * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) - */ -#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned int)(x) < 32) + (1U << (unsigned int)(x))) -#define FLAG_UNSAFE(x) ((unsigned int)(x) < 32 ? (1U << (unsigned int)(x)) : 0) -#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x)) - - -template <typename T, typename T2> static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2) -{ - for (unsigned int i = 1; i < len; i++) - { - unsigned int j = i; - while (j && compar (&array[j - 1], &array[i]) > 0) - j--; - if (i == j) - continue; - /* Move item i to occupy place for item j, shift what's in between. */ - { - T t = array[i]; - memmove (&array[j + 1], &array[j], (i - j) * sizeof (T)); - array[j] = t; - } - if (array2) - { - T2 t = array2[i]; - memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2)); - array2[j] = t; - } - } -} - -template <typename T> static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) -{ - hb_stable_sort (array, len, compar, (int *) nullptr); -} - -static inline hb_bool_t -hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) -{ - /* Pain because we don't know whether s is nul-terminated. */ - char buf[64]; - len = MIN (ARRAY_LENGTH (buf) - 1, len); - strncpy (buf, s, len); - buf[len] = '\0'; - - char *end; - errno = 0; - unsigned long v = strtoul (buf, &end, base); - if (errno) return false; - if (*end) return false; - *out = v; - return true; -} - - -/* Vectorization */ - -struct HbOpOr -{ - static const bool passthru_left = true; - static const bool passthru_right = true; - template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; } -}; -struct HbOpAnd -{ - static const bool passthru_left = false; - static const bool passthru_right = false; - template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; } -}; -struct HbOpMinus -{ - static const bool passthru_left = true; - static const bool passthru_right = false; - template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; } -}; -struct HbOpXor -{ - static const bool passthru_left = true; - static const bool passthru_right = true; - template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; } -}; - - -/* Compiler-assisted vectorization. */ - -/* The `vector_size' attribute was introduced in gcc 3.1. */ -#if defined( __GNUC__ ) && ( __GNUC__ >= 4 ) -#define HB_VECTOR_SIZE 128 -#elif !defined(HB_VECTOR_SIZE) -#define HB_VECTOR_SIZE 0 -#endif - -/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */ -template <typename elt_t, unsigned int byte_size> -struct hb_vector_size_t -{ - elt_t& operator [] (unsigned int i) { return u.v[i]; } - const elt_t& operator [] (unsigned int i) const { return u.v[i]; } - - template <class Op> - inline hb_vector_size_t process (const hb_vector_size_t &o) const - { - hb_vector_size_t r; -#if HB_VECTOR_SIZE - if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) - for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) - Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]); - else -#endif - for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) - Op::process (r.u.v[i], u.v[i], o.u.v[i]); - return r; - } - inline hb_vector_size_t operator | (const hb_vector_size_t &o) const - { return process<HbOpOr> (o); } - inline hb_vector_size_t operator & (const hb_vector_size_t &o) const - { return process<HbOpAnd> (o); } - inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const - { return process<HbOpXor> (o); } - inline hb_vector_size_t operator ~ () const - { - hb_vector_size_t r; -#if HB_VECTOR_SIZE && 0 - if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) - for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) - r.u.vec[i] = ~u.vec[i]; - else -#endif - for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) - r.u.v[i] = ~u.v[i]; - return r; - } - - private: - static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, ""); - union { - elt_t v[byte_size / sizeof (elt_t)]; -#if HB_VECTOR_SIZE - typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8))); - vec_t vec[byte_size / sizeof (vec_t)]; -#endif - } u; -}; - - -/* Global runtime options. */ - -struct hb_options_t -{ - unsigned int initialized : 1; - unsigned int uniscribe_bug_compatible : 1; -}; - -union hb_options_union_t { - unsigned int i; - hb_options_t opts; -}; -static_assert ((sizeof (int) == sizeof (hb_options_union_t)), ""); - -HB_INTERNAL void -_hb_options_init (void); - -extern HB_INTERNAL hb_options_union_t _hb_options; - -static inline hb_options_t -hb_options (void) -{ - if (unlikely (!_hb_options.i)) - _hb_options_init (); - - return _hb_options.opts; -} - -/* Size signifying variable-sized array */ -#define VAR 1 - - -/* String type. */ - -struct hb_bytes_t -{ - inline hb_bytes_t (void) : bytes (nullptr), len (0) {} - inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {} - - inline int cmp (const hb_bytes_t &a) const - { - if (len != a.len) - return (int) a.len - (int) len; - - return memcmp (a.bytes, bytes, len); - } - static inline int cmp (const void *pa, const void *pb) - { - hb_bytes_t *a = (hb_bytes_t *) pa; - hb_bytes_t *b = (hb_bytes_t *) pb; - return b->cmp (*a); - } - - const char *bytes; - unsigned int len; -}; - - -/* fallback for round() */ -#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND) -static inline double -round (double x) -{ - if (x >= 0) - return floor (x + 0.5); - else - return ceil (x - 0.5); -} -#endif - - -#endif /* HB_PRIVATE_HH */ diff --git a/src/hb-set-digest-private.hh b/src/hb-set-digest.hh index e099a82..b97526f 100644 --- a/src/hb-set-digest-private.hh +++ b/src/hb-set-digest.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SET_DIGEST_PRIVATE_HH -#define HB_SET_DIGEST_PRIVATE_HH +#ifndef HB_SET_DIGEST_HH +#define HB_SET_DIGEST_HH -#include "hb-private.hh" +#include "hb.hh" /* * The set digests here implement various "filters" that support @@ -48,11 +48,9 @@ template <typename mask_t, unsigned int shift> struct hb_set_digest_lowest_bits_t { - ASSERT_POD (); - - static const unsigned int mask_bytes = sizeof (mask_t); - static const unsigned int mask_bits = sizeof (mask_t) * 8; - static const unsigned int num_bits = 0 + static constexpr unsigned mask_bytes = sizeof (mask_t); + static constexpr unsigned mask_bits = sizeof (mask_t) * 8; + static constexpr unsigned num_bits = 0 + (mask_bytes >= 1 ? 3 : 0) + (mask_bytes >= 2 ? 1 : 0) + (mask_bytes >= 4 ? 1 : 0) @@ -63,15 +61,12 @@ struct hb_set_digest_lowest_bits_t static_assert ((shift < sizeof (hb_codepoint_t) * 8), ""); static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), ""); - inline void init (void) { - mask = 0; - } + void init () { mask = 0; } - inline void add (hb_codepoint_t g) { - mask |= mask_for (g); - } + void add (hb_codepoint_t g) { mask |= mask_for (g); } - inline bool add_range (hb_codepoint_t a, hb_codepoint_t b) { + bool add_range (hb_codepoint_t a, hb_codepoint_t b) + { if ((b >> shift) - (a >> shift) >= mask_bits - 1) mask = (mask_t) -1; else { @@ -83,7 +78,7 @@ struct hb_set_digest_lowest_bits_t } template <typename T> - inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { for (unsigned int i = 0; i < count; i++) { @@ -92,7 +87,7 @@ struct hb_set_digest_lowest_bits_t } } template <typename T> - inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { for (unsigned int i = 0; i < count; i++) { @@ -102,53 +97,53 @@ struct hb_set_digest_lowest_bits_t return true; } - inline bool may_have (hb_codepoint_t g) const { - return !!(mask & mask_for (g)); - } + bool may_have (hb_codepoint_t g) const + { return !!(mask & mask_for (g)); } private: - static inline mask_t mask_for (hb_codepoint_t g) { - return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); - } + static mask_t mask_for (hb_codepoint_t g) + { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); } mask_t mask; }; template <typename head_t, typename tail_t> struct hb_set_digest_combiner_t { - ASSERT_POD (); - - inline void init (void) { + void init () + { head.init (); tail.init (); } - inline void add (hb_codepoint_t g) { + void add (hb_codepoint_t g) + { head.add (g); tail.add (g); } - inline bool add_range (hb_codepoint_t a, hb_codepoint_t b) { + bool add_range (hb_codepoint_t a, hb_codepoint_t b) + { head.add_range (a, b); tail.add_range (a, b); return true; } template <typename T> - inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { head.add_array (array, count, stride); tail.add_array (array, count, stride); } template <typename T> - inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { head.add_sorted_array (array, count, stride); tail.add_sorted_array (array, count, stride); return true; } - inline bool may_have (hb_codepoint_t g) const { + bool may_have (hb_codepoint_t g) const + { return head.may_have (g) && tail.may_have (g); } @@ -176,4 +171,4 @@ typedef hb_set_digest_combiner_t > hb_set_digest_t; -#endif /* HB_SET_DIGEST_PRIVATE_HH */ +#endif /* HB_SET_DIGEST_HH */ diff --git a/src/hb-set.cc b/src/hb-set.cc index 25027e6..0682362 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -24,10 +24,19 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-set-private.hh" +#include "hb-set.hh" -/* Public API */ +/** + * SECTION:hb-set + * @title: hb-set + * @short_description: Object representing a set of integers + * @include: hb.h + * + * Set objects represent a mathematical set of integer values. They are + * used in non-shaping API to query certain set of characters or glyphs, + * or other integer values. + **/ /** @@ -38,7 +47,7 @@ * Since: 0.9.2 **/ hb_set_t * -hb_set_create (void) +hb_set_create () { hb_set_t *set; @@ -58,7 +67,7 @@ hb_set_create (void) * Since: 0.9.2 **/ hb_set_t * -hb_set_get_empty (void) +hb_set_get_empty () { return const_cast<hb_set_t *> (&Null(hb_set_t)); } @@ -391,7 +400,7 @@ hb_set_symmetric_difference (hb_set_t *set, * Deprecated: 1.6.1 **/ void -hb_set_invert (hb_set_t *set) +hb_set_invert (hb_set_t *set HB_UNUSED) { } diff --git a/src/hb-set-private.hh b/src/hb-set.hh index ccd4d8d..64a1363 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set.hh @@ -24,11 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SET_PRIVATE_HH -#define HB_SET_PRIVATE_HH +#ifndef HB_SET_HH +#define HB_SET_HH -#include "hb-private.hh" -#include "hb-object-private.hh" +#include "hb.hh" /* @@ -40,9 +39,13 @@ struct hb_set_t { + HB_NO_COPY_ASSIGN (hb_set_t); + hb_set_t () { init (); } + ~hb_set_t () { fini (); } + struct page_map_t { - inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; } + int cmp (const page_map_t &o) const { return (int) o.major - (int) major; } uint32_t major; uint32_t index; @@ -50,13 +53,13 @@ struct hb_set_t struct page_t { - inline void init0 (void) { memset (&v, 0, sizeof (v)); } - inline void init1 (void) { memset (&v, 0xff, sizeof (v)); } + void init0 () { v.clear (); } + void init1 () { v.clear (0xFF); } - inline unsigned int len (void) const + unsigned int len () const { return ARRAY_LENGTH_CONST (v); } - inline bool is_empty (void) const + bool is_empty () const { for (unsigned int i = 0; i < len (); i++) if (v[i]) @@ -64,11 +67,11 @@ struct hb_set_t return true; } - inline void add (hb_codepoint_t g) { elt (g) |= mask (g); } - inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } - inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); } + void add (hb_codepoint_t g) { elt (g) |= mask (g); } + void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } + bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); } - inline void add_range (hb_codepoint_t a, hb_codepoint_t b) + void add_range (hb_codepoint_t a, hb_codepoint_t b) { elt_t *la = &elt (a); elt_t *lb = &elt (b); @@ -85,20 +88,20 @@ struct hb_set_t } } - inline bool is_equal (const page_t *other) const + bool is_equal (const page_t *other) const { - return 0 == memcmp (&v, &other->v, sizeof (v)); + return 0 == hb_memcmp (&v, &other->v, sizeof (v)); } - inline unsigned int get_population (void) const + unsigned int get_population () const { unsigned int pop = 0; for (unsigned int i = 0; i < len (); i++) - pop += _hb_popcount (v[i]); + pop += hb_popcount (v[i]); return pop; } - inline bool next (hb_codepoint_t *codepoint) const + bool next (hb_codepoint_t *codepoint) const { unsigned int m = (*codepoint + 1) & MASK; if (!m) @@ -120,7 +123,7 @@ struct hb_set_t *codepoint = INVALID; return false; } - inline bool previous (hb_codepoint_t *codepoint) const + bool previous (hb_codepoint_t *codepoint) const { unsigned int m = (*codepoint - 1) & MASK; if (m == MASK) @@ -142,14 +145,14 @@ struct hb_set_t *codepoint = INVALID; return false; } - inline hb_codepoint_t get_min (void) const + hb_codepoint_t get_min () const { for (unsigned int i = 0; i < len (); i++) if (v[i]) return i * ELT_BITS + elt_get_min (v[i]); return INVALID; } - inline hb_codepoint_t get_max (void) const + hb_codepoint_t get_max () const { for (int i = len () - 1; i >= 0; i--) if (v[i]) @@ -158,19 +161,19 @@ struct hb_set_t } typedef unsigned long long elt_t; - static const unsigned int PAGE_BITS = 512; + static constexpr unsigned PAGE_BITS = 512; static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); - static inline unsigned int elt_get_min (const elt_t &elt) { return _hb_ctz (elt); } - static inline unsigned int elt_get_max (const elt_t &elt) { return _hb_bit_storage (elt) - 1; } + static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } + static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; } typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t; - static const unsigned int ELT_BITS = sizeof (elt_t) * 8; - static const unsigned int ELT_MASK = ELT_BITS - 1; - static const unsigned int BITS = sizeof (vector_t) * 8; - static const unsigned int MASK = BITS - 1; - static_assert (PAGE_BITS == BITS, ""); + static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8; + static constexpr unsigned ELT_MASK = ELT_BITS - 1; + static constexpr unsigned BITS = sizeof (vector_t) * 8; + static constexpr unsigned MASK = BITS - 1; + static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, ""); elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; } elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; } @@ -183,63 +186,68 @@ struct hb_set_t hb_object_header_t header; bool successful; /* Allocations successful */ mutable unsigned int population; - hb_vector_t<page_map_t, 1> page_map; - hb_vector_t<page_t, 1> pages; + hb_vector_t<page_map_t> page_map; + hb_vector_t<page_t> pages; - inline void init_shallow (void) + void init_shallow () { successful = true; population = 0; page_map.init (); pages.init (); } - inline void init (void) + void init () { hb_object_init (this); init_shallow (); } - inline void fini_shallow (void) + void fini_shallow () { + population = 0; page_map.fini (); pages.fini (); } - inline void fini (void) + void fini () { hb_object_fini (this); fini_shallow (); } - inline bool resize (unsigned int count) + bool in_error () const { return !successful; } + + bool resize (unsigned int count) { if (unlikely (!successful)) return false; if (!pages.resize (count) || !page_map.resize (count)) { - pages.resize (page_map.len); + pages.resize (page_map.length); successful = false; return false; } return true; } - inline void clear (void) { - if (unlikely (hb_object_is_inert (this))) + void clear () + { + if (unlikely (hb_object_is_immutable (this))) return; successful = true; population = 0; page_map.resize (0); pages.resize (0); } - inline bool is_empty (void) const { - unsigned int count = pages.len; + bool is_empty () const + { + unsigned int count = pages.length; for (unsigned int i = 0; i < count; i++) if (!pages[i].is_empty ()) return false; return true; } - inline void dirty (void) { population = (unsigned int) -1; } + void dirty () { population = (unsigned int) -1; } - inline void add (hb_codepoint_t g) + void add (hb_codepoint_t g) { if (unlikely (!successful)) return; if (unlikely (g == INVALID)) return; @@ -247,7 +255,7 @@ struct hb_set_t page_t *page = page_for_insert (g); if (unlikely (!page)) return; page->add (g); } - inline bool add_range (hb_codepoint_t a, hb_codepoint_t b) + bool add_range (hb_codepoint_t a, hb_codepoint_t b) { if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ if (unlikely (a > b || a == INVALID || b == INVALID)) return false; @@ -277,7 +285,7 @@ struct hb_set_t } template <typename T> - inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { if (unlikely (!successful)) return; if (!count) return; @@ -303,7 +311,7 @@ struct hb_set_t /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename T> - inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) + bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ if (!count) return true; @@ -331,17 +339,17 @@ struct hb_set_t return true; } - inline void del (hb_codepoint_t g) + void del (hb_codepoint_t g) { /* TODO perform op even if !successful. */ if (unlikely (!successful)) return; - page_t *p = page_for (g); - if (!p) + page_t *page = page_for (g); + if (!page) return; dirty (); - p->del (g); + page->del (g); } - inline void del_range (hb_codepoint_t a, hb_codepoint_t b) + void del_range (hb_codepoint_t a, hb_codepoint_t b) { /* TODO perform op even if !successful. */ /* TODO Optimize, like add_range(). */ @@ -349,37 +357,37 @@ struct hb_set_t for (unsigned int i = a; i < b + 1; i++) del (i); } - inline bool has (hb_codepoint_t g) const + bool has (hb_codepoint_t g) const { - const page_t *p = page_for (g); - if (!p) + const page_t *page = page_for (g); + if (!page) return false; - return p->has (g); + return page->has (g); } - inline bool intersects (hb_codepoint_t first, + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { hb_codepoint_t c = first - 1; return next (&c) && c <= last; } - inline void set (const hb_set_t *other) + void set (const hb_set_t *other) { if (unlikely (!successful)) return; - unsigned int count = other->pages.len; + unsigned int count = other->pages.length; if (!resize (count)) return; population = other->population; - memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0])); - memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0])); + memcpy ((void *) pages, (const void *) other->pages, count * pages.item_size); + memcpy ((void *) page_map, (const void *) other->page_map, count * page_map.item_size); } - inline bool is_equal (const hb_set_t *other) const + bool is_equal (const hb_set_t *other) const { if (get_population () != other->get_population ()) return false; - unsigned int na = pages.len; - unsigned int nb = other->pages.len; + unsigned int na = pages.length; + unsigned int nb = other->pages.length; unsigned int a = 0, b = 0; for (; a < na && b < nb; ) @@ -400,11 +408,12 @@ struct hb_set_t return true; } - inline bool is_subset (const hb_set_t *larger_set) const + bool is_subset (const hb_set_t *larger_set) const { if (get_population () > larger_set->get_population ()) return false; + /* TODO Optimize to use pages. */ hb_codepoint_t c = INVALID; while (next (&c)) if (!larger_set->has (c)) @@ -414,14 +423,14 @@ struct hb_set_t } template <class Op> - inline void process (const hb_set_t *other) + void process (const hb_set_t *other) { if (unlikely (!successful)) return; dirty (); - unsigned int na = pages.len; - unsigned int nb = other->pages.len; + unsigned int na = pages.length; + unsigned int nb = other->pages.length; unsigned int next_page = na; unsigned int count = 0, newCount = 0; @@ -452,7 +461,7 @@ struct hb_set_t if (Op::passthru_right) count += nb - b; - if (count > pages.len) + if (count > pages.length) if (!resize (count)) return; newCount = count; @@ -508,27 +517,27 @@ struct hb_set_t page_at (count).v = other->page_at (b).v; } assert (!count); - if (pages.len > newCount) + if (pages.length > newCount) resize (newCount); } - inline void union_ (const hb_set_t *other) + void union_ (const hb_set_t *other) { process<HbOpOr> (other); } - inline void intersect (const hb_set_t *other) + void intersect (const hb_set_t *other) { process<HbOpAnd> (other); } - inline void subtract (const hb_set_t *other) + void subtract (const hb_set_t *other) { process<HbOpMinus> (other); } - inline void symmetric_difference (const hb_set_t *other) + void symmetric_difference (const hb_set_t *other) { process<HbOpXor> (other); } - inline bool next (hb_codepoint_t *codepoint) const + bool next (hb_codepoint_t *codepoint) const { if (unlikely (*codepoint == INVALID)) { *codepoint = get_min (); @@ -537,8 +546,8 @@ struct hb_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; - page_map.bfind (map, &i); - if (i < page_map.len && page_map[i].major == map.major) + page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST); + if (i < page_map.length && page_map[i].major == map.major) { if (pages[page_map[i].index].next (codepoint)) { @@ -547,7 +556,7 @@ struct hb_set_t } i++; } - for (; i < page_map.len; i++) + for (; i < page_map.length; i++) { hb_codepoint_t m = pages[page_map[i].index].get_min (); if (m != INVALID) @@ -559,7 +568,7 @@ struct hb_set_t *codepoint = INVALID; return false; } - inline bool previous (hb_codepoint_t *codepoint) const + bool previous (hb_codepoint_t *codepoint) const { if (unlikely (*codepoint == INVALID)) { *codepoint = get_max (); @@ -568,8 +577,8 @@ struct hb_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; - page_map.bfind (map, &i); - if (i < page_map.len && page_map[i].major == map.major) + page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST); + if (i < page_map.length && page_map[i].major == map.major) { if (pages[page_map[i].index].previous (codepoint)) { @@ -590,7 +599,7 @@ struct hb_set_t *codepoint = INVALID; return false; } - inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const + bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const { hb_codepoint_t i; @@ -608,7 +617,7 @@ struct hb_set_t return true; } - inline bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const + bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const { hb_codepoint_t i; @@ -627,54 +636,83 @@ struct hb_set_t return true; } - inline unsigned int get_population (void) const + unsigned int get_population () const { if (population != (unsigned int) -1) return population; unsigned int pop = 0; - unsigned int count = pages.len; + unsigned int count = pages.length; for (unsigned int i = 0; i < count; i++) pop += pages[i].get_population (); population = pop; return pop; } - inline hb_codepoint_t get_min (void) const + hb_codepoint_t get_min () const { - unsigned int count = pages.len; + unsigned int count = pages.length; for (unsigned int i = 0; i < count; i++) if (!page_at (i).is_empty ()) return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min (); return INVALID; } - inline hb_codepoint_t get_max (void) const + hb_codepoint_t get_max () const { - unsigned int count = pages.len; + unsigned int count = pages.length; for (int i = count - 1; i >= 0; i++) if (!page_at (i).is_empty ()) - return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max (); + return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max (); return INVALID; } - static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; + static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; + + /* + * Iterator implementation. + */ + struct const_iter_t : hb_sorted_iter_t<const_iter_t, const hb_codepoint_t> + { + const_iter_t (const hb_set_t &s_) : + s (s_), v (INVALID), l (s.get_population () + 1) { __next__ (); } + + typedef hb_codepoint_t __item_type__; + hb_codepoint_t __item__ () const { return v; } + bool __more__ () const { return v != INVALID; } + void __next__ () { s.next (&v); if (l) l--; } + void __prev__ () { s.previous (&v); } + unsigned __len__ () { return l; } + + protected: + const hb_set_t &s; + hb_codepoint_t v; + unsigned l; + }; + const_iter_t const_iter () const { return const_iter_t (*this); } + operator const_iter_t () const { return const_iter (); } + typedef const_iter_t iter_t; + iter_t iter () const { return const_iter (); } + + protected: - inline page_t *page_for_insert (hb_codepoint_t g) + page_t *page_for_insert (hb_codepoint_t g) { - page_map_t map = {get_major (g), pages.len}; + page_map_t map = {get_major (g), pages.length}; unsigned int i; - if (!page_map.bfind (map, &i)) + if (!page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST)) { - if (!resize (pages.len + 1)) + if (!resize (pages.length + 1)) return nullptr; pages[map.index].init0 (); - memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0])); + memmove (page_map + i + 1, + page_map + i, + (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } return &pages[page_map[i].index]; } - inline page_t *page_for (hb_codepoint_t g) + page_t *page_for (hb_codepoint_t g) { page_map_t key = {get_major (g)}; const page_map_t *found = page_map.bsearch (key); @@ -682,7 +720,7 @@ struct hb_set_t return &pages[found->index]; return nullptr; } - inline const page_t *page_for (hb_codepoint_t g) const + const page_t *page_for (hb_codepoint_t g) const { page_map_t key = {get_major (g)}; const page_map_t *found = page_map.bsearch (key); @@ -690,11 +728,11 @@ struct hb_set_t return &pages[found->index]; return nullptr; } - inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } - inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } - inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; } - inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; } + page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } + const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } + unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; } + hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; } }; -#endif /* HB_SET_PRIVATE_HH */ +#endif /* HB_SET_HH */ diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 6eeba2b..61ea8d0 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -24,64 +24,132 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-debug.hh" -#include "hb-shape-plan-private.hh" -#include "hb-shaper-private.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" - - -static void -hb_shape_plan_plan (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords, - const char * const *shaper_list) +#include "hb.hh" +#include "hb-shape-plan.hh" +#include "hb-shaper.hh" +#include "hb-font.hh" +#include "hb-buffer.hh" + + +/** + * SECTION:hb-shape-plan + * @title: hb-shape-plan + * @short_description: Object representing a shaping plan + * @include: hb.h + * + * Shape plans are not used for shaping directly, but can be access to query + * certain information about how shaping will perform given a set of input + * parameters (script, language, direction, features, etc.) + * Most client would not need to deal with shape plans directly. + **/ + + +/* + * hb_shape_plan_key_t + */ + +bool +hb_shape_plan_key_t::init (bool copy, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords, + const char * const *shaper_list) { - DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, - "num_features=%d num_coords=%d shaper_list=%p", - num_user_features, - num_coords, - shaper_list); + hb_feature_t *features = nullptr; + if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t)))) + goto bail; + + this->props = *props; + this->num_user_features = num_user_features; + this->user_features = copy ? features : user_features; + if (copy && num_user_features) + { + memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); + /* Make start/end uniform to easier catch bugs. */ + for (unsigned int i = 0; i < num_user_features; i++) + { + if (features[0].start != HB_FEATURE_GLOBAL_START) + features[0].start = 1; + if (features[0].end != HB_FEATURE_GLOBAL_END) + features[0].end = 2; + } + } + this->shaper_func = nullptr; + this->shaper_name = nullptr; + this->ot.init (face, coords, num_coords); - const hb_shaper_pair_t *shapers = _hb_shapers_get (); + /* + * Choose shaper. + */ #define HB_SHAPER_PLAN(shaper) \ HB_STMT_START { \ - if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \ - HB_SHAPER_DATA (shaper, shape_plan) = \ - HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \ - user_features, num_user_features, \ - coords, num_coords); \ - shape_plan->shaper_func = _hb_##shaper##_shape; \ - shape_plan->shaper_name = #shaper; \ - return; \ + if (face->data.shaper) \ + { \ + this->shaper_func = _hb_##shaper##_shape; \ + this->shaper_name = #shaper; \ + return true; \ } \ } HB_STMT_END - if (likely (!shaper_list)) { - for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) - if (0) + if (unlikely (shaper_list)) + { + for (; *shaper_list; shaper_list++) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ - else if (shapers[i].func == _hb_##shaper##_shape) \ + else if (0 == strcmp (*shaper_list, #shaper)) \ HB_SHAPER_PLAN (shaper); #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT - } else { - for (; *shaper_list; shaper_list++) - if (0) + } + else + { + const hb_shaper_entry_t *shapers = _hb_shapers_get (); + for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ - else if (0 == strcmp (*shaper_list, #shaper)) \ + else if (shapers[i].func == _hb_##shaper##_shape) \ HB_SHAPER_PLAN (shaper); #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT } - #undef HB_SHAPER_PLAN + +bail: + ::free (features); + return false; +} + +bool +hb_shape_plan_key_t::user_features_match (const hb_shape_plan_key_t *other) +{ + if (this->num_user_features != other->num_user_features) + return false; + for (unsigned int i = 0; i < num_user_features; i++) + { + if (this->user_features[i].tag != other->user_features[i].tag || + this->user_features[i].value != other->user_features[i].value || + (this->user_features[i].start == HB_FEATURE_GLOBAL_START && + this->user_features[i].end == HB_FEATURE_GLOBAL_END) != + (other->user_features[i].start == HB_FEATURE_GLOBAL_START && + other->user_features[i].end == HB_FEATURE_GLOBAL_END)) + return false; + } + return true; +} + +bool +hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other) +{ + return hb_segment_properties_equal (&this->props, &other->props) && + this->user_features_match (other) && + this->ot.equal (&other->ot) && + this->shaper_func == other->shaper_func; } @@ -89,6 +157,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan, * hb_shape_plan_t */ + /** * hb_shape_plan_create: (Xconstructor) * @face: @@ -121,7 +190,7 @@ hb_shape_plan_create2 (hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, - const int *orig_coords, + const int *coords, unsigned int num_coords, const char * const *shaper_list) { @@ -132,49 +201,40 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list); + assert (props->direction != HB_DIRECTION_INVALID); + hb_shape_plan_t *shape_plan; - hb_feature_t *features = nullptr; - int *coords = nullptr; - if (unlikely (!face)) - face = hb_face_get_empty (); if (unlikely (!props)) - return hb_shape_plan_get_empty (); - if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t)))) - return hb_shape_plan_get_empty (); - if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int)))) - { - free (features); - return hb_shape_plan_get_empty (); - } + goto bail; if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) - { - free (coords); - free (features); - return hb_shape_plan_get_empty (); - } - - assert (props->direction != HB_DIRECTION_INVALID); + goto bail; + if (unlikely (!face)) + face = hb_face_get_empty (); hb_face_make_immutable (face); - shape_plan->default_shaper_list = !shaper_list; shape_plan->face_unsafe = face; - shape_plan->props = *props; - shape_plan->num_user_features = num_user_features; - shape_plan->user_features = features; - if (num_user_features) - memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); - shape_plan->num_coords = num_coords; - shape_plan->coords = coords; - if (num_coords) - memcpy (coords, orig_coords, num_coords * sizeof (int)); - hb_shape_plan_plan (shape_plan, - user_features, num_user_features, - coords, num_coords, - shaper_list); + if (unlikely (!shape_plan->key.init (true, + face, + props, + user_features, + num_user_features, + coords, + num_coords, + shaper_list))) + goto bail2; + if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key))) + goto bail3; return shape_plan; + +bail3: + shape_plan->key.free (); +bail2: + free (shape_plan); +bail: + return hb_shape_plan_get_empty (); } /** @@ -187,32 +247,9 @@ hb_shape_plan_create2 (hb_face_t *face, * Since: 0.9.7 **/ hb_shape_plan_t * -hb_shape_plan_get_empty (void) +hb_shape_plan_get_empty () { - static const hb_shape_plan_t _hb_shape_plan_nil = { - HB_OBJECT_HEADER_STATIC, - - true, /* default_shaper_list */ - nullptr, /* face */ - HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ - - nullptr, /* shaper_func */ - nullptr, /* shaper_name */ - - nullptr, /* user_features */ - 0, /* num_user_featurs */ - - nullptr, /* coords */ - 0, /* num_coords */ - - { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - } - }; - - return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); + return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t)); } /** @@ -244,13 +281,8 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) { if (!hb_object_destroy (shape_plan)) return; -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - - free (shape_plan->user_features); - free (shape_plan->coords); - + shape_plan->ot.fini (); + shape_plan->key.free (); free (shape_plan); } @@ -296,6 +328,22 @@ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, return hb_object_get_user_data (shape_plan, key); } +/** + * hb_shape_plan_get_shaper: + * @shape_plan: a shape plan. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.7 + **/ +const char * +hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) +{ + return shape_plan->key.shaper_name; +} + /** * hb_shape_plan_execute: @@ -321,32 +369,31 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "num_features=%d shaper_func=%p, shaper_name=%s", num_features, - shape_plan->shaper_func, - shape_plan->shaper_name); + shape_plan->key.shaper_func, + shape_plan->key.shaper_name); if (unlikely (!buffer->len)) return true; - assert (!hb_object_is_inert (buffer)); + assert (!hb_object_is_immutable (buffer)); assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); if (unlikely (hb_object_is_inert (shape_plan))) return false; assert (shape_plan->face_unsafe == font->face); - assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); + assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props)); #define HB_SHAPER_EXECUTE(shaper) \ HB_STMT_START { \ - return HB_SHAPER_DATA (shaper, shape_plan) && \ - hb_##shaper##_shaper_font_data_ensure (font) && \ + return font->data.shaper && \ _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \ } HB_STMT_END - if (0) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ - else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ + else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \ HB_SHAPER_EXECUTE (shaper); #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT @@ -358,91 +405,8 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, /* - * caching - */ - -#if 0 -static unsigned int -hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) -{ - return hb_segment_properties_hash (&shape_plan->props) + - shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func; -} -#endif - -/* User-feature caching is currently somewhat dumb: - * it only finds matches where the feature array is identical, - * not cases where the feature lists would be compatible for plan purposes - * but have different ranges, for example. + * Caching */ -struct hb_shape_plan_proposal_t -{ - const hb_segment_properties_t props; - const char * const *shaper_list; - const hb_feature_t *user_features; - unsigned int num_user_features; - const int *coords; - unsigned int num_coords; - hb_shape_func_t *shaper_func; -}; - -static inline hb_bool_t -hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) -{ - if (proposal->num_user_features != shape_plan->num_user_features) - return false; - for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++) - if (proposal->user_features[i].tag != shape_plan->user_features[i].tag || - proposal->user_features[i].value != shape_plan->user_features[i].value || - proposal->user_features[i].start != shape_plan->user_features[i].start || - proposal->user_features[i].end != shape_plan->user_features[i].end) - return false; - return true; -} - -static inline hb_bool_t -hb_shape_plan_coords_match (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) -{ - if (proposal->num_coords != shape_plan->num_coords) - return false; - for (unsigned int i = 0, n = proposal->num_coords; i < n; i++) - if (proposal->coords[i] != shape_plan->coords[i]) - return false; - return true; -} - -static hb_bool_t -hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) -{ - return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && - hb_shape_plan_user_features_match (shape_plan, proposal) && - hb_shape_plan_coords_match (shape_plan, proposal) && - ((shape_plan->default_shaper_list && !proposal->shaper_list) || - (shape_plan->shaper_func == proposal->shaper_func)); -} - -static inline hb_bool_t -hb_non_global_user_features_present (const hb_feature_t *user_features, - unsigned int num_user_features) -{ - while (num_user_features) { - if (user_features->start != 0 || user_features->end != (unsigned int) -1) - return true; - num_user_features--; - user_features++; - } - return false; -} - -static inline hb_bool_t -hb_coords_present (const int *coords, - unsigned int num_coords) -{ - return num_coords != 0; -} /** * hb_shape_plan_create_cached: @@ -486,62 +450,38 @@ hb_shape_plan_create_cached2 (hb_face_t *face, num_user_features, shaper_list); - hb_shape_plan_proposal_t proposal = { - *props, - shaper_list, - user_features, - num_user_features, - nullptr - }; - - if (shaper_list) { - /* Choose shaper. Adapted from hb_shape_plan_plan(). - * Must choose shaper exactly the same way as that function. */ - for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) - if (0) - ; -#define HB_SHAPER_IMPLEMENT(shaper) \ - else if (0 == strcmp (*shaper_item, #shaper) && \ - hb_##shaper##_shaper_face_data_ensure (face)) \ - { \ - proposal.shaper_func = _hb_##shaper##_shape; \ - break; \ - } -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - - if (unlikely (!proposal.shaper_func)) - return hb_shape_plan_get_empty (); - } +retry: + hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; + bool dont_cache = hb_object_is_inert (face); -retry: - hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans); + if (likely (!dont_cache)) + { + hb_shape_plan_key_t key; + if (!key.init (false, + face, + props, + user_features, + num_user_features, + coords, + num_coords, + shaper_list)) + return hb_shape_plan_get_empty (); - /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */ - if (!hb_coords_present (coords, num_coords)) for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) - if (hb_shape_plan_matches (node->shape_plan, &proposal)) + if (node->shape_plan->key.equal (&key)) { DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); return hb_shape_plan_reference (node->shape_plan); } + } - /* Not found. */ hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props, user_features, num_user_features, coords, num_coords, shaper_list); - /* Don't add to the cache if face is inert. */ - if (unlikely (hb_object_is_inert (face))) - return shape_plan; - - /* Don't add the plan to the cache if there were user features with non-global ranges */ - if (hb_non_global_user_features_present (user_features, num_user_features)) - return shape_plan; - /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */ - if (hb_coords_present (coords, num_coords)) + if (unlikely (dont_cache)) return shape_plan; hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); @@ -551,7 +491,8 @@ retry: node->shape_plan = shape_plan; node->next = cached_plan_nodes; - if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { + if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node))) + { hb_shape_plan_destroy (shape_plan); free (node); goto retry; @@ -560,19 +501,3 @@ retry: return hb_shape_plan_reference (shape_plan); } - -/** - * hb_shape_plan_get_shaper: - * @shape_plan: a shape plan. - * - * - * - * Return value: (transfer none): - * - * Since: 0.9.7 - **/ -const char * -hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) -{ - return shape_plan->shaper_name; -} diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan.hh index aa0413a..3a057fd 100644 --- a/src/hb-shape-plan-private.hh +++ b/src/hb-shape-plan.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Google, Inc. + * Copyright © 2012,2018 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,44 +24,49 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SHAPE_PLAN_PRIVATE_HH -#define HB_SHAPE_PLAN_PRIVATE_HH +#ifndef HB_SHAPE_PLAN_HH +#define HB_SHAPE_PLAN_HH -#include "hb-private.hh" -#include "hb-object-private.hh" -#include "hb-shaper-private.hh" +#include "hb.hh" +#include "hb-shaper.hh" +#include "hb-ot-shape.hh" -struct hb_shape_plan_t +struct hb_shape_plan_key_t { - hb_object_header_t header; - ASSERT_POD (); + hb_segment_properties_t props; - hb_bool_t default_shaper_list; - hb_face_t *face_unsafe; /* We don't carry a reference to face. */ - hb_segment_properties_t props; + const hb_feature_t *user_features; + unsigned int num_user_features; + + hb_ot_shape_plan_key_t ot; + + hb_shape_func_t *shaper_func; + const char *shaper_name; - hb_shape_func_t *shaper_func; - const char *shaper_name; + HB_INTERNAL inline bool init (bool copy, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords, + const char * const *shaper_list); - hb_feature_t *user_features; - unsigned int num_user_features; + HB_INTERNAL inline void free () { ::free ((void *) user_features); } - int *coords; - unsigned int num_coords; + HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other); - struct hb_shaper_data_t shaper_data; + HB_INTERNAL bool equal (const hb_shape_plan_key_t *other); }; -#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \ - , const hb_feature_t *user_features \ - , unsigned int num_user_features \ - , const int *coords \ - , unsigned int num_coords -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT -#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS +struct hb_shape_plan_t +{ + hb_object_header_t header; + hb_face_t *face_unsafe; /* We don't carry a reference to face. */ + hb_shape_plan_key_t key; + hb_ot_shape_plan_t ot; +}; -#endif /* HB_SHAPE_PLAN_PRIVATE_HH */ +#endif /* HB_SHAPE_PLAN_HH */ diff --git a/src/hb-shape.cc b/src/hb-shape.cc index c1e7365..deff77b 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -26,40 +26,70 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" + +#include "hb-shaper.hh" +#include "hb-shape-plan.hh" +#include "hb-buffer.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" -#include "hb-buffer-private.hh" -#include "hb-font-private.hh" /** * SECTION:hb-shape - * @title: Shaping + * @title: hb-shape * @short_description: Conversion of text strings into positioned glyphs * @include: hb.h * * Shaping is the central operation of HarfBuzz. Shaping operates on buffers, * which are sequences of Unicode characters that use the same font and have - * the same text direction, script and language. After shaping the buffer + * the same text direction, script, and language. After shaping the buffer * contains the output glyphs and their positions. **/ -static const char **static_shaper_list; -#ifdef HB_USE_ATEXIT -static -void free_static_shaper_list (void) +#if HB_USE_ATEXIT +static void free_static_shaper_list (); +#endif + +static const char *nil_shaper_list[] = {nullptr}; + +static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *, + hb_shaper_list_lazy_loader_t> { -retry: - const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); - if (!hb_atomic_ptr_cmpexch (&static_shaper_list, shaper_list, nullptr)) - goto retry; + static const char ** create () + { + const char **shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *)); + if (unlikely (!shaper_list)) + return nullptr; + + const hb_shaper_entry_t *shapers = _hb_shapers_get (); + unsigned int i; + for (i = 0; i < HB_SHAPERS_COUNT; i++) + shaper_list[i] = shapers[i].name; + shaper_list[i] = nullptr; + +#if HB_USE_ATEXIT + atexit (free_static_shaper_list); +#endif + + return shaper_list; + } + static void destroy (const char **l) + { free (l); } + static const char ** get_null () + { return nil_shaper_list; } +} static_shaper_list; - free (shaper_list); +#if HB_USE_ATEXIT +static +void free_static_shaper_list () +{ + static_shaper_list.free_instance (); } #endif + /** * hb_shape_list_shapers: * @@ -71,37 +101,9 @@ retry: * Since: 0.9.2 **/ const char ** -hb_shape_list_shapers (void) +hb_shape_list_shapers () { -retry: - const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); - - if (unlikely (!shaper_list)) - { - /* Not found; allocate one. */ - shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *)); - if (unlikely (!shaper_list)) { - static const char *nil_shaper_list[] = {nullptr}; - return nil_shaper_list; - } - - const hb_shaper_pair_t *shapers = _hb_shapers_get (); - unsigned int i; - for (i = 0; i < HB_SHAPERS_COUNT; i++) - shaper_list[i] = shapers[i].name; - shaper_list[i] = nullptr; - - if (!hb_atomic_ptr_cmpexch (&static_shaper_list, nullptr, shaper_list)) { - free (shaper_list); - goto retry; - } - -#ifdef HB_USE_ATEXIT - atexit (free_static_shaper_list); /* First person registers atexit() callback. */ -#endif - } - - return shaper_list; + return static_shaper_list.get_unconst (); } diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl.hh index 7844081..b674fce 100644 --- a/src/hb-shaper-impl-private.hh +++ b/src/hb-shaper-impl.hh @@ -24,20 +24,15 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SHAPER_IMPL_PRIVATE_HH -#define HB_SHAPER_IMPL_PRIVATE_HH +#ifndef HB_SHAPER_IMPL_HH +#define HB_SHAPER_IMPL_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" +#include "hb-shaper.hh" +#include "hb-face.hh" +#include "hb-font.hh" +#include "hb-shape-plan.hh" +#include "hb-buffer.hh" - -#ifdef HB_SHAPER -#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object) -#endif - - -#endif /* HB_SHAPER_IMPL_PRIVATE_HH */ +#endif /* HB_SHAPER_IMPL_HH */ diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh index b0835d3..36d8fc7 100644 --- a/src/hb-shaper-list.hh +++ b/src/hb-shaper-list.hh @@ -34,14 +34,8 @@ /* Only picks up fonts that have a "Silf" table. */ HB_SHAPER_IMPLEMENT (graphite2) #endif -#ifdef HAVE_CORETEXT -/* Only picks up fonts that have a "mort" or "morx" table. */ -HB_SHAPER_IMPLEMENT (coretext_aat) -#endif -#ifdef HAVE_OT HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ -#endif #ifdef HAVE_UNISCRIBE HB_SHAPER_IMPLEMENT (uniscribe) @@ -51,6 +45,10 @@ HB_SHAPER_IMPLEMENT (directwrite) #endif #ifdef HAVE_CORETEXT HB_SHAPER_IMPLEMENT (coretext) + +/* Only picks up fonts that have a "mort" or "morx" table. + Probably going to be removed https://github.com/harfbuzz/harfbuzz/issues/1478 */ +HB_SHAPER_IMPLEMENT (coretext_aat) #endif #ifdef HAVE_FALLBACK diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh deleted file mode 100644 index ce2d9f2..0000000 --- a/src/hb-shaper-private.hh +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright © 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): Behdad Esfahbod - */ - -#ifndef HB_SHAPER_PRIVATE_HH -#define HB_SHAPER_PRIVATE_HH - -#include "hb-private.hh" - -typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan, - hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features); - -#define HB_SHAPER_IMPLEMENT(name) \ - extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape; -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - -struct hb_shaper_pair_t { - char name[16]; - hb_shape_func_t *func; -}; - -HB_INTERNAL const hb_shaper_pair_t * -_hb_shapers_get (void); - - -/* For embedding in face / font / ... */ -struct hb_shaper_data_t { -#define HB_SHAPER_IMPLEMENT(shaper) void *shaper; -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT -}; - -#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *)) - -/* Means: succeeded, but don't need to keep any data. */ -#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1) - -/* Means: tried but failed to create. */ -#define HB_SHAPER_DATA_INVALID ((void *) -1) -#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID) - -#define HB_SHAPER_DATA_TYPE_NAME(shaper, object) hb_##shaper##_shaper_##object##_data_t -#define HB_SHAPER_DATA_TYPE(shaper, object) struct HB_SHAPER_DATA_TYPE_NAME(shaper, object) -#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper) -#define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE(shaper, object, object) -#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_create -#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_destroy -#define HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) hb_##shaper##_shaper_##object##_data_ensure - -#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \ - HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \ - extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \ - HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \ - extern "C" HB_INTERNAL void \ - HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data); \ - extern "C" HB_INTERNAL bool \ - HB_SHAPER_DATA_ENSURE_FUNC (shaper, object) (hb_##object##_t *object) - -#define HB_SHAPER_DATA_DESTROY(shaper, object) \ - if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \ - if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \ - HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); - -#define HB_SHAPER_DATA_ENSURE_DEFINE(shaper, object) \ - HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, true) - -#define HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, condition) \ -bool \ -HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \ -{\ - retry: \ - HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \ - if (likely (data) && !(condition)) { \ - /* Drop and recreate. */ \ - /* If someone dropped it in the mean time, throw it away and don't touch it. \ - * Otherwise, destruct it. */ \ - if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, nullptr)) { \ - HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \ - } \ - goto retry; \ - } \ - if (unlikely (!data)) { \ - data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \ - if (unlikely (!data)) \ - data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \ - if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), nullptr, data)) { \ - if (data && \ - data != HB_SHAPER_DATA_INVALID && \ - data != HB_SHAPER_DATA_SUCCEEDED) \ - HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \ - goto retry; \ - } \ - } \ - return data != nullptr && !HB_SHAPER_DATA_IS_INVALID (data); \ -} - - -#endif /* HB_SHAPER_PRIVATE_HH */ diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc index d44d8c9..575ab1f 100644 --- a/src/hb-shaper.cc +++ b/src/hb-shaper.cc @@ -24,63 +24,41 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-shaper-private.hh" -#include "hb-atomic-private.hh" +#include "hb.hh" +#include "hb-shaper.hh" +#include "hb-machinery.hh" -static const hb_shaper_pair_t all_shapers[] = { +static const hb_shaper_entry_t all_shapers[] = { #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}, #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT }; - -/* Thread-safe, lock-free, shapers */ - -static const hb_shaper_pair_t *static_shapers; - -#ifdef HB_USE_ATEXIT -static -void free_static_shapers (void) -{ -retry: - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); - if (!hb_atomic_ptr_cmpexch (&static_shapers, shapers, nullptr)) - goto retry; - - if (unlikely (shapers != all_shapers)) - free ((void *) shapers); -} +#if HB_USE_ATEXIT +static void free_static_shapers (); #endif -const hb_shaper_pair_t * -_hb_shapers_get (void) +static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_t, + hb_shapers_lazy_loader_t> { -retry: - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); - - if (unlikely (!shapers)) + static hb_shaper_entry_t *create () { char *env = getenv ("HB_SHAPER_LIST"); - if (!env || !*env) { - (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); - return (const hb_shaper_pair_t *) all_shapers; - } + if (!env || !*env) + return nullptr; - /* Not found; allocate one. */ - shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers)); - if (unlikely (!shapers)) { - (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); - return (const hb_shaper_pair_t *) all_shapers; - } + hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) calloc (1, sizeof (all_shapers)); + if (unlikely (!shapers)) + return nullptr; memcpy (shapers, all_shapers, sizeof (all_shapers)); /* Reorder shaper list to prefer requested shapers. */ unsigned int i = 0; char *end, *p = env; - for (;;) { + for (;;) + { end = strchr (p, ','); if (!end) end = p + strlen (p); @@ -90,7 +68,7 @@ retry: 0 == strncmp (shapers[j].name, p, end - p)) { /* Reorder this shaper to position i */ - struct hb_shaper_pair_t t = shapers[j]; + struct hb_shaper_entry_t t = shapers[j]; memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i)); shapers[i] = t; i++; @@ -102,15 +80,26 @@ retry: p = end + 1; } - if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) { - free (shapers); - goto retry; - } - -#ifdef HB_USE_ATEXIT - atexit (free_static_shapers); /* First person registers atexit() callback. */ +#if HB_USE_ATEXIT + atexit (free_static_shapers); #endif + + return shapers; } + static void destroy (const hb_shaper_entry_t *p) { free ((void *) p); } + static const hb_shaper_entry_t *get_null () { return all_shapers; } +} static_shapers; - return shapers; +#if HB_USE_ATEXIT +static +void free_static_shapers () +{ + static_shapers.free_instance (); +} +#endif + +const hb_shaper_entry_t * +_hb_shapers_get () +{ + return static_shapers.get_unconst (); } diff --git a/src/hb-shaper.hh b/src/hb-shaper.hh new file mode 100644 index 0000000..79dc5d0 --- /dev/null +++ b/src/hb-shaper.hh @@ -0,0 +1,134 @@ +/* + * Copyright © 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): Behdad Esfahbod + */ + +#ifndef HB_SHAPER_HH +#define HB_SHAPER_HH + +#include "hb.hh" +#include "hb-machinery.hh" + +typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); + +#define HB_SHAPER_IMPLEMENT(name) \ + extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape; +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + +struct hb_shaper_entry_t { + char name[16]; + hb_shape_func_t *func; +}; + +HB_INTERNAL const hb_shaper_entry_t * +_hb_shapers_get (); + + +template <typename Data, unsigned int WheresData, typename T> +struct hb_shaper_lazy_loader_t; + +#define HB_SHAPER_ORDER(Shaper) \ + HB_PASTE (HB_SHAPER_ORDER_, Shaper) +enum hb_shaper_order_t +{ + _HB_SHAPER_ORDER_ORDER_ZERO, +#define HB_SHAPER_IMPLEMENT(Shaper) \ + HB_SHAPER_ORDER (Shaper), +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + _HB_SHAPERS_COUNT_PLUS_ONE, + HB_SHAPERS_COUNT = _HB_SHAPERS_COUNT_PLUS_ONE - 1, +}; + +template <enum hb_shaper_order_t order, typename Object> struct hb_shaper_object_data_type_t; + +#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1) +#define HB_SHAPER_DATA_TYPE(shaper, object) hb_##shaper##_##object##_data_t +#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_create +#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_destroy + +#define HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, object) \ + \ + struct HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \ + extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \ + HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object); \ + extern "C" HB_INTERNAL void \ + HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *shaper##_##object); \ + \ + template <> \ + struct hb_shaper_object_data_type_t<HB_SHAPER_ORDER (shaper), hb_##object##_t> \ + { \ + typedef HB_SHAPER_DATA_TYPE(shaper, object) value; \ + }; \ + \ + template <unsigned int WheresData> \ + struct hb_shaper_lazy_loader_t<hb_##object##_t, WheresData, HB_SHAPER_DATA_TYPE(shaper, object)> \ + : hb_lazy_loader_t<HB_SHAPER_DATA_TYPE(shaper, object), \ + hb_shaper_lazy_loader_t<hb_##object##_t, \ + WheresData, \ + HB_SHAPER_DATA_TYPE(shaper, object)>, \ + hb_##object##_t, WheresData> \ + { \ + typedef HB_SHAPER_DATA_TYPE(shaper, object) Type; \ + static Type* create (hb_##object##_t *data) \ + { return HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (data); } \ + static Type *get_null () { return nullptr; } \ + static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \ + }; \ + \ + static_assert (true, "") /* Require semicolon. */ + + +template <typename Object> +struct hb_shaper_object_dataset_t +{ + void init0 (Object *parent_data) + { + this->parent_data = parent_data; +#define HB_SHAPER_IMPLEMENT(shaper) shaper.init0 (); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + } + void fini () + { +#define HB_SHAPER_IMPLEMENT(shaper) shaper.fini (); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + } + + Object *parent_data; /* MUST be JUST before the lazy loaders. */ +#define HB_SHAPER_IMPLEMENT(shaper) \ + hb_shaper_lazy_loader_t<Object, HB_SHAPER_ORDER(shaper), \ + typename hb_shaper_object_data_type_t<HB_SHAPER_ORDER(shaper), Object>::value \ + > shaper; +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT +}; + +#endif /* HB_SHAPER_HH */ diff --git a/src/hb-static.cc b/src/hb-static.cc index e26e5c8..4c51588 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -24,9 +24,52 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" + +#include "hb-open-type.hh" +#include "hb-face.hh" + +#include "hb-aat-layout-common.hh" +#include "hb-aat-layout-feat-table.hh" +#include "hb-ot-layout-common.hh" +#include "hb-ot-cmap-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-maxp-table.hh" #ifndef HB_NO_VISIBILITY -void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {}; -/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {}; + +hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; +/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; + +DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF}; +DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00}; +DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00}; +DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; +DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF}; +/* Hand-coded because Lookup is a template. Sad. */ +const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; + + +unsigned int +hb_face_t::load_num_glyphs () const +{ + hb_sanitize_context_t c = hb_sanitize_context_t (); + c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */ + hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this); + const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> (); + + unsigned int ret = maxp_table->get_num_glyphs (); + num_glyphs.set_relaxed (ret); + hb_blob_destroy (maxp_blob); + return ret; +} + +unsigned int +hb_face_t::load_upem () const +{ + unsigned int ret = table.head->get_upem (); + upem.set_relaxed (ret); + return ret; +} + #endif diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh index 679841c..c4cf666 100644 --- a/src/hb-string-array.hh +++ b/src/hb-string-array.hh @@ -29,7 +29,7 @@ #define HB_STRING_ARRAY_HH #endif -#include "hb-private.hh" +#include "hb.hh" /* Based on Bruno Haible's code in Appendix B of Ulrich Drepper's dsohowto.pdf: * https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf */ diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc new file mode 100644 index 0000000..3e617d5 --- /dev/null +++ b/src/hb-subset-cff-common.cc @@ -0,0 +1,226 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-ot-cff-common.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-subset-cff-common.hh" + +/* Disable FDSelect format 0 for compatibility with fonttools which doesn't seem choose it. + * Rarely any/much smaller than format 3 anyway. */ +#define CFF_SERIALIZE_FDSELECT_0 0 + +using namespace CFF; + +/** + * hb_plan_subset_cff_fdselect + * Determine an optimal FDSelect format according to a provided plan. + * + * Return value: FDSelect format, size, and ranges for the most compact subset FDSelect + * along with a font index remapping table + **/ + +bool +hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs, + unsigned int fdCount, + const FDSelect &src, /* IN */ + unsigned int &subset_fd_count /* OUT */, + unsigned int &subset_fdselect_size /* OUT */, + unsigned int &subset_fdselect_format /* OUT */, + hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */, + remap_t &fdmap /* OUT */) +{ + subset_fd_count = 0; + subset_fdselect_size = 0; + subset_fdselect_format = 0; + unsigned int num_ranges = 0; + + unsigned int subset_num_glyphs = glyphs.length; + if (subset_num_glyphs == 0) + return true; + + { + /* use hb_set to determine the subset of font dicts */ + hb_set_t *set = hb_set_create (); + if (set == &Null (hb_set_t)) + return false; + hb_codepoint_t prev_fd = CFF_UNDEF_CODE; + for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) + { + hb_codepoint_t fd = src.get_fd (glyphs[i]); + set->add (fd); + + if (fd != prev_fd) + { + num_ranges++; + prev_fd = fd; + code_pair_t pair = { fd, i }; + fdselect_ranges.push (pair); + } + } + + subset_fd_count = set->get_population (); + if (subset_fd_count == fdCount) + { + /* all font dicts belong to the subset. no need to subset FDSelect & FDArray */ + fdmap.identity (fdCount); + hb_set_destroy (set); + } + else + { + /* create a fdmap */ + if (!fdmap.reset (fdCount)) + { + hb_set_destroy (set); + return false; + } + + hb_codepoint_t fd = CFF_UNDEF_CODE; + while (set->next (&fd)) + fdmap.add (fd); + hb_set_destroy (set); + if (unlikely (fdmap.get_count () != subset_fd_count)) + return false; + } + + /* update each font dict index stored as "code" in fdselect_ranges */ + for (unsigned int i = 0; i < fdselect_ranges.length; i++) + fdselect_ranges[i].code = fdmap[fdselect_ranges[i].code]; + } + + /* determine which FDSelect format is most compact */ + if (subset_fd_count > 0xFF) + { + if (unlikely (src.format != 4)) + return false; + subset_fdselect_format = 4; + subset_fdselect_size = FDSelect::min_size + FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges + HBUINT32::static_size; + } + else + { +#if CFF_SERIALIZE_FDSELECT_0 + unsigned int format0_size = FDSelect::min_size + FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs; +#endif + unsigned int format3_size = FDSelect::min_size + FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges + HBUINT16::static_size; + +#if CFF_SERIALIZE_FDSELECT_0 + if (format0_size <= format3_size) + { + // subset_fdselect_format = 0; + subset_fdselect_size = format0_size; + } + else +#endif + { + subset_fdselect_format = 3; + subset_fdselect_size = format3_size; + } + } + + return true; +} + +template <typename FDSELECT3_4> +static inline bool +serialize_fdselect_3_4 (hb_serialize_context_t *c, + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int size, + const hb_vector_t<code_pair_t> &fdselect_ranges) +{ + TRACE_SERIALIZE (this); + FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size); + if (unlikely (p == nullptr)) return_trace (false); + p->nRanges ().set (fdselect_ranges.length); + for (unsigned int i = 0; i < fdselect_ranges.length; i++) + { + p->ranges[i].first.set (fdselect_ranges[i].glyph); + p->ranges[i].fd.set (fdselect_ranges[i].code); + } + p->sentinel().set (num_glyphs); + return_trace (true); +} + +/** + * hb_serialize_cff_fdselect + * Serialize a subset FDSelect format planned above. + **/ +bool +hb_serialize_cff_fdselect (hb_serialize_context_t *c, + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int fd_count, + unsigned int fdselect_format, + unsigned int size, + const hb_vector_t<code_pair_t> &fdselect_ranges) +{ + TRACE_SERIALIZE (this); + FDSelect *p = c->allocate_min<FDSelect> (); + if (unlikely (p == nullptr)) return_trace (false); + p->format.set (fdselect_format); + size -= FDSelect::min_size; + + switch (fdselect_format) + { +#if CFF_SERIALIZE_FDSELECT_0 + case 0: + { + FDSelect0 *p = c->allocate_size<FDSelect0> (size); + if (unlikely (p == nullptr)) return_trace (false); + unsigned int range_index = 0; + unsigned int fd = fdselect_ranges[range_index++].code; + for (unsigned int i = 0; i < num_glyphs; i++) + { + if ((range_index < fdselect_ranges.len) && + (i >= fdselect_ranges[range_index].glyph)) + { + fd = fdselect_ranges[range_index++].code; + } + p->fds[i].set (fd); + } + break; + } +#endif /* CFF_SERIALIZE_FDSELECT_0 */ + + case 3: + return serialize_fdselect_3_4<FDSelect3> (c, + num_glyphs, + src, + size, + fdselect_ranges); + + case 4: + return serialize_fdselect_3_4<FDSelect4> (c, + num_glyphs, + src, + size, + fdselect_ranges); + + default: + assert(false); + } + + return_trace (true); +} diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh new file mode 100644 index 0000000..915b4c4 --- /dev/null +++ b/src/hb-subset-cff-common.hh @@ -0,0 +1,990 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_SUBSET_CFF_COMMON_HH +#define HB_SUBSET_CFF_COMMON_HH + +#include "hb.hh" + +#include "hb-subset-plan.hh" +#include "hb-cff-interp-cs-common.hh" + +namespace CFF { + +/* Used for writing a temporary charstring */ +struct str_encoder_t +{ + str_encoder_t (str_buff_t &buff_) + : buff (buff_), error (false) {} + + void reset () { buff.resize (0); } + + void encode_byte (unsigned char b) + { + if (unlikely (buff.push (b) == &Crap(unsigned char))) + set_error (); + } + + void encode_int (int v) + { + if ((-1131 <= v) && (v <= 1131)) + { + if ((-107 <= v) && (v <= 107)) + encode_byte (v + 139); + else if (v > 0) + { + v -= 108; + encode_byte ((v >> 8) + OpCode_TwoBytePosInt0); + encode_byte (v & 0xFF); + } + else + { + v = -v - 108; + encode_byte ((v >> 8) + OpCode_TwoByteNegInt0); + encode_byte (v & 0xFF); + } + } + else + { + if (unlikely (v < -32768)) + v = -32768; + else if (unlikely (v > 32767)) + v = 32767; + encode_byte (OpCode_shortint); + encode_byte ((v >> 8) & 0xFF); + encode_byte (v & 0xFF); + } + } + + void encode_num (const number_t& n) + { + if (n.in_int_range ()) + { + encode_int (n.to_int ()); + } + else + { + int32_t v = n.to_fixed (); + encode_byte (OpCode_fixedcs); + encode_byte ((v >> 24) & 0xFF); + encode_byte ((v >> 16) & 0xFF); + encode_byte ((v >> 8) & 0xFF); + encode_byte (v & 0xFF); + } + } + + void encode_op (op_code_t op) + { + if (Is_OpCode_ESC (op)) + { + encode_byte (OpCode_escape); + encode_byte (Unmake_OpCode_ESC (op)); + } + else + encode_byte (op); + } + + void copy_str (const byte_str_t &str) + { + unsigned int offset = buff.length; + buff.resize (offset + str.length); + if (unlikely (buff.length < offset + str.length)) + { + set_error (); + return; + } + memcpy (&buff[offset], &str[0], str.length); + } + + bool is_error () const { return error; } + + protected: + void set_error () { error = true; } + + str_buff_t &buff; + bool error; +}; + +struct cff_sub_table_offsets_t { + cff_sub_table_offsets_t () : privateDictsOffset (0) + { + topDictInfo.init (); + FDSelectInfo.init (); + FDArrayInfo.init (); + charStringsInfo.init (); + globalSubrsInfo.init (); + localSubrsInfos.init (); + } + + ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); } + + table_info_t topDictInfo; + table_info_t FDSelectInfo; + table_info_t FDArrayInfo; + table_info_t charStringsInfo; + unsigned int privateDictsOffset; + table_info_t globalSubrsInfo; + hb_vector_t<table_info_t> localSubrsInfos; +}; + +template <typename OPSTR=op_str_t> +struct cff_top_dict_op_serializer_t : op_serializer_t +{ + bool serialize (hb_serialize_context_t *c, + const OPSTR &opstr, + const cff_sub_table_offsets_t &offsets) const + { + TRACE_SERIALIZE (this); + + switch (opstr.op) + { + case OpCode_CharStrings: + return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset)); + + case OpCode_FDArray: + return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset)); + + case OpCode_FDSelect: + return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset)); + + default: + return_trace (copy_opstr (c, opstr)); + } + return_trace (true); + } + + unsigned int calculate_serialized_size (const OPSTR &opstr) const + { + switch (opstr.op) + { + case OpCode_CharStrings: + case OpCode_FDArray: + case OpCode_FDSelect: + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); + + default: + return opstr.str.length; + } + } +}; + +struct cff_font_dict_op_serializer_t : op_serializer_t +{ + bool serialize (hb_serialize_context_t *c, + const op_str_t &opstr, + const table_info_t &privateDictInfo) const + { + TRACE_SERIALIZE (this); + + if (opstr.op == OpCode_Private) + { + /* serialize the private dict size & offset as 2-byte & 4-byte integers */ + if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) || + !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) + return_trace (false); + + /* serialize the opcode */ + HBUINT8 *p = c->allocate_size<HBUINT8> (1); + if (unlikely (p == nullptr)) return_trace (false); + p->set (OpCode_Private); + + return_trace (true); + } + else + { + HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length); + if (unlikely (d == nullptr)) return_trace (false); + memcpy (d, &opstr.str[0], opstr.str.length); + } + return_trace (true); + } + + unsigned int calculate_serialized_size (const op_str_t &opstr) const + { + if (opstr.op == OpCode_Private) + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); + else + return opstr.str.length; + } +}; + +struct cff_private_dict_op_serializer_t : op_serializer_t +{ + cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_) + : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {} + + bool serialize (hb_serialize_context_t *c, + const op_str_t &opstr, + const unsigned int subrsOffset) const + { + TRACE_SERIALIZE (this); + + if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) + return true; + if (opstr.op == OpCode_Subrs) + { + if (desubroutinize || (subrsOffset == 0)) + return_trace (true); + else + return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset)); + } + else + return_trace (copy_opstr (c, opstr)); + } + + unsigned int calculate_serialized_size (const op_str_t &opstr, + bool has_localsubr=true) const + { + if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) + return 0; + if (opstr.op == OpCode_Subrs) + { + if (desubroutinize || !has_localsubr) + return 0; + else + return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op); + } + else + return opstr.str.length; + } + + protected: + const bool desubroutinize; + const bool drop_hints; +}; + +struct flatten_param_t +{ + str_buff_t &flatStr; + bool drop_hints; +}; + +template <typename ACC, typename ENV, typename OPSET> +struct subr_flattener_t +{ + subr_flattener_t (const ACC &acc_, + const hb_vector_t<hb_codepoint_t> &glyphs_, + bool drop_hints_) : acc (acc_), glyphs (glyphs_), + drop_hints (drop_hints_) {} + + bool flatten (str_buff_vec_t &flat_charstrings) + { + if (!flat_charstrings.resize (glyphs.length)) + return false; + for (unsigned int i = 0; i < glyphs.length; i++) + flat_charstrings[i].init (); + for (unsigned int i = 0; i < glyphs.length; i++) + { + hb_codepoint_t glyph = glyphs[i]; + const byte_str_t str = (*acc.charStrings)[glyph]; + unsigned int fd = acc.fdSelect->get_fd (glyph); + if (unlikely (fd >= acc.fdCount)) + return false; + cs_interpreter_t<ENV, OPSET, flatten_param_t> interp; + interp.env.init (str, acc, fd); + flatten_param_t param = { flat_charstrings[i], drop_hints }; + if (unlikely (!interp.interpret (param))) + return false; + } + return true; + } + + const ACC &acc; + const hb_vector_t<hb_codepoint_t> &glyphs; + bool drop_hints; +}; + +struct subr_closures_t +{ + subr_closures_t () : valid (false), global_closure (nullptr) + { local_closures.init (); } + + void init (unsigned int fd_count) + { + valid = true; + global_closure = hb_set_create (); + if (global_closure == hb_set_get_empty ()) + valid = false; + if (!local_closures.resize (fd_count)) + valid = false; + + for (unsigned int i = 0; i < local_closures.length; i++) + { + local_closures[i] = hb_set_create (); + if (local_closures[i] == hb_set_get_empty ()) + valid = false; + } + } + + void fini () + { + hb_set_destroy (global_closure); + for (unsigned int i = 0; i < local_closures.length; i++) + hb_set_destroy (local_closures[i]); + local_closures.fini (); + } + + void reset () + { + hb_set_clear (global_closure); + for (unsigned int i = 0; i < local_closures.length; i++) + hb_set_clear (local_closures[i]); + } + + bool is_valid () const { return valid; } + bool valid; + hb_set_t *global_closure; + hb_vector_t<hb_set_t *> local_closures; +}; + +struct parsed_cs_op_t : op_str_t +{ + void init (unsigned int subr_num_ = 0) + { + op_str_t::init (); + subr_num = subr_num_; + drop_flag = false; + keep_flag = false; + skip_flag = false; + } + + void fini () { op_str_t::fini (); } + + bool for_drop () const { return drop_flag; } + void set_drop () { if (!for_keep ()) drop_flag = true; } + + bool for_keep () const { return keep_flag; } + void set_keep () { keep_flag = true; } + + bool for_skip () const { return skip_flag; } + void set_skip () { skip_flag = true; } + + unsigned int subr_num; + + protected: + bool drop_flag : 1; + bool keep_flag : 1; + bool skip_flag : 1; +}; + +struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> +{ + void init () + { + SUPER::init (); + parsed = false; + hint_dropped = false; + has_prefix_ = false; + } + + void add_op (op_code_t op, const byte_str_ref_t& str_ref) + { + if (!is_parsed ()) + SUPER::add_op (op, str_ref); + } + + void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num) + { + if (!is_parsed ()) + { + unsigned int parsed_len = get_count (); + if (likely (parsed_len > 0)) + values[parsed_len-1].set_skip (); + + parsed_cs_op_t val; + val.init (subr_num); + SUPER::add_op (op, str_ref, val); + } + } + + void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid) + { + has_prefix_ = true; + prefix_op_ = op; + prefix_num_ = num; + } + + bool at_end (unsigned int pos) const + { + return ((pos + 1 >= values.length) /* CFF2 */ + || (values[pos + 1].op == OpCode_return)); + } + + bool is_parsed () const { return parsed; } + void set_parsed () { parsed = true; } + + bool is_hint_dropped () const { return hint_dropped; } + void set_hint_dropped () { hint_dropped = true; } + + bool is_vsindex_dropped () const { return vsindex_dropped; } + void set_vsindex_dropped () { vsindex_dropped = true; } + + bool has_prefix () const { return has_prefix_; } + op_code_t prefix_op () const { return prefix_op_; } + const number_t &prefix_num () const { return prefix_num_; } + + protected: + bool parsed; + bool hint_dropped; + bool vsindex_dropped; + bool has_prefix_; + op_code_t prefix_op_; + number_t prefix_num_; + + private: + typedef parsed_values_t<parsed_cs_op_t> SUPER; +}; + +struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> +{ + void init (unsigned int len_ = 0) + { + SUPER::init (); + resize (len_); + for (unsigned int i = 0; i < length; i++) + (*this)[i].init (); + } + void fini () { SUPER::fini_deep (); } + + private: + typedef hb_vector_t<parsed_cs_str_t> SUPER; +}; + +struct subr_subset_param_t +{ + void init (parsed_cs_str_t *parsed_charstring_, + parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_, + hb_set_t *global_closure_, hb_set_t *local_closure_, + bool drop_hints_) + { + parsed_charstring = parsed_charstring_; + current_parsed_str = parsed_charstring; + parsed_global_subrs = parsed_global_subrs_; + parsed_local_subrs = parsed_local_subrs_; + global_closure = global_closure_; + local_closure = local_closure_; + drop_hints = drop_hints_; + } + + parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) + { + switch (context.type) + { + case CSType_CharString: + return parsed_charstring; + + case CSType_LocalSubr: + if (likely (context.subr_num < parsed_local_subrs->length)) + return &(*parsed_local_subrs)[context.subr_num]; + break; + + case CSType_GlobalSubr: + if (likely (context.subr_num < parsed_global_subrs->length)) + return &(*parsed_global_subrs)[context.subr_num]; + break; + } + return nullptr; + } + + template <typename ENV> + void set_current_str (ENV &env, bool calling) + { + parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); + if (likely (parsed_str != nullptr)) + { + /* If the called subroutine is parsed partially but not completely yet, + * it must be because we are calling it recursively. + * Handle it as an error. */ + if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) + env.set_error (); + else + current_parsed_str = parsed_str; + } + else + env.set_error (); + } + + parsed_cs_str_t *current_parsed_str; + + parsed_cs_str_t *parsed_charstring; + parsed_cs_str_vec_t *parsed_global_subrs; + parsed_cs_str_vec_t *parsed_local_subrs; + hb_set_t *global_closure; + hb_set_t *local_closure; + bool drop_hints; +}; + +struct subr_remap_t : remap_t +{ + void create (hb_set_t *closure) + { + /* create a remapping of subroutine numbers from old to new. + * no optimization based on usage counts. fonttools doesn't appear doing that either. + */ + reset (closure->get_max () + 1); + for (hb_codepoint_t old_num = 0; old_num < length; old_num++) + { + if (hb_set_has (closure, old_num)) + add (old_num); + } + + if (get_count () < 1240) + bias = 107; + else if (get_count () < 33900) + bias = 1131; + else + bias = 32768; + } + + hb_codepoint_t operator[] (unsigned int old_num) const + { + if (old_num >= length) + return CFF_UNDEF_CODE; + else + return remap_t::operator[] (old_num); + } + + int biased_num (unsigned int old_num) const + { + hb_codepoint_t new_num = (*this)[old_num]; + return (int)new_num - bias; + } + + protected: + int bias; +}; + +struct subr_remap_ts +{ + subr_remap_ts () + { + global_remap.init (); + local_remaps.init (); + } + + ~subr_remap_ts () { fini (); } + + void init (unsigned int fdCount) + { + local_remaps.resize (fdCount); + for (unsigned int i = 0; i < fdCount; i++) + local_remaps[i].init (); + } + + void create (subr_closures_t& closures) + { + global_remap.create (closures.global_closure); + for (unsigned int i = 0; i < local_remaps.length; i++) + local_remaps[i].create (closures.local_closures[i]); + } + + void fini () + { + global_remap.fini (); + local_remaps.fini_deep (); + } + + subr_remap_t global_remap; + hb_vector_t<subr_remap_t> local_remaps; +}; + +template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET> +struct subr_subsetter_t +{ + subr_subsetter_t () + { + parsed_charstrings.init (); + parsed_global_subrs.init (); + parsed_local_subrs.init (); + } + + ~subr_subsetter_t () + { + closures.fini (); + remaps.fini (); + parsed_charstrings.fini_deep (); + parsed_global_subrs.fini_deep (); + parsed_local_subrs.fini_deep (); + } + + /* Subroutine subsetting with --no-desubroutinize runs in phases: + * + * 1. execute charstrings/subroutines to determine subroutine closures + * 2. parse out all operators and numbers + * 3. mark hint operators and operands for removal if --no-hinting + * 4. re-encode all charstrings and subroutines with new subroutine numbers + * + * Phases #1 and #2 are done at the same time in collect_subrs (). + * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required), + * because we can't tell if a number belongs to a hint op until we see the first moveto. + * + * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number + * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine. + */ + bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints) + { + closures.init (acc.fdCount); + remaps.init (acc.fdCount); + + parsed_charstrings.init (glyphs.length); + parsed_global_subrs.init (acc.globalSubrs->count); + parsed_local_subrs.resize (acc.fdCount); + for (unsigned int i = 0; i < acc.fdCount; i++) + { + parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); + } + if (unlikely (!closures.valid)) + return false; + + /* phase 1 & 2 */ + for (unsigned int i = 0; i < glyphs.length; i++) + { + hb_codepoint_t glyph = glyphs[i]; + const byte_str_t str = (*acc.charStrings)[glyph]; + unsigned int fd = acc.fdSelect->get_fd (glyph); + if (unlikely (fd >= acc.fdCount)) + return false; + + cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp; + interp.env.init (str, acc, fd); + + subr_subset_param_t param; + param.init (&parsed_charstrings[i], + &parsed_global_subrs, &parsed_local_subrs[fd], + closures.global_closure, closures.local_closures[fd], + drop_hints); + + if (unlikely (!interp.interpret (param))) + return false; + + /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ + SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]); + } + + if (drop_hints) + { + /* mark hint ops and arguments for drop */ + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + if (unlikely (fd >= acc.fdCount)) + return false; + subr_subset_param_t param; + param.init (&parsed_charstrings[i], + &parsed_global_subrs, &parsed_local_subrs[fd], + closures.global_closure, closures.local_closures[fd], + drop_hints); + + drop_hints_param_t drop; + if (drop_hints_in_str (parsed_charstrings[i], param, drop)) + { + parsed_charstrings[i].set_hint_dropped (); + if (drop.vsindex_dropped) + parsed_charstrings[i].set_vsindex_dropped (); + } + } + + /* after dropping hints recreate closures of actually used subrs */ + closures.reset (); + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + if (unlikely (fd >= acc.fdCount)) + return false; + subr_subset_param_t param; + param.init (&parsed_charstrings[i], + &parsed_global_subrs, &parsed_local_subrs[fd], + closures.global_closure, closures.local_closures[fd], + drop_hints); + collect_subr_refs_in_str (parsed_charstrings[i], param); + } + } + + remaps.create (closures); + + return true; + } + + bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, str_buff_vec_t &buffArray) const + { + if (unlikely (!buffArray.resize (glyphs.length))) + return false; + for (unsigned int i = 0; i < glyphs.length; i++) + { + unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + if (unlikely (fd >= acc.fdCount)) + return false; + if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i]))) + return false; + } + return true; + } + + bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const + { + unsigned int count = remap.get_count (); + + if (unlikely (!buffArray.resize (count))) + return false; + for (unsigned int old_num = 0; old_num < subrs.length; old_num++) + { + hb_codepoint_t new_num = remap[old_num]; + if (new_num != CFF_UNDEF_CODE) + { + if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num]))) + return false; + } + } + return true; + } + + bool encode_globalsubrs (str_buff_vec_t &buffArray) + { + return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray); + } + + bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const + { + return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray); + } + + protected: + struct drop_hints_param_t + { + drop_hints_param_t () + : seen_moveto (false), + ends_in_hint (false), + vsindex_dropped (false) {} + + bool seen_moveto; + bool ends_in_hint; + bool vsindex_dropped; + }; + + bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos, + parsed_cs_str_vec_t &subrs, unsigned int subr_num, + const subr_subset_param_t ¶m, drop_hints_param_t &drop) + { + drop.ends_in_hint = false; + bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); + + /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto), + * then this entire subroutine must be a hint. drop its call. */ + if (drop.ends_in_hint) + { + str.values[pos].set_drop (); + /* if this subr call is at the end of the parent subr, propagate the flag + * otherwise reset the flag */ + if (!str.at_end (pos)) + drop.ends_in_hint = false; + } + + return has_hint; + } + + /* returns true if it sees a hint op before the first moveto */ + bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m, drop_hints_param_t &drop) + { + bool seen_hint = false; + + for (unsigned int pos = 0; pos < str.values.length; pos++) + { + bool has_hint = false; + switch (str.values[pos].op) + { + case OpCode_callsubr: + has_hint = drop_hints_in_subr (str, pos, + *param.parsed_local_subrs, str.values[pos].subr_num, + param, drop); + + break; + + case OpCode_callgsubr: + has_hint = drop_hints_in_subr (str, pos, + *param.parsed_global_subrs, str.values[pos].subr_num, + param, drop); + break; + + case OpCode_rmoveto: + case OpCode_hmoveto: + case OpCode_vmoveto: + drop.seen_moveto = true; + break; + + case OpCode_hintmask: + case OpCode_cntrmask: + if (drop.seen_moveto) + { + str.values[pos].set_drop (); + break; + } + HB_FALLTHROUGH; + + case OpCode_hstemhm: + case OpCode_vstemhm: + case OpCode_hstem: + case OpCode_vstem: + has_hint = true; + str.values[pos].set_drop (); + if (str.at_end (pos)) + drop.ends_in_hint = true; + break; + + case OpCode_dotsection: + str.values[pos].set_drop (); + break; + + default: + /* NONE */ + break; + } + if (has_hint) + { + for (int i = pos - 1; i >= 0; i--) + { + parsed_cs_op_t &csop = str.values[(unsigned)i]; + if (csop.for_drop ()) + break; + csop.set_drop (); + if (csop.op == OpCode_vsindexcs) + drop.vsindex_dropped = true; + } + seen_hint |= has_hint; + } + } + + return seen_hint; + } + + void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos, + unsigned int subr_num, parsed_cs_str_vec_t &subrs, + hb_set_t *closure, + const subr_subset_param_t ¶m) + { + hb_set_add (closure, subr_num); + collect_subr_refs_in_str (subrs[subr_num], param); + } + + void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m) + { + for (unsigned int pos = 0; pos < str.values.length; pos++) + { + if (!str.values[pos].for_drop ()) + { + switch (str.values[pos].op) + { + case OpCode_callsubr: + collect_subr_refs_in_subr (str, pos, + str.values[pos].subr_num, *param.parsed_local_subrs, + param.local_closure, param); + break; + + case OpCode_callgsubr: + collect_subr_refs_in_subr (str, pos, + str.values[pos].subr_num, *param.parsed_global_subrs, + param.global_closure, param); + break; + + default: break; + } + } + } + } + + bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const + { + buff.init (); + str_encoder_t encoder (buff); + encoder.reset (); + /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, + * re-insert it at the beginning of charstreing */ + if (str.has_prefix () && str.is_hint_dropped ()) + { + encoder.encode_num (str.prefix_num ()); + if (str.prefix_op () != OpCode_Invalid) + encoder.encode_op (str.prefix_op ()); + } + for (unsigned int i = 0; i < str.get_count(); i++) + { + const parsed_cs_op_t &opstr = str.values[i]; + if (!opstr.for_drop () && !opstr.for_skip ()) + { + switch (opstr.op) + { + case OpCode_callsubr: + encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num)); + encoder.encode_op (OpCode_callsubr); + break; + + case OpCode_callgsubr: + encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num)); + encoder.encode_op (OpCode_callgsubr); + break; + + default: + encoder.copy_str (opstr.str); + break; + } + } + } + return !encoder.is_error (); + } + + protected: + subr_closures_t closures; + + parsed_cs_str_vec_t parsed_charstrings; + parsed_cs_str_vec_t parsed_global_subrs; + hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs; + + subr_remap_ts remaps; + + private: + typedef typename SUBRS::count_type subr_count_type; +}; + +} /* namespace CFF */ + +HB_INTERNAL bool +hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs, + unsigned int fdCount, + const CFF::FDSelect &src, /* IN */ + unsigned int &subset_fd_count /* OUT */, + unsigned int &subset_fdselect_size /* OUT */, + unsigned int &subset_fdselect_format /* OUT */, + hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */, + CFF::remap_t &fdmap /* OUT */); + +HB_INTERNAL bool +hb_serialize_cff_fdselect (hb_serialize_context_t *c, + unsigned int num_glyphs, + const CFF::FDSelect &src, + unsigned int fd_count, + unsigned int fdselect_format, + unsigned int size, + const hb_vector_t<CFF::code_pair_t> &fdselect_ranges); + +#endif /* HB_SUBSET_CFF_COMMON_HH */ diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc new file mode 100644 index 0000000..5133a4d --- /dev/null +++ b/src/hb-subset-cff1.cc @@ -0,0 +1,1103 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-open-type.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-set.h" +#include "hb-subset-cff1.hh" +#include "hb-subset-plan.hh" +#include "hb-subset-cff-common.hh" +#include "hb-cff1-interp-cs.hh" + +using namespace CFF; + +struct remap_sid_t : remap_t +{ + unsigned int add (unsigned int sid) + { + if ((sid != CFF_UNDEF_SID) && !is_std_std (sid)) + return offset_sid (remap_t::add (unoffset_sid (sid))); + else + return sid; + } + + unsigned int operator[] (unsigned int sid) const + { + if (is_std_std (sid) || (sid == CFF_UNDEF_SID)) + return sid; + else + return offset_sid (remap_t::operator [] (unoffset_sid (sid))); + } + + static const unsigned int num_std_strings = 391; + + static bool is_std_std (unsigned int sid) { return sid < num_std_strings; } + static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; } + static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } +}; + +struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t +{ + cff1_sub_table_offsets_t () + : cff_sub_table_offsets_t (), + nameIndexOffset (0), + encodingOffset (0) + { + stringIndexInfo.init (); + charsetInfo.init (); + privateDictInfo.init (); + } + + unsigned int nameIndexOffset; + table_info_t stringIndexInfo; + unsigned int encodingOffset; + table_info_t charsetInfo; + table_info_t privateDictInfo; +}; + +/* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */ +struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t +{ + void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t)) + { + SUPER::init (); + base = base_; + } + + void fini () { SUPER::fini (); } + + unsigned get_count () const { return base->get_count () + SUPER::get_count (); } + const cff1_top_dict_val_t &get_value (unsigned int i) const + { + if (i < base->get_count ()) + return (*base)[i]; + else + return SUPER::values[i - base->get_count ()]; + } + const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); } + + void reassignSIDs (const remap_sid_t& sidmap) + { + for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) + nameSIDs[i] = sidmap[base->nameSIDs[i]]; + } + + protected: + typedef cff1_top_dict_values_t SUPER; + const cff1_top_dict_values_t *base; +}; + +struct top_dict_modifiers_t +{ + top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_, + const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) + : offsets (offsets_), + nameSIDs (nameSIDs_) + {} + + const cff1_sub_table_offsets_t &offsets; + const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; +}; + +struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t> +{ + bool serialize (hb_serialize_context_t *c, + const cff1_top_dict_val_t &opstr, + const top_dict_modifiers_t &mod) const + { + TRACE_SERIALIZE (this); + + op_code_t op = opstr.op; + switch (op) + { + case OpCode_charset: + return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset)); + + case OpCode_Encoding: + return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset)); + + case OpCode_Private: + { + if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size))) + return_trace (false); + if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset))) + return_trace (false); + HBUINT8 *p = c->allocate_size<HBUINT8> (1); + if (unlikely (p == nullptr)) return_trace (false); + p->set (OpCode_Private); + } + break; + + case OpCode_version: + case OpCode_Notice: + case OpCode_Copyright: + case OpCode_FullName: + case OpCode_FamilyName: + case OpCode_Weight: + case OpCode_PostScript: + case OpCode_BaseFontName: + case OpCode_FontName: + return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)])); + + case OpCode_ROS: + { + /* for registry & ordering, reassigned SIDs are serialized + * for supplement, the original byte string is copied along with the op code */ + op_str_t supp_op; + supp_op.op = op; + if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3))) + return_trace (false); + supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); + return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) && + UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && + copy_opstr (c, supp_op)); + } + default: + return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets)); + } + return_trace (true); + } + + unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const + { + op_code_t op = opstr.op; + switch (op) + { + case OpCode_charset: + case OpCode_Encoding: + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); + + case OpCode_Private: + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); + + case OpCode_version: + case OpCode_Notice: + case OpCode_Copyright: + case OpCode_FullName: + case OpCode_FamilyName: + case OpCode_Weight: + case OpCode_PostScript: + case OpCode_BaseFontName: + case OpCode_FontName: + return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op); + + case OpCode_ROS: + return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */; + + default: + return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr); + } + } +}; + +struct font_dict_values_mod_t +{ + void init (const cff1_font_dict_values_t *base_, + unsigned int fontName_, + const table_info_t &privateDictInfo_) + { + base = base_; + fontName = fontName_; + privateDictInfo = privateDictInfo_; + } + + unsigned get_count () const { return base->get_count (); } + + const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } + + const cff1_font_dict_values_t *base; + table_info_t privateDictInfo; + unsigned int fontName; +}; + +struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t +{ + bool serialize (hb_serialize_context_t *c, + const op_str_t &opstr, + const font_dict_values_mod_t &mod) const + { + TRACE_SERIALIZE (this); + + if (opstr.op == OpCode_FontName) + return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName)); + else + return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); + } + + unsigned int calculate_serialized_size (const op_str_t &opstr) const + { + if (opstr.op == OpCode_FontName) + return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName); + else + return SUPER::calculate_serialized_size (opstr); + } + + private: + typedef cff_font_dict_op_serializer_t SUPER; +}; + +struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> +{ + static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) + { + if (env.arg_start > 0) + flush_width (env, param); + + switch (op) + { + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + case OpCode_dotsection: + if (param.drop_hints) + { + env.clear_args (); + return; + } + HB_FALLTHROUGH; + + default: + SUPER::flush_args_and_op (op, env, param); + break; + } + } + static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param) + { + str_encoder_t encoder (param.flatStr); + for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++) + encoder.encode_num (env.eval_arg (i)); + SUPER::flush_args (env, param); + } + + static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) + { + str_encoder_t encoder (param.flatStr); + encoder.encode_op (op); + } + + static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param) + { + assert (env.has_width); + str_encoder_t encoder (param.flatStr); + encoder.encode_num (env.width); + } + + static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) + { + SUPER::flush_hintmask (op, env, param); + if (!param.drop_hints) + { + str_encoder_t encoder (param.flatStr); + for (unsigned int i = 0; i < env.hintmask_size; i++) + encoder.encode_byte (env.str_ref[i]); + } + } + + private: + typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER; +}; + +struct range_list_t : hb_vector_t<code_pair_t> +{ + /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ + bool finalize (unsigned int last_glyph) + { + bool two_byte = false; + for (unsigned int i = (*this).length; i > 0; i--) + { + code_pair_t &pair = (*this)[i - 1]; + unsigned int nLeft = last_glyph - pair.glyph - 1; + if (nLeft >= 0x100) + two_byte = true; + last_glyph = pair.glyph; + pair.glyph = nLeft; + } + return two_byte; + } +}; + +struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> +{ + static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param) + { + switch (op) { + + case OpCode_return: + param.current_parsed_str->add_op (op, env.str_ref); + param.current_parsed_str->set_parsed (); + env.returnFromSubr (); + param.set_current_str (env, false); + break; + + case OpCode_endchar: + param.current_parsed_str->add_op (op, env.str_ref); + param.current_parsed_str->set_parsed (); + SUPER::process_op (op, env, param); + break; + + case OpCode_callsubr: + process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure); + break; + + case OpCode_callgsubr: + process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure); + break; + + default: + SUPER::process_op (op, env, param); + param.current_parsed_str->add_op (op, env.str_ref); + break; + } + } + + protected: + static void process_call_subr (op_code_t op, cs_type_t type, + cff1_cs_interp_env_t &env, subr_subset_param_t& param, + cff1_biased_subrs_t& subrs, hb_set_t *closure) + { + byte_str_ref_t str_ref = env.str_ref; + env.callSubr (subrs, type); + param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); + hb_set_add (closure, env.context.subr_num); + param.set_current_str (env, true); + } + + private: + typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; +}; + +struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t> +{ + static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + { + /* insert width at the beginning of the charstring as necessary */ + if (env.has_width) + charstring.set_prefix (env.width); + + /* subroutines/charstring left on the call stack are legally left unmarked + * unmarked when a subroutine terminates with endchar. mark them. + */ + param.current_parsed_str->set_parsed (); + for (unsigned int i = 0; i < env.callStack.get_count (); i++) + { + parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); + if (likely (parsed_str != nullptr)) + parsed_str->set_parsed (); + else + env.set_error (); + } + } +}; + +struct cff_subset_plan { + cff_subset_plan () + : final_size (0), + offsets (), + orig_fdcount (0), + subset_fdcount (1), + subset_fdselect_format (0), + drop_hints (false), + desubroutinize(false) + { + topdict_sizes.init (); + topdict_sizes.resize (1); + topdict_mod.init (); + subset_fdselect_ranges.init (); + fdmap.init (); + subset_charstrings.init (); + subset_globalsubrs.init (); + subset_localsubrs.init (); + fontdicts_mod.init (); + subset_enc_code_ranges.init (); + subset_enc_supp_codes.init (); + subset_charset_ranges.init (); + sidmap.init (); + for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) + topDictModSIDs[i] = CFF_UNDEF_SID; + } + + ~cff_subset_plan () + { + topdict_sizes.fini (); + topdict_mod.fini (); + subset_fdselect_ranges.fini (); + fdmap.fini (); + subset_charstrings.fini_deep (); + subset_globalsubrs.fini_deep (); + subset_localsubrs.fini_deep (); + fontdicts_mod.fini (); + subset_enc_code_ranges.fini (); + subset_enc_supp_codes.fini (); + subset_charset_ranges.fini (); + sidmap.fini (); + } + + unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + { + const Encoding *encoding = acc.encoding; + unsigned int size0, size1, supp_size; + hb_codepoint_t code, last_code = CFF_UNDEF_CODE; + hb_vector_t<hb_codepoint_t> supp_codes; + + subset_enc_code_ranges.resize (0); + supp_size = 0; + supp_codes.init (); + + subset_enc_num_codes = plan->glyphs.length - 1; + unsigned int glyph; + for (glyph = 1; glyph < plan->glyphs.length; glyph++) + { + hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + code = acc.glyph_to_code (orig_glyph); + if (code == CFF_UNDEF_CODE) + { + subset_enc_num_codes = glyph - 1; + break; + } + + if (code != last_code + 1) + { + code_pair_t pair = { code, glyph }; + subset_enc_code_ranges.push (pair); + } + last_code = code; + + if (encoding != &Null(Encoding)) + { + hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph); + encoding->get_supplement_codes (sid, supp_codes); + for (unsigned int i = 0; i < supp_codes.length; i++) + { + code_pair_t pair = { supp_codes[i], sid }; + subset_enc_supp_codes.push (pair); + } + supp_size += SuppEncoding::static_size * supp_codes.length; + } + } + supp_codes.fini (); + + subset_enc_code_ranges.finalize (glyph); + + assert (subset_enc_num_codes <= 0xFF); + size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes; + size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length; + + if (size0 < size1) + subset_enc_format = 0; + else + subset_enc_format = 1; + + return Encoding::calculate_serialized_size ( + subset_enc_format, + subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes, + subset_enc_supp_codes.length); + } + + unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + { + unsigned int size0, size_ranges; + hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; + + subset_charset_ranges.resize (0); + unsigned int glyph; + for (glyph = 1; glyph < plan->glyphs.length; glyph++) + { + hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + sid = acc.glyph_to_sid (orig_glyph); + + if (!acc.is_CID ()) + sid = sidmap.add (sid); + + if (sid != last_sid + 1) + { + code_pair_t pair = { sid, glyph }; + subset_charset_ranges.push (pair); + } + last_sid = sid; + } + + bool two_byte = subset_charset_ranges.finalize (glyph); + + size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1); + if (!two_byte) + size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length; + else + size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length; + + if (size0 < size_ranges) + subset_charset_format = 0; + else if (!two_byte) + subset_charset_format = 1; + else + subset_charset_format = 2; + + return Charset::calculate_serialized_size ( + subset_charset_format, + subset_charset_format? subset_charset_ranges.length: plan->glyphs.length); + } + + bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) + { + if (unlikely (!sidmap.reset (acc.stringIndex->count))) + return false; + + for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) + { + unsigned int sid = acc.topDict.nameSIDs[i]; + if (sid != CFF_UNDEF_SID) + { + (void)sidmap.add (sid); + topDictModSIDs[i] = sidmap[sid]; + } + } + + if (acc.fdArray != &Null(CFF1FDArray)) + for (unsigned int i = 0; i < orig_fdcount; i++) + if (fdmap.includes (i)) + (void)sidmap.add (acc.fontDicts[i].fontName); + + return true; + } + + bool create (const OT::cff1::accelerator_subset_t &acc, + hb_subset_plan_t *plan) + { + /* make sure notdef is first */ + if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false; + + final_size = 0; + num_glyphs = plan->glyphs.length; + orig_fdcount = acc.fdCount; + drop_hints = plan->drop_hints; + desubroutinize = plan->desubroutinize; + + /* check whether the subset renumbers any glyph IDs */ + gid_renum = false; + for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++) + { + if (plan->glyphs[glyph] != glyph) { + gid_renum = true; + break; + } + } + + subset_charset = gid_renum || !acc.is_predef_charset (); + subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); + + /* CFF header */ + final_size += OT::cff1::static_size; + + /* Name INDEX */ + offsets.nameIndexOffset = final_size; + final_size += acc.nameIndex->get_size (); + + /* top dict INDEX */ + { + /* Add encoding/charset to a (copy of) top dict as necessary */ + topdict_mod.init (&acc.topDict); + bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding)); + bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset)); + if (need_to_add_enc || need_to_add_set) + { + if (need_to_add_enc) + topdict_mod.add_op (OpCode_Encoding); + if (need_to_add_set) + topdict_mod.add_op (OpCode_charset); + } + offsets.topDictInfo.offset = final_size; + cff1_top_dict_op_serializer_t topSzr; + unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); + offsets.topDictInfo.offSize = calcOffSize(topDictSize); + if (unlikely (offsets.topDictInfo.offSize > 4)) + return false; + final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t> + (offsets.topDictInfo.offSize, + &topdict_mod, 1, topdict_sizes, topSzr); + } + + /* Determine re-mapping of font index as fdmap among other info */ + if (acc.fdSelect != &Null(CFF1FDSelect)) + { + if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + orig_fdcount, + *acc.fdSelect, + subset_fdcount, + offsets.FDSelectInfo.size, + subset_fdselect_format, + subset_fdselect_ranges, + fdmap))) + return false; + } + else + fdmap.identity (1); + + /* remove unused SIDs & reassign SIDs */ + { + /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */ + if (unlikely (!collect_sids_in_dicts (acc))) + return false; + if (unlikely (sidmap.get_count () > 0x8000)) /* assumption: a dict won't reference that many strings */ + return false; + if (subset_charset) + offsets.charsetInfo.size = plan_subset_charset (acc, plan); + + topdict_mod.reassignSIDs (sidmap); + } + + /* String INDEX */ + { + offsets.stringIndexInfo.offset = final_size; + offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); + final_size += offsets.stringIndexInfo.size; + } + + if (desubroutinize) + { + /* Flatten global & local subrs */ + subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t> + flattener(acc, plan->glyphs, plan->drop_hints); + if (!flattener.flatten (subset_charstrings)) + return false; + + /* no global/local subroutines */ + offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0); + } + else + { + /* Subset subrs: collect used subroutines, leaving all unused ones behind */ + if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + return false; + + /* encode charstrings, global subrs, local subrs with new subroutine numbers */ + if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + return false; + + if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) + return false; + + /* global subrs */ + unsigned int dataSize = subset_globalsubrs.total_size (); + offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); + if (unlikely (offsets.globalSubrsInfo.offSize > 4)) + return false; + offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); + + /* local subrs */ + if (!offsets.localSubrsInfos.resize (orig_fdcount)) + return false; + if (!subset_localsubrs.resize (orig_fdcount)) + return false; + for (unsigned int fd = 0; fd < orig_fdcount; fd++) + { + subset_localsubrs[fd].init (); + offsets.localSubrsInfos[fd].init (); + if (fdmap.includes (fd)) + { + if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) + return false; + + unsigned int dataSize = subset_localsubrs[fd].total_size (); + if (dataSize > 0) + { + offsets.localSubrsInfos[fd].offset = final_size; + offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); + if (unlikely (offsets.localSubrsInfos[fd].offSize > 4)) + return false; + offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); + } + } + } + } + + /* global subrs */ + offsets.globalSubrsInfo.offset = final_size; + final_size += offsets.globalSubrsInfo.size; + + /* Encoding */ + if (!subset_encoding) + offsets.encodingOffset = acc.topDict.EncodingOffset; + else + { + offsets.encodingOffset = final_size; + final_size += plan_subset_encoding (acc, plan); + } + + /* Charset */ + if (!subset_charset && acc.is_predef_charset ()) + offsets.charsetInfo.offset = acc.topDict.CharsetOffset; + else + offsets.charsetInfo.offset = final_size; + final_size += offsets.charsetInfo.size; + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF1FDSelect)) + { + offsets.FDSelectInfo.offset = final_size; + final_size += offsets.FDSelectInfo.size; + } + + /* FDArray (FDIndex) */ + if (acc.fdArray != &Null(CFF1FDArray)) { + offsets.FDArrayInfo.offset = final_size; + cff1_font_dict_op_serializer_t fontSzr; + unsigned int dictsSize = 0; + for (unsigned int i = 0; i < acc.fontDicts.length; i++) + if (fdmap.includes (i)) + dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); + + offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); + if (unlikely (offsets.FDArrayInfo.offSize > 4)) + return false; + final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); + } + + /* CharStrings */ + { + offsets.charStringsInfo.offset = final_size; + unsigned int dataSize = subset_charstrings.total_size (); + offsets.charStringsInfo.offSize = calcOffSize (dataSize); + if (unlikely (offsets.charStringsInfo.offSize > 4)) + return false; + final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); + } + + /* private dicts & local subrs */ + offsets.privateDictInfo.offset = final_size; + for (unsigned int i = 0; i < orig_fdcount; i++) + { + if (fdmap.includes (i)) + { + bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; + cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints); + unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); + table_info_t privInfo = { final_size, priv_size, 0 }; + font_dict_values_mod_t fontdict_mod; + if (!acc.is_CID ()) + fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo ); + else + fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); + fontdicts_mod.push (fontdict_mod); + final_size += privInfo.size; + + if (!plan->desubroutinize && has_localsubrs) + { + offsets.localSubrsInfos[i].offset = final_size; + final_size += offsets.localSubrsInfos[i].size; + } + } + } + + if (!acc.is_CID ()) + offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; + + return ((subset_charstrings.length == plan->glyphs.length) + && (fontdicts_mod.length == subset_fdcount)); + } + + unsigned int get_final_size () const { return final_size; } + + unsigned int final_size; + hb_vector_t<unsigned int> topdict_sizes; + cff1_top_dict_values_mod_t topdict_mod; + cff1_sub_table_offsets_t offsets; + + unsigned int num_glyphs; + unsigned int orig_fdcount; + unsigned int subset_fdcount; + unsigned int subset_fdselect_format; + hb_vector_t<code_pair_t> subset_fdselect_ranges; + + /* font dict index remap table from fullset FDArray to subset FDArray. + * set to CFF_UNDEF_CODE if excluded from subset */ + remap_t fdmap; + + str_buff_vec_t subset_charstrings; + str_buff_vec_t subset_globalsubrs; + hb_vector_t<str_buff_vec_t> subset_localsubrs; + hb_vector_t<font_dict_values_mod_t> fontdicts_mod; + + bool drop_hints; + + bool gid_renum; + bool subset_encoding; + uint8_t subset_enc_format; + unsigned int subset_enc_num_codes; + range_list_t subset_enc_code_ranges; + hb_vector_t<code_pair_t> subset_enc_supp_codes; + + uint8_t subset_charset_format; + range_list_t subset_charset_ranges; + bool subset_charset; + + remap_sid_t sidmap; + unsigned int topDictModSIDs[name_dict_values_t::ValCount]; + + bool desubroutinize; + cff1_subr_subsetter_t subr_subsetter; +}; + +static inline bool _write_cff1 (const cff_subset_plan &plan, + const OT::cff1::accelerator_subset_t &acc, + const hb_vector_t<hb_codepoint_t>& glyphs, + unsigned int dest_sz, + void *dest) +{ + hb_serialize_context_t c (dest, dest_sz); + + OT::cff1 *cff = c.start_serialize<OT::cff1> (); + if (unlikely (!c.extend_min (*cff))) + return false; + + /* header */ + cff->version.major.set (0x01); + cff->version.minor.set (0x00); + cff->nameIndex.set (cff->min_size); + cff->offSize.set (4); /* unused? */ + + /* name INDEX */ + { + assert (cff->nameIndex == (unsigned) (c.head - c.start)); + CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, *acc.nameIndex))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX"); + return false; + } + } + + /* top dict INDEX */ + { + assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start)); + CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > (); + if (dest == nullptr) return false; + cff1_top_dict_op_serializer_t topSzr; + top_dict_modifiers_t modifier (plan.offsets, plan.topDictModSIDs); + if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, + &plan.topdict_mod, 1, + plan.topdict_sizes, topSzr, modifier))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); + return false; + } + } + + /* String INDEX */ + { + assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start)); + CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); + return false; + } + } + + /* global subrs */ + { + assert (plan.offsets.globalSubrsInfo.offset != 0); + assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start)); + + CFF1Subrs *dest = c.start_embed <CFF1Subrs> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); + return false; + } + } + + /* Encoding */ + if (plan.subset_encoding) + { + assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start)); + Encoding *dest = c.start_embed<Encoding> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, + plan.subset_enc_format, + plan.subset_enc_num_codes, + plan.subset_enc_code_ranges, + plan.subset_enc_supp_codes))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding"); + return false; + } + } + + /* Charset */ + if (plan.subset_charset) + { + assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start)); + Charset *dest = c.start_embed<Charset> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, + plan.subset_charset_format, + plan.num_glyphs, + plan.subset_charset_ranges))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset"); + return false; + } + } + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF1FDSelect)) + { + assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); + + if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount, + plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, + plan.subset_fdselect_ranges))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); + return false; + } + } + + /* FDArray (FD Index) */ + if (acc.fdArray != &Null(CFF1FDArray)) + { + assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); + CFF1FDArray *fda = c.start_embed<CFF1FDArray> (); + if (unlikely (fda == nullptr)) return false; + cff1_font_dict_op_serializer_t fontSzr; + if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, + plan.fontdicts_mod, + fontSzr))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); + return false; + } + } + + /* CharStrings */ + { + assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); + CFF1CharStrings *cs = c.start_embed<CFF1CharStrings> (); + if (unlikely (cs == nullptr)) return false; + if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings"); + return false; + } + } + + /* private dicts & local subrs */ + assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start)); + for (unsigned int i = 0; i < acc.privateDicts.length; i++) + { + if (plan.fdmap.includes (i)) + { + PrivateDict *pd = c.start_embed<PrivateDict> (); + if (unlikely (pd == nullptr)) return false; + unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; + bool result; + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; + result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); + if (unlikely (!result)) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); + return false; + } + if (plan.offsets.localSubrsInfos[i].size > 0) + { + CFF1Subrs *dest = c.start_embed <CFF1Subrs> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); + return false; + } + } + } + } + + assert (c.head == c.end); + c.end_serialize (); + + return true; +} + +static bool +_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, + const char *data, + hb_subset_plan_t *plan, + hb_blob_t **prime /* OUT */) +{ + cff_subset_plan cff_plan; + + if (unlikely (!cff_plan.create (acc, plan))) + { + DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); + return false; + } + + unsigned int cff_prime_size = cff_plan.get_final_size (); + char *cff_prime_data = (char *) calloc (1, cff_prime_size); + + if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs, + cff_prime_size, cff_prime_data))) { + DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); + free (cff_prime_data); + return false; + } + + *prime = hb_blob_create (cff_prime_data, + cff_prime_size, + HB_MEMORY_MODE_READONLY, + cff_prime_data, + free); + return true; +} + +/** + * hb_subset_cff1: + * Subsets the CFF table according to a provided plan. + * + * Return value: subsetted cff table. + **/ +bool +hb_subset_cff1 (hb_subset_plan_t *plan, + hb_blob_t **prime /* OUT */) +{ + hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source); + const char *data = hb_blob_get_data(cff_blob, nullptr); + + OT::cff1::accelerator_subset_t acc; + acc.init(plan->source); + bool result = likely (acc.is_valid ()) && + _hb_subset_cff1 (acc, data, plan, prime); + hb_blob_destroy (cff_blob); + acc.fini (); + + return result; +} diff --git a/src/hb-subset-cff1.hh b/src/hb-subset-cff1.hh new file mode 100644 index 0000000..1ec8678 --- /dev/null +++ b/src/hb-subset-cff1.hh @@ -0,0 +1,38 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_SUBSET_CFF1_HH +#define HB_SUBSET_CFF1_HH + +#include "hb.hh" + +#include "hb-subset-plan.hh" + +HB_INTERNAL bool +hb_subset_cff1 (hb_subset_plan_t *plan, + hb_blob_t **cff_prime /* OUT */); + +#endif /* HB_SUBSET_CFF1_HH */ diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc new file mode 100644 index 0000000..73a292d --- /dev/null +++ b/src/hb-subset-cff2.cc @@ -0,0 +1,624 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-open-type.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-set.h" +#include "hb-subset-cff2.hh" +#include "hb-subset-plan.hh" +#include "hb-subset-cff-common.hh" +#include "hb-cff2-interp-cs.hh" + +using namespace CFF; + +struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t +{ + cff2_sub_table_offsets_t () + : cff_sub_table_offsets_t (), + varStoreOffset (0) + {} + + unsigned int varStoreOffset; +}; + +struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> +{ + bool serialize (hb_serialize_context_t *c, + const op_str_t &opstr, + const cff2_sub_table_offsets_t &offsets) const + { + TRACE_SERIALIZE (this); + + switch (opstr.op) + { + case OpCode_vstore: + return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); + + default: + return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets)); + } + } + + unsigned int calculate_serialized_size (const op_str_t &opstr) const + { + switch (opstr.op) + { + case OpCode_vstore: + return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); + + default: + return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr); + } + } +}; + +struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> +{ + static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + { + switch (op) + { + case OpCode_return: + case OpCode_endchar: + /* dummy opcodes in CFF2. ignore */ + break; + + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + if (param.drop_hints) + { + env.clear_args (); + return; + } + HB_FALLTHROUGH; + + default: + SUPER::flush_args_and_op (op, env, param); + break; + } + } + + static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param) + { + for (unsigned int i = 0; i < env.argStack.get_count ();) + { + const blend_arg_t &arg = env.argStack[i]; + if (arg.blending ()) + { + if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues)))) + { + env.set_error (); + return; + } + flatten_blends (arg, i, env, param); + i += arg.numValues; + } + else + { + str_encoder_t encoder (param.flatStr); + encoder.encode_num (arg); + i++; + } + } + SUPER::flush_args (env, param); + } + + static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param) + { + /* flatten the default values */ + str_encoder_t encoder (param.flatStr); + for (unsigned int j = 0; j < arg.numValues; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + if (unlikely (!((arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) && + (arg1.deltas.length == env.get_region_count ()))))) + { + env.set_error (); + return; + } + encoder.encode_num (arg1); + } + /* flatten deltas for each value */ + for (unsigned int j = 0; j < arg.numValues; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + for (unsigned int k = 0; k < arg1.deltas.length; k++) + encoder.encode_num (arg1.deltas[k]); + } + /* flatten the number of values followed by blend operator */ + encoder.encode_int (arg.numValues); + encoder.encode_op (OpCode_blendcs); + } + + static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + { + switch (op) + { + case OpCode_return: + case OpCode_endchar: + return; + default: + str_encoder_t encoder (param.flatStr); + encoder.encode_op (op); + } + } + + private: + typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER; + typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET; +}; + +struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> +{ + static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) + { + switch (op) { + + case OpCode_return: + param.current_parsed_str->set_parsed (); + env.returnFromSubr (); + param.set_current_str (env, false); + break; + + case OpCode_endchar: + param.current_parsed_str->set_parsed (); + SUPER::process_op (op, env, param); + break; + + case OpCode_callsubr: + process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure); + break; + + case OpCode_callgsubr: + process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure); + break; + + default: + SUPER::process_op (op, env, param); + param.current_parsed_str->add_op (op, env.str_ref); + break; + } + } + + protected: + static void process_call_subr (op_code_t op, cs_type_t type, + cff2_cs_interp_env_t &env, subr_subset_param_t& param, + cff2_biased_subrs_t& subrs, hb_set_t *closure) + { + byte_str_ref_t str_ref = env.str_ref; + env.callSubr (subrs, type); + param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); + hb_set_add (closure, env.context.subr_num); + param.set_current_str (env, true); + } + + private: + typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; +}; + +struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t> +{ + static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + { + /* vsindex is inserted at the beginning of the charstring as necessary */ + if (env.seen_vsindex ()) + { + number_t ivs; + ivs.set_int ((int)env.get_ivs ()); + charstring.set_prefix (ivs, OpCode_vsindexcs); + } + } +}; + +struct cff2_subset_plan { + cff2_subset_plan () + : final_size (0), + orig_fdcount (0), + subset_fdcount(1), + subset_fdselect_format (0), + drop_hints (false), + desubroutinize (false) + { + subset_fdselect_ranges.init (); + fdmap.init (); + subset_charstrings.init (); + subset_globalsubrs.init (); + subset_localsubrs.init (); + privateDictInfos.init (); + } + + ~cff2_subset_plan () + { + subset_fdselect_ranges.fini (); + fdmap.fini (); + subset_charstrings.fini_deep (); + subset_globalsubrs.fini_deep (); + subset_localsubrs.fini_deep (); + privateDictInfos.fini (); + } + + bool create (const OT::cff2::accelerator_subset_t &acc, + hb_subset_plan_t *plan) + { + final_size = 0; + orig_fdcount = acc.fdArray->count; + + drop_hints = plan->drop_hints; + desubroutinize = plan->desubroutinize; + + /* CFF2 header */ + final_size += OT::cff2::static_size; + + /* top dict */ + { + cff2_top_dict_op_serializer_t topSzr; + offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr); + final_size += offsets.topDictInfo.size; + } + + if (desubroutinize) + { + /* Flatten global & local subrs */ + subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t> + flattener(acc, plan->glyphs, plan->drop_hints); + if (!flattener.flatten (subset_charstrings)) + return false; + + /* no global/local subroutines */ + offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0); + } + else + { + /* Subset subrs: collect used subroutines, leaving all unused ones behind */ + if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + return false; + + /* encode charstrings, global subrs, local subrs with new subroutine numbers */ + if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + return false; + + if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) + return false; + + /* global subrs */ + unsigned int dataSize = subset_globalsubrs.total_size (); + offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); + offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); + + /* local subrs */ + if (!offsets.localSubrsInfos.resize (orig_fdcount)) + return false; + if (!subset_localsubrs.resize (orig_fdcount)) + return false; + for (unsigned int fd = 0; fd < orig_fdcount; fd++) + { + subset_localsubrs[fd].init (); + offsets.localSubrsInfos[fd].init (); + if (fdmap.includes (fd)) + { + if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) + return false; + + unsigned int dataSize = subset_localsubrs[fd].total_size (); + if (dataSize > 0) + { + offsets.localSubrsInfos[fd].offset = final_size; + offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); + offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); + } + } + } + } + + /* global subrs */ + offsets.globalSubrsInfo.offset = final_size; + final_size += offsets.globalSubrsInfo.size; + + /* variation store */ + if (acc.varStore != &Null(CFF2VariationStore)) + { + offsets.varStoreOffset = final_size; + final_size += acc.varStore->get_size (); + } + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF2FDSelect)) + { + offsets.FDSelectInfo.offset = final_size; + if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + orig_fdcount, + *(const FDSelect *)acc.fdSelect, + subset_fdcount, + offsets.FDSelectInfo.size, + subset_fdselect_format, + subset_fdselect_ranges, + fdmap))) + return false; + + final_size += offsets.FDSelectInfo.size; + } + else + fdmap.identity (1); + + /* FDArray (FDIndex) */ + { + offsets.FDArrayInfo.offset = final_size; + cff_font_dict_op_serializer_t fontSzr; + unsigned int dictsSize = 0; + for (unsigned int i = 0; i < acc.fontDicts.length; i++) + if (fdmap.includes (i)) + dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); + + offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); + final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); + } + + /* CharStrings */ + { + offsets.charStringsInfo.offset = final_size; + unsigned int dataSize = subset_charstrings.total_size (); + offsets.charStringsInfo.offSize = calcOffSize (dataSize); + final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); + } + + /* private dicts & local subrs */ + offsets.privateDictsOffset = final_size; + for (unsigned int i = 0; i < orig_fdcount; i++) + { + if (fdmap.includes (i)) + { + bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; + cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints); + unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); + table_info_t privInfo = { final_size, priv_size, 0 }; + privateDictInfos.push (privInfo); + final_size += privInfo.size; + + if (!plan->desubroutinize && has_localsubrs) + { + offsets.localSubrsInfos[i].offset = final_size; + final_size += offsets.localSubrsInfos[i].size; + } + } + } + + return true; + } + + unsigned int get_final_size () const { return final_size; } + + unsigned int final_size; + cff2_sub_table_offsets_t offsets; + + unsigned int orig_fdcount; + unsigned int subset_fdcount; + unsigned int subset_fdselect_format; + hb_vector_t<code_pair_t> subset_fdselect_ranges; + + remap_t fdmap; + + str_buff_vec_t subset_charstrings; + str_buff_vec_t subset_globalsubrs; + hb_vector_t<str_buff_vec_t> subset_localsubrs; + hb_vector_t<table_info_t> privateDictInfos; + + bool drop_hints; + bool desubroutinize; + cff2_subr_subsetter_t subr_subsetter; +}; + +static inline bool _write_cff2 (const cff2_subset_plan &plan, + const OT::cff2::accelerator_subset_t &acc, + const hb_vector_t<hb_codepoint_t>& glyphs, + unsigned int dest_sz, + void *dest) +{ + hb_serialize_context_t c (dest, dest_sz); + + OT::cff2 *cff2 = c.start_serialize<OT::cff2> (); + if (unlikely (!c.extend_min (*cff2))) + return false; + + /* header */ + cff2->version.major.set (0x02); + cff2->version.minor.set (0x00); + cff2->topDict.set (OT::cff2::static_size); + + /* top dict */ + { + assert (cff2->topDict == (unsigned) (c.head - c.start)); + cff2->topDictSize.set (plan.offsets.topDictInfo.size); + TopDict &dict = cff2 + cff2->topDict; + cff2_top_dict_op_serializer_t topSzr; + if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict"); + return false; + } + } + + /* global subrs */ + { + assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start)); + CFF2Subrs *dest = c.start_embed <CFF2Subrs> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); + return false; + } + } + + /* variation store */ + if (acc.varStore != &Null(CFF2VariationStore)) + { + assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start)); + CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> (); + if (unlikely (!dest->serialize (&c, acc.varStore))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store"); + return false; + } + } + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF2FDSelect)) + { + assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); + + if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, + plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, + plan.subset_fdselect_ranges))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); + return false; + } + } + + /* FDArray (FD Index) */ + { + assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); + CFF2FDArray *fda = c.start_embed<CFF2FDArray> (); + if (unlikely (fda == nullptr)) return false; + cff_font_dict_op_serializer_t fontSzr; + if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, + acc.fontDicts, plan.subset_fdcount, plan.fdmap, + fontSzr, plan.privateDictInfos))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray"); + return false; + } + } + + /* CharStrings */ + { + assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); + CFF2CharStrings *cs = c.start_embed<CFF2CharStrings> (); + if (unlikely (cs == nullptr)) return false; + if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings"); + return false; + } + } + + /* private dicts & local subrs */ + assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start)); + for (unsigned int i = 0; i < acc.privateDicts.length; i++) + { + if (plan.fdmap.includes (i)) + { + PrivateDict *pd = c.start_embed<PrivateDict> (); + if (unlikely (pd == nullptr)) return false; + unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size; + bool result; + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; + result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); + if (unlikely (!result)) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); + return false; + } + if (plan.offsets.localSubrsInfos[i].size > 0) + { + CFF2Subrs *dest = c.start_embed <CFF2Subrs> (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) + { + DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); + return false; + } + } + } + } + + assert (c.head == c.end); + c.end_serialize (); + + return true; +} + +static bool +_hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, + const char *data, + hb_subset_plan_t *plan, + hb_blob_t **prime /* OUT */) +{ + cff2_subset_plan cff2_plan; + + if (unlikely (!cff2_plan.create (acc, plan))) + { + DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan."); + return false; + } + + unsigned int cff2_prime_size = cff2_plan.get_final_size (); + char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); + + if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs, + cff2_prime_size, cff2_prime_data))) { + DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); + free (cff2_prime_data); + return false; + } + + *prime = hb_blob_create (cff2_prime_data, + cff2_prime_size, + HB_MEMORY_MODE_READONLY, + cff2_prime_data, + free); + return true; +} + +/** + * hb_subset_cff2: + * Subsets the CFF2 table according to a provided plan. + * + * Return value: subsetted cff2 table. + **/ +bool +hb_subset_cff2 (hb_subset_plan_t *plan, + hb_blob_t **prime /* OUT */) +{ + hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source); + const char *data = hb_blob_get_data(cff2_blob, nullptr); + + OT::cff2::accelerator_subset_t acc; + acc.init(plan->source); + bool result = likely (acc.is_valid ()) && + _hb_subset_cff2 (acc, data, plan, prime); + + hb_blob_destroy (cff2_blob); + acc.fini (); + + return result; +} diff --git a/src/hb-subset-cff2.hh b/src/hb-subset-cff2.hh new file mode 100644 index 0000000..a07dc29 --- /dev/null +++ b/src/hb-subset-cff2.hh @@ -0,0 +1,38 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_SUBSET_CFF2_HH +#define HB_SUBSET_CFF2_HH + +#include "hb.hh" + +#include "hb-subset-plan.hh" + +HB_INTERNAL bool +hb_subset_cff2 (hb_subset_plan_t *plan, + hb_blob_t **cff2_prime /* OUT */); + +#endif /* HB_SUBSET_CFF2_HH */ diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index c8fa39b..cca364d 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -24,38 +24,37 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-glyf-table.hh" #include "hb-set.h" #include "hb-subset-glyf.hh" -#include "hb-subset-plan.hh" static bool _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, - hb_vector_t<hb_codepoint_t> &glyph_ids, - hb_bool_t drop_hints, - bool *use_short_loca /* OUT */, - unsigned int *glyf_size /* OUT */, - unsigned int *loca_size /* OUT */, - hb_vector_t<unsigned int> *instruction_ranges /* OUT */) + hb_vector_t<hb_codepoint_t> &glyph_ids, + hb_bool_t drop_hints, + bool *use_short_loca /* OUT */, + unsigned int *glyf_size /* OUT */, + unsigned int *loca_size /* OUT */, + hb_vector_t<unsigned int> *instruction_ranges /* OUT */) { unsigned int total = 0; - for (unsigned int i = 0; i < glyph_ids.len; i++) + for (unsigned int i = 0; i < glyph_ids.length; i++) { hb_codepoint_t next_glyph = glyph_ids[i]; - if (!instruction_ranges->resize (instruction_ranges->len + 2)) + if (!instruction_ranges->resize (instruction_ranges->length + 2)) { DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); return false; } - unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->len - 2]; + unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2]; *instruction_start = 0; - unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->len - 1]; + unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1]; *instruction_end = 0; unsigned int start_offset, end_offset; - if (unlikely (!(glyf.get_offsets(next_glyph, &start_offset, &end_offset) - && glyf.remove_padding(start_offset, &end_offset)))) + if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) && + glyf.remove_padding (start_offset, &end_offset)))) { DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph); continue; @@ -65,11 +64,11 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, if (drop_hints) { - if (unlikely (!glyf.get_instruction_offsets(start_offset, end_offset, - instruction_start, instruction_end))) + if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset, + instruction_start, instruction_end))) { - DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph); - return false; + DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph); + return false; } } @@ -80,22 +79,22 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, *glyf_size = total; *use_short_loca = (total <= 131070); - *loca_size = (glyph_ids.len + 1) - * (*use_short_loca ? sizeof(OT::HBUINT16) : sizeof(OT::HBUINT32)); + *loca_size = (glyph_ids.length + 1) + * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", - total, - *loca_size, - *use_short_loca ? "short" : "long"); + total, + *loca_size, + *use_short_loca ? "short" : "long"); return true; } static bool _write_loca_entry (unsigned int id, - unsigned int offset, - bool is_short, - void *loca_prime, - unsigned int loca_size) + unsigned int offset, + bool is_short, + void *loca_prime, + unsigned int loca_size) { unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32); if ((id + 1) * entry_size <= loca_size) @@ -109,11 +108,11 @@ _write_loca_entry (unsigned int id, } // Offset was not written because the write is out of bounds. - DEBUG_MSG (SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.", - id, - loca_size); + DEBUG_MSG(SUBSET, + nullptr, + "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.", + id, + loca_size); return false; } @@ -131,15 +130,15 @@ _update_components (hb_subset_plan_t * plan, { hb_codepoint_t new_gid; if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex, - &new_gid)) + &new_gid)) continue; ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid); - } while (iterator.move_to_next()); + } while (iterator.move_to_next ()); } } -static bool _remove_composite_instruction_flag(char *glyf_prime, unsigned int length) +static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int length) { /* remove WE_HAVE_INSTRUCTIONS from flags in dest */ OT::glyf::CompositeGlyphHeader::Iterator composite_it; @@ -149,30 +148,30 @@ static bool _remove_composite_instruction_flag(char *glyf_prime, unsigned int le glyph = composite_it.current; OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags); flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS); - } while (composite_it.move_to_next()); + } while (composite_it.move_to_next ()); return true; } static bool _write_glyf_and_loca_prime (hb_subset_plan_t *plan, const OT::glyf::accelerator_t &glyf, - const char *glyf_data, - bool use_short_loca, - hb_vector_t<unsigned int> &instruction_ranges, - unsigned int glyf_prime_size, - char *glyf_prime_data /* OUT */, - unsigned int loca_prime_size, - char *loca_prime_data /* OUT */) + const char *glyf_data, + bool use_short_loca, + hb_vector_t<unsigned int> &instruction_ranges, + unsigned int glyf_prime_size, + char *glyf_prime_data /* OUT */, + unsigned int loca_prime_size, + char *loca_prime_data /* OUT */) { hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs; char *glyf_prime_data_next = glyf_prime_data; bool success = true; - for (unsigned int i = 0; i < glyph_ids.len; i++) + for (unsigned int i = 0; i < glyph_ids.length; i++) { unsigned int start_offset, end_offset; - if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) - && glyf.remove_padding(start_offset, &end_offset)))) + if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && + glyf.remove_padding (start_offset, &end_offset)))) end_offset = start_offset = 0; unsigned int instruction_start = instruction_ranges[i * 2]; @@ -182,10 +181,10 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan, if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size) { - DEBUG_MSG (SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)", - i, length); + DEBUG_MSG(SUBSET, + nullptr, + "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)", + i, length); return false; } @@ -198,39 +197,39 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan, /* if the instructions end at the end this was a composite glyph, else simple */ if (instruction_end == end_offset) { - if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false; + if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false; } else - /* zero instruction length, which is just before instruction_start */ - memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); + /* zero instruction length, which is just before instruction_start */ + memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); } success = success && _write_loca_entry (i, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); + glyf_prime_data_next - glyf_prime_data, + use_short_loca, + loca_prime_data, + loca_prime_size); _update_components (plan, glyf_prime_data_next, length); // TODO: don't align to two bytes if using long loca. glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. } - success = success && _write_loca_entry (glyph_ids.len, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); + success = success && _write_loca_entry (glyph_ids.length, + glyf_prime_data_next - glyf_prime_data, + use_short_loca, + loca_prime_data, + loca_prime_size); return success; } static bool _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, - const char *glyf_data, - hb_subset_plan_t *plan, - bool *use_short_loca, - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */) + const char *glyf_data, + hb_subset_plan_t *plan, + bool *use_short_loca, + hb_blob_t **glyf_prime /* OUT */, + hb_blob_t **loca_prime /* OUT */) { // TODO(grieger): Sanity check allocation size for the new table. hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs; @@ -238,43 +237,43 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, unsigned int glyf_prime_size; unsigned int loca_prime_size; hb_vector_t<unsigned int> instruction_ranges; - instruction_ranges.init(); + instruction_ranges.init (); if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, - glyphs_to_retain, - plan->drop_hints, - use_short_loca, - &glyf_prime_size, - &loca_prime_size, - &instruction_ranges))) { - instruction_ranges.fini(); + glyphs_to_retain, + plan->drop_hints, + use_short_loca, + &glyf_prime_size, + &loca_prime_size, + &instruction_ranges))) { + instruction_ranges.fini (); return false; } char *glyf_prime_data = (char *) calloc (1, glyf_prime_size); char *loca_prime_data = (char *) calloc (1, loca_prime_size); if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data, - *use_short_loca, - instruction_ranges, - glyf_prime_size, glyf_prime_data, - loca_prime_size, loca_prime_data))) { + *use_short_loca, + instruction_ranges, + glyf_prime_size, glyf_prime_data, + loca_prime_size, loca_prime_data))) { free (glyf_prime_data); free (loca_prime_data); - instruction_ranges.fini(); + instruction_ranges.fini (); return false; } - instruction_ranges.fini(); + instruction_ranges.fini (); *glyf_prime = hb_blob_create (glyf_prime_data, - glyf_prime_size, - HB_MEMORY_MODE_READONLY, - glyf_prime_data, - free); + glyf_prime_size, + HB_MEMORY_MODE_READONLY, + glyf_prime_data, + free); *loca_prime = hb_blob_create (loca_prime_data, - loca_prime_size, - HB_MEMORY_MODE_READONLY, - loca_prime_data, - free); + loca_prime_size, + HB_MEMORY_MODE_READONLY, + loca_prime_data, + free); return true; } @@ -288,24 +287,24 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, **/ bool hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime, /* OUT */ - hb_blob_t **loca_prime /* OUT */) + bool *use_short_loca, /* OUT */ + hb_blob_t **glyf_prime, /* OUT */ + hb_blob_t **loca_prime /* OUT */) { - hb_blob_t *glyf_blob = OT::Sanitizer<OT::glyf>().sanitize (plan->source->reference_table (HB_OT_TAG_glyf)); - const char *glyf_data = hb_blob_get_data(glyf_blob, nullptr); + hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table<OT::glyf> (plan->source); + const char *glyf_data = hb_blob_get_data (glyf_blob, nullptr); OT::glyf::accelerator_t glyf; - glyf.init(plan->source); + glyf.init (plan->source); bool result = _hb_subset_glyf_and_loca (glyf, - glyf_data, - plan, - use_short_loca, - glyf_prime, - loca_prime); + glyf_data, + plan, + use_short_loca, + glyf_prime, + loca_prime); hb_blob_destroy (glyf_blob); - glyf.fini(); + glyf.fini (); return result; } diff --git a/src/hb-subset-glyf.hh b/src/hb-subset-glyf.hh index 99b76db..99cf8f0 100644 --- a/src/hb-subset-glyf.hh +++ b/src/hb-subset-glyf.hh @@ -27,14 +27,14 @@ #ifndef HB_SUBSET_GLYF_HH #define HB_SUBSET_GLYF_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-subset-plan.hh" +#include "hb-subset.hh" HB_INTERNAL bool hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */); + bool *use_short_loca, /* OUT */ + hb_blob_t **glyf_prime /* OUT */, + hb_blob_t **loca_prime /* OUT */); #endif /* HB_SUBSET_GLYF_HH */ diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 39c5ac4..f718a56 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -24,9 +24,8 @@ * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod */ -#include "hb-object-private.hh" -#include "hb-subset-private.hh" -#include "hb-set-private.hh" +#include "hb-subset.hh" +#include "hb-set.hh" /** * hb_subset_input_create_or_fail: @@ -36,7 +35,7 @@ * Since: 1.8.0 **/ hb_subset_input_t * -hb_subset_input_create_or_fail (void) +hb_subset_input_create_or_fail () { hb_subset_input_t *input = hb_object_create<hb_subset_input_t>(); @@ -45,7 +44,7 @@ hb_subset_input_create_or_fail (void) input->unicodes = hb_set_create (); input->glyphs = hb_set_create (); - input->drop_ot_layout = true; + input->drop_layout = true; return input; } @@ -73,7 +72,7 @@ hb_subset_input_reference (hb_subset_input_t *subset_input) * Since: 1.8.0 **/ void -hb_subset_input_destroy(hb_subset_input_t *subset_input) +hb_subset_input_destroy (hb_subset_input_t *subset_input) { if (!hb_object_destroy (subset_input)) return; @@ -107,30 +106,41 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input) return subset_input->glyphs; } -/** - * hb_subset_input_drop_hints: - * @subset_input: a subset_input. - * - * Since: 1.8.0 - **/ -HB_EXTERN hb_bool_t * -hb_subset_input_drop_hints (hb_subset_input_t *subset_input) +HB_EXTERN void +hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, + hb_bool_t drop_hints) { - return &subset_input->drop_hints; + subset_input->drop_hints = drop_hints; } -/** - * hb_subset_input_drop_ot_layout: - * @subset_input: a subset_input. - * - * If enabled ot layout tables will be dropped as part of - * the subsetting operation. Currently this defaults to - * true. - * - * Since: REPLACEME - **/ -HB_EXTERN hb_bool_t * -hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input) +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input) +{ + return subset_input->drop_hints; +} + +HB_EXTERN void +hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, + hb_bool_t drop_layout) +{ + subset_input->drop_layout = drop_layout; +} + +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input) +{ + return subset_input->drop_layout; +} + +HB_EXTERN void +hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, + hb_bool_t desubroutinize) +{ + subset_input->desubroutinize = desubroutinize; +} + +HB_EXTERN hb_bool_t +hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input) { - return &subset_input->drop_ot_layout; + return subset_input->desubroutinize; } diff --git a/src/hb-subset-private.hh b/src/hb-subset-input.hh index 6b2b207..8dad94f 100644 --- a/src/hb-subset-private.hh +++ b/src/hb-subset-input.hh @@ -24,27 +24,26 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#ifndef HB_SUBSET_PRIVATE_HH -#define HB_SUBSET_PRIVATE_HH +#ifndef HB_SUBSET_INPUT_HH +#define HB_SUBSET_INPUT_HH -#include "hb-private.hh" +#include "hb.hh" #include "hb-subset.h" -#include "hb-font-private.hh" +#include "hb-font.hh" -typedef struct hb_subset_face_data_t hb_subset_face_data_t; - -struct hb_subset_input_t { +struct hb_subset_input_t +{ hb_object_header_t header; - ASSERT_POD (); hb_set_t *unicodes; hb_set_t *glyphs; - hb_bool_t drop_hints; - hb_bool_t drop_ot_layout; + bool drop_hints : 1; + bool drop_layout : 1; + bool desubroutinize : 1; /* TODO * * features @@ -54,10 +53,5 @@ struct hb_subset_input_t { */ }; -HB_INTERNAL hb_face_t * -hb_subset_face_create (void); - -HB_INTERNAL hb_bool_t -hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob); -#endif /* HB_SUBSET_PRIVATE_HH */ +#endif /* HB_SUBSET_INPUT_HH */ diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 55c4e3f..cff3426 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -24,13 +24,13 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#include "hb-map-private.hh" -#include "hb-subset-private.hh" -#include "hb-set-private.hh" - #include "hb-subset-plan.hh" +#include "hb-map.hh" +#include "hb-set.hh" + #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" static void _add_gid_and_children (const OT::glyf::accelerator_t &glyf, @@ -54,29 +54,59 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, } static void +_add_cff_seac_components (const OT::cff1::accelerator_t &cff, + hb_codepoint_t gid, + hb_set_t *gids_to_retain) +{ + hb_codepoint_t base_gid, accent_gid; + if (cff.get_seac_components (gid, &base_gid, &accent_gid)) + { + hb_set_add (gids_to_retain, base_gid); + hb_set_add (gids_to_retain, accent_gid); + } +} + +static void _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) { - // TODO(grieger): This uses all lookups, instead collect - // the set of lookups that are relevant. - // See fontTools implementation. + hb_set_t lookup_indices; + hb_ot_layout_collect_lookups (face, + HB_OT_TAG_GSUB, + nullptr, + nullptr, + nullptr, + &lookup_indices); hb_ot_layout_lookups_substitute_closure (face, - nullptr, - gids_to_retain); + &lookup_indices, + gids_to_retain); } - static void +_remove_invalid_gids (hb_set_t *glyphs, + unsigned int num_glyphs) +{ + hb_codepoint_t gid = HB_SET_VALUE_INVALID; + while (glyphs->next (&gid)) + { + if (gid >= num_glyphs) + glyphs->del (gid); + } +} + +static hb_set_t * _populate_gids_to_retain (hb_face_t *face, - const hb_set_t *unicodes, - bool close_over_gsub, - hb_set_t *unicodes_to_retain, - hb_map_t *codepoint_to_glyph, - hb_vector_t<hb_codepoint_t> *glyphs) + const hb_set_t *unicodes, + bool close_over_gsub, + hb_set_t *unicodes_to_retain, + hb_map_t *codepoint_to_glyph, + hb_vector_t<hb_codepoint_t> *glyphs) { OT::cmap::accelerator_t cmap; OT::glyf::accelerator_t glyf; + OT::cff1::accelerator_t cff; cmap.init (face); glyf.init (face); + cff.init (face); hb_set_t *initial_gids_to_retain = hb_set_create (); initial_gids_to_retain->add (0); // Not-def @@ -106,24 +136,30 @@ _populate_gids_to_retain (hb_face_t *face, while (initial_gids_to_retain->next (&gid)) { _add_gid_and_children (glyf, gid, all_gids_to_retain); + if (cff.is_valid ()) + _add_cff_seac_components (cff, gid, all_gids_to_retain); } hb_set_destroy (initial_gids_to_retain); + _remove_invalid_gids (all_gids_to_retain, face->get_num_glyphs ()); + glyphs->alloc (all_gids_to_retain->get_population ()); gid = HB_SET_VALUE_INVALID; while (all_gids_to_retain->next (&gid)) glyphs->push (gid); - hb_set_destroy (all_gids_to_retain); + cff.fini (); glyf.fini (); cmap.fini (); + + return all_gids_to_retain; } static void _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, - hb_map_t *glyph_map) + hb_map_t *glyph_map) { - for (unsigned int i = 0; i < glyphs.len; i++) { + for (unsigned int i = 0; i < glyphs.length; i++) { glyph_map->set (glyphs[i], i); } } @@ -131,7 +167,7 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, /** * hb_subset_plan_create: * Computes a plan for subsetting the supplied face according - * to a provide profile and input. The plan describes + * to a provided input. The plan describes * which tables and glyphs should be retained. * * Return value: New subset plan. @@ -140,28 +176,27 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, **/ hb_subset_plan_t * hb_subset_plan_create (hb_face_t *face, - hb_subset_profile_t *profile, - hb_subset_input_t *input) + hb_subset_input_t *input) { hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> (); plan->drop_hints = input->drop_hints; - plan->drop_ot_layout = input->drop_ot_layout; + plan->drop_layout = input->drop_layout; + plan->desubroutinize = input->desubroutinize; plan->unicodes = hb_set_create(); plan->glyphs.init(); plan->source = hb_face_reference (face); - plan->dest = hb_subset_face_create (); + plan->dest = hb_face_builder_create (); plan->codepoint_to_glyph = hb_map_create(); plan->glyph_map = hb_map_create(); - - _populate_gids_to_retain (face, - input->unicodes, - !plan->drop_ot_layout, - plan->unicodes, - plan->codepoint_to_glyph, - &plan->glyphs); + plan->glyphset = _populate_gids_to_retain (face, + input->unicodes, + !plan->drop_layout, + plan->unicodes, + plan->codepoint_to_glyph, + &plan->glyphs); _create_old_gid_to_new_gid_map (plan->glyphs, - plan->glyph_map); + plan->glyph_map); return plan; } @@ -177,11 +212,12 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); - plan->glyphs.fini(); + plan->glyphs.fini (); hb_face_destroy (plan->source); hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); + hb_set_destroy (plan->glyphset); free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index f4b261d..a710a4d 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -27,28 +27,26 @@ #ifndef HB_SUBSET_PLAN_HH #define HB_SUBSET_PLAN_HH -#include "hb-private.hh" +#include "hb.hh" #include "hb-subset.h" -#include "hb-subset-private.hh" +#include "hb-subset-input.hh" -#include "hb-object-private.hh" -#include "hb-map-private.hh" +#include "hb-map.hh" struct hb_subset_plan_t { hb_object_header_t header; - ASSERT_POD (); - hb_bool_t drop_hints; - hb_bool_t drop_ot_layout; + bool drop_hints : 1; + bool drop_layout : 1; + bool desubroutinize : 1; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; - // This list contains the complete set of glyphs to retain and may contain - // more glyphs then the lists above. hb_vector_t<hb_codepoint_t> glyphs; + hb_set_t *glyphset; hb_map_t *codepoint_to_glyph; hb_map_t *glyph_map; @@ -57,9 +55,8 @@ struct hb_subset_plan_t hb_face_t *source; hb_face_t *dest; - inline hb_bool_t - new_gid_for_codepoint (hb_codepoint_t codepoint, - hb_codepoint_t *new_gid) const + bool new_gid_for_codepoint (hb_codepoint_t codepoint, + hb_codepoint_t *new_gid) const { hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); if (old_gid == HB_MAP_VALUE_INVALID) @@ -68,9 +65,8 @@ struct hb_subset_plan_t return new_gid_for_old_gid (old_gid, new_gid); } - inline hb_bool_t - new_gid_for_old_gid (hb_codepoint_t old_gid, - hb_codepoint_t *new_gid) const + bool new_gid_for_old_gid (hb_codepoint_t old_gid, + hb_codepoint_t *new_gid) const { hb_codepoint_t gid = glyph_map->get (old_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -80,17 +76,17 @@ struct hb_subset_plan_t return true; } - inline hb_bool_t + bool add_table (hb_tag_t tag, - hb_blob_t *contents) + hb_blob_t *contents) { hb_blob_t *source_blob = source->reference_table (tag); DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes", - HB_UNTAG(tag), - hb_blob_get_length (contents), - hb_blob_get_length (source_blob)); + HB_UNTAG(tag), + hb_blob_get_length (contents), + hb_blob_get_length (source_blob)); hb_blob_destroy (source_blob); - return hb_subset_face_add_table(dest, tag, contents); + return hb_face_builder_add_table (dest, tag, contents); } }; @@ -98,7 +94,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; HB_INTERNAL hb_subset_plan_t * hb_subset_plan_create (hb_face_t *face, - hb_subset_profile_t *profile, hb_subset_input_t *input); HB_INTERNAL void diff --git a/src/hb-subset.cc b/src/hb-subset.cc index b97c763..37e7cec 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -24,15 +24,13 @@ * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-object-private.hh" -#include "hb-open-type-private.hh" +#include "hb.hh" +#include "hb-open-type.hh" +#include "hb-subset.hh" #include "hb-subset-glyf.hh" -#include "hb-subset-private.hh" -#include "hb-subset-plan.hh" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-hdmx-table.hh" @@ -42,197 +40,106 @@ #include "hb-ot-maxp-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-ot-vorg-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" -struct hb_subset_profile_t { - hb_object_header_t header; - ASSERT_POD (); -}; - -/** - * hb_subset_profile_create: - * - * Return value: New profile with default settings. - * - * Since: 1.8.0 - **/ -hb_subset_profile_t * -hb_subset_profile_create () +static unsigned int +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, + unsigned int table_len) { - return hb_object_create<hb_subset_profile_t>(); -} + unsigned int src_glyphs = plan->source->get_num_glyphs (); + unsigned int dst_glyphs = plan->glyphset->get_population (); -/** - * hb_subset_profile_destroy: - * - * Since: 1.8.0 - **/ -void -hb_subset_profile_destroy (hb_subset_profile_t *profile) -{ - if (!hb_object_destroy (profile)) return; + if (unlikely (!src_glyphs)) + return 512 + table_len; - free (profile); + return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); } template<typename TableType> static bool -_subset (hb_subset_plan_t *plan) +_subset2 (hb_subset_plan_t *plan) { - OT::Sanitizer<TableType> sanitizer; - - hb_blob_t *source_blob = sanitizer.sanitize (plan->source->reference_table (TableType::tableTag)); + hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); const TableType *table = source_blob->as<TableType> (); hb_tag_t tag = TableType::tableTag; hb_bool_t result = false; - if (table != &Null(TableType)) - { - result = table->subset(plan); - } else { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag)); - } - - hb_blob_destroy (source_blob); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!"); - return result; -} - - -/* - * A face that has add_table(). - */ - -struct hb_subset_face_data_t -{ - struct table_entry_t + if (source_blob->data) { - inline int cmp (const hb_tag_t *t) const + hb_vector_t<char> buf; + unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) { - if (*t < tag) return -1; - if (*t > tag) return -1; - return 0; + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + return false; + } + retry: + hb_serialize_context_t serializer ((void *) buf, buf_size); + hb_subset_context_t c (plan, &serializer); + result = table->subset (&c); + if (serializer.in_error ()) + { + buf_size += (buf_size >> 1) + 32; + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size); + return false; + } + goto retry; + } + if (result) + { + hb_blob_t *dest_blob = serializer.copy_blob (); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); + result = c.plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + else + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + result = true; } - - hb_tag_t tag; - hb_blob_t *blob; - }; - - hb_vector_t<table_entry_t, 32> tables; -}; - -static hb_subset_face_data_t * -_hb_subset_face_data_create (void) -{ - hb_subset_face_data_t *data = (hb_subset_face_data_t *) calloc (1, sizeof (hb_subset_face_data_t)); - if (unlikely (!data)) - return nullptr; - - data->tables.init (); - - return data; -} - -static void -_hb_subset_face_data_destroy (void *user_data) -{ - hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data; - - for (unsigned int i = 0; i < data->tables.len; i++) - hb_blob_destroy (data->tables[i].blob); - - data->tables.fini (); - - free (data); -} - -static hb_blob_t * -_hb_subset_face_data_reference_blob (hb_subset_face_data_t *data) -{ - - unsigned int table_count = data->tables.len; - unsigned int face_length = table_count * 16 + 12; - - for (unsigned int i = 0; i < table_count; i++) - face_length += _hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob)); - - char *buf = (char *) malloc (face_length); - if (unlikely (!buf)) - return nullptr; - - OT::hb_serialize_context_t c (buf, face_length); - OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> (); - - bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2')); - hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; - - OT::Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0])); - OT::Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0])); - bool ret = f->serialize_single (&c, - sfnt_tag, - tags_supplier, - blobs_supplier, - table_count); - - c.end_serialize (); - - if (unlikely (!ret)) - { - free (buf); - return nullptr; } + else + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free); + hb_blob_destroy (source_blob); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); + return result; } -static hb_blob_t * -_hb_subset_face_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data) +template<typename TableType> +static bool +_subset (hb_subset_plan_t *plan) { - hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data; - - if (!tag) - return _hb_subset_face_data_reference_blob (data); - - hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag); - if (entry) - return hb_blob_reference (entry->blob); - - return nullptr; -} + hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); + const TableType *table = source_blob->as<TableType> (); -/* TODO: Move this to hb-face.h and rename to hb_face_builder_create() - * with hb_face_builder_add_table(). */ -hb_face_t * -hb_subset_face_create (void) -{ - hb_subset_face_data_t *data = _hb_subset_face_data_create (); - if (unlikely (!data)) return hb_face_get_empty (); + hb_tag_t tag = TableType::tableTag; + hb_bool_t result = false; + if (source_blob->data) + result = table->subset (plan); + else + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - return hb_face_create_for_tables (_hb_subset_face_reference_table, - data, - _hb_subset_face_data_destroy); + hb_blob_destroy (source_blob); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); + return result; } -hb_bool_t -hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) -{ - if (unlikely (face->destroy != (hb_destroy_func_t) _hb_subset_face_data_destroy)) - return false; - - hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data; - hb_subset_face_data_t::table_entry_t *entry = data->tables.push (); - - entry->tag = tag; - entry->blob = hb_blob_reference (blob); - - return true; -} static bool _subset_table (hb_subset_plan_t *plan, - hb_tag_t tag) + hb_tag_t tag) { - DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG(tag)); + DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag)); bool result = true; switch (tag) { case HB_OT_TAG_glyf: @@ -267,27 +174,46 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_cmap: result = _subset<const OT::cmap> (plan); break; - case HB_OT_TAG_os2: - result = _subset<const OT::os2> (plan); + case HB_OT_TAG_OS2: + result = _subset<const OT::OS2> (plan); break; case HB_OT_TAG_post: result = _subset<const OT::post> (plan); break; + case HB_OT_TAG_cff1: + result = _subset<const OT::cff1> (plan); + break; + case HB_OT_TAG_cff2: + result = _subset<const OT::cff2> (plan); + break; + case HB_OT_TAG_VORG: + result = _subset<const OT::VORG> (plan); + break; + case HB_OT_TAG_GDEF: + result = _subset2<const OT::GDEF> (plan); + break; + case HB_OT_TAG_GSUB: + result = _subset2<const OT::GSUB> (plan); + break; + case HB_OT_TAG_GPOS: + result = _subset2<const OT::GPOS> (plan); + break; + default: - hb_blob_t *source_table = hb_face_reference_table(plan->source, tag); + hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); if (likely (source_table)) - result = plan->add_table(tag, source_table); + result = plan->add_table (tag, source_table); else - result = false; + result = false; hb_blob_destroy (source_table); break; } - DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG(tag), result ? "ok" : "FAILED"); + DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED"); return result; } static bool -_should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag) +_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) { switch (tag) { case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */ @@ -298,10 +224,10 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag) case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */ return plan->drop_hints; // Drop Layout Tables if requested. - case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */ - case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */ - case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */ - return plan->drop_ot_layout; + case HB_OT_TAG_GDEF: + case HB_OT_TAG_GPOS: + case HB_OT_TAG_GSUB: + return plan->drop_layout; // Drop these tables below by default, list pulled // from fontTools: case HB_TAG ('B', 'A', 'S', 'E'): @@ -330,19 +256,17 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag) /** * hb_subset: * @source: font face data to be subset. - * @profile: profile to use for the subsetting. * @input: input to use for the subsetting. * - * Subsets a font according to provided profile and input. + * Subsets a font according to provided input. **/ hb_face_t * hb_subset (hb_face_t *source, - hb_subset_profile_t *profile, - hb_subset_input_t *input) + hb_subset_input_t *input) { - if (unlikely (!profile || !input || !source)) return hb_face_get_empty(); + if (unlikely (!input || !source)) return hb_face_get_empty (); - hb_subset_plan_t *plan = hb_subset_plan_create (source, profile, input); + hb_subset_plan_t *plan = hb_subset_plan_create (source, input); hb_tag_t table_tags[32]; unsigned int offset = 0, count; @@ -353,31 +277,17 @@ hb_subset (hb_face_t *source, for (unsigned int i = 0; i < count; i++) { hb_tag_t tag = table_tags[i]; - if (_should_drop_table(plan, tag)) + if (_should_drop_table (plan, tag)) { - DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG(tag)); - continue; + DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag)); + continue; } success = success && _subset_table (plan, tag); } offset += count; - } while (count == ARRAY_LENGTH (table_tags)); + } while (success && count == ARRAY_LENGTH (table_tags)); - hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty(); + hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty (); hb_subset_plan_destroy (plan); return result; } - -/** - * hb_subset_get_all_codepoints: - * @source: font face data to load. - * @out: set to add the all codepoints covered by font face, source. - */ -void -hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out) -{ - OT::cmap::accelerator_t cmap; - cmap.init (source); - cmap.get_all_codepoints (out); - cmap.fini(); -} diff --git a/src/hb-subset.h b/src/hb-subset.h index f6d2ae0..f582e46 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -32,20 +32,6 @@ HB_BEGIN_DECLS /* - * hb_subset_profile_t - * Things that change based on target environment, e.g. OS. - * Threadsafe for multiple concurrent subset operations. - */ - -typedef struct hb_subset_profile_t hb_subset_profile_t; - -HB_EXTERN hb_subset_profile_t * -hb_subset_profile_create (void); - -HB_EXTERN void -hb_subset_profile_destroy (hb_subset_profile_t *profile); - -/* * hb_subset_input_t * * Things that change based on the input. Characters to keep, etc. @@ -68,21 +54,28 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input); HB_EXTERN hb_set_t * hb_subset_input_glyph_set (hb_subset_input_t *subset_input); -HB_EXTERN hb_bool_t * -hb_subset_input_drop_hints (hb_subset_input_t *subset_input); +HB_EXTERN void +hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, + hb_bool_t drop_hints); +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input); + +HB_EXTERN void +hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, + hb_bool_t drop_layout); +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input); -HB_EXTERN hb_bool_t * -hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input); +HB_EXTERN void +hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, + hb_bool_t desubroutinize); +HB_EXTERN hb_bool_t +hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); -/* hb_subset() */ +/* hb_subset () */ HB_EXTERN hb_face_t * -hb_subset (hb_face_t *source, - hb_subset_profile_t *profile, - hb_subset_input_t *input); +hb_subset (hb_face_t *source, hb_subset_input_t *input); -/* hb_subset_get_all_codepoints */ -HB_EXTERN void -hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out); HB_END_DECLS diff --git a/src/hb-subset.hh b/src/hb-subset.hh new file mode 100644 index 0000000..45cb763 --- /dev/null +++ b/src/hb-subset.hh @@ -0,0 +1,59 @@ +/* + * Copyright © 2018 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, Roderick Sheeter + */ + +#ifndef HB_SUBSET_HH +#define HB_SUBSET_HH + + +#include "hb.hh" + +#include "hb-subset.h" + +#include "hb-machinery.hh" +#include "hb-subset-input.hh" +#include "hb-subset-plan.hh" + +struct hb_subset_context_t : + hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET> +{ + const char *get_name () { return "SUBSET"; } + template <typename T> + bool dispatch (const T &obj) { return obj.subset (this); } + static bool default_return_value () { return true; } + + hb_subset_plan_t *plan; + hb_serialize_context_t *serializer; + unsigned int debug_depth; + + hb_subset_context_t (hb_subset_plan_t *plan_, + hb_serialize_context_t *serializer_) : + plan (plan_), + serializer (serializer_), + debug_depth (0) {} +}; + + +#endif /* HB_SUBSET_HH */ diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc index 2c08718..534935f 100644 --- a/src/hb-ucdn.cc +++ b/src/hb-ucdn.cc @@ -14,9 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-unicode-private.hh" +#include "hb-machinery.hh" #include "ucdn.h" @@ -181,15 +181,6 @@ hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode); } -static unsigned int -hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - int w = ucdn_get_east_asian_width(unicode); - return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1; -} - static hb_unicode_general_category_t hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -230,56 +221,48 @@ hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED, return ucdn_decompose(ab, a, b); } -static unsigned int -hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ - return ucdn_compat_decompose(u, decomposed); -} -static hb_unicode_funcs_t *static_ucdn_funcs = nullptr; - -#ifdef HB_USE_ATEXIT -static -void free_static_ucdn_funcs (void) -{ -retry: - hb_unicode_funcs_t *ucdn_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, ucdn_funcs, nullptr)) - goto retry; - - hb_unicode_funcs_destroy (ucdn_funcs); -} +#if HB_USE_ATEXIT +static void free_static_ucdn_funcs (); #endif -extern "C" HB_INTERNAL -hb_unicode_funcs_t * -hb_ucdn_get_unicode_funcs (void) +static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t> { -retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs); - - if (unlikely (!funcs)) + static hb_unicode_funcs_t *create () { - funcs = hb_unicode_funcs_create (nullptr); + hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT + hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr); hb_unicode_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, nullptr, funcs)) { - hb_unicode_funcs_destroy (funcs); - goto retry; - } +#if HB_USE_ATEXIT + atexit (free_static_ucdn_funcs); +#endif + + return funcs; + } +} static_ucdn_funcs; -#ifdef HB_USE_ATEXIT - atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */ +#if HB_USE_ATEXIT +static +void free_static_ucdn_funcs () +{ + static_ucdn_funcs.free_instance (); +} #endif - }; - return hb_unicode_funcs_reference (funcs); +extern "C" HB_INTERNAL +hb_unicode_funcs_t * +hb_ucdn_get_unicode_funcs (); + +hb_unicode_funcs_t * +hb_ucdn_get_unicode_funcs () +{ + return static_ucdn_funcs.get_unconst (); } diff --git a/src/hb-ucdn/Makefile.in b/src/hb-ucdn/Makefile.in index 59bbf55..9529940 100644 --- a/src/hb-ucdn/Makefile.in +++ b/src/hb-ucdn/Makefile.in @@ -95,8 +95,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.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 + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) @@ -294,6 +293,8 @@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h index 9b0f9d4..05d46d2 100644 --- a/src/hb-ucdn/ucdn.h +++ b/src/hb-ucdn/ucdn.h @@ -456,8 +456,6 @@ int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed); */ int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b); -#ifdef __cplusplus -} -#endif +HB_END_HEADER #endif diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh new file mode 100644 index 0000000..1dd0b32 --- /dev/null +++ b/src/hb-unicode-emoji-table.hh @@ -0,0 +1,110 @@ +/* == Start of generated table == */ +/* + * The following tables are generated by running: + * + * ./gen-emoji-table.py emoji-data.txt + * + * on file with this header: + * + * # emoji-data.txt + * # Date: 2018-02-07, 07:55:18 GMT + * # © 2018 Unicode®, Inc. + * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. + * # For terms of use, see http://www.unicode.org/terms_of_use.html + * # + * # Emoji Data for UTS #51 + * # Version: 11.0 + * # + * # For documentation and usage, see http://www.unicode.org/reports/tr51 + */ + +#ifndef HB_UNICODE_EMOJI_TABLE_HH +#define HB_UNICODE_EMOJI_TABLE_HH + +#include "hb-unicode.hh" + + +static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] = +{ + {0x00A9, 0x00A9}, + {0x00AE, 0x00AE}, + {0x203C, 0x203C}, + {0x2049, 0x2049}, + {0x2122, 0x2122}, + {0x2139, 0x2139}, + {0x2194, 0x2199}, + {0x21A9, 0x21AA}, + {0x231A, 0x231B}, + {0x2328, 0x2328}, + {0x2388, 0x2388}, + {0x23CF, 0x23CF}, + {0x23E9, 0x23F3}, + {0x23F8, 0x23FA}, + {0x24C2, 0x24C2}, + {0x25AA, 0x25AB}, + {0x25B6, 0x25B6}, + {0x25C0, 0x25C0}, + {0x25FB, 0x25FE}, + {0x2600, 0x2605}, + {0x2607, 0x2612}, + {0x2614, 0x2685}, + {0x2690, 0x2705}, + {0x2708, 0x2712}, + {0x2714, 0x2714}, + {0x2716, 0x2716}, + {0x271D, 0x271D}, + {0x2721, 0x2721}, + {0x2728, 0x2728}, + {0x2733, 0x2734}, + {0x2744, 0x2744}, + {0x2747, 0x2747}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2763, 0x2767}, + {0x2795, 0x2797}, + {0x27A1, 0x27A1}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2934, 0x2935}, + {0x2B05, 0x2B07}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x3030, 0x3030}, + {0x303D, 0x303D}, + {0x3297, 0x3297}, + {0x3299, 0x3299}, + {0x1F000, 0x1F0FF}, + {0x1F10D, 0x1F10F}, + {0x1F12F, 0x1F12F}, + {0x1F16C, 0x1F171}, + {0x1F17E, 0x1F17F}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F1AD, 0x1F1E5}, + {0x1F201, 0x1F20F}, + {0x1F21A, 0x1F21A}, + {0x1F22F, 0x1F22F}, + {0x1F232, 0x1F23A}, + {0x1F23C, 0x1F23F}, + {0x1F249, 0x1F3FA}, + {0x1F400, 0x1F53D}, + {0x1F546, 0x1F64F}, + {0x1F680, 0x1F6FF}, + {0x1F774, 0x1F77F}, + {0x1F7D5, 0x1F7FF}, + {0x1F80C, 0x1F80F}, + {0x1F848, 0x1F84F}, + {0x1F85A, 0x1F85F}, + {0x1F888, 0x1F88F}, + {0x1F8AE, 0x1F8FF}, + {0x1F90C, 0x1F93A}, + {0x1F93C, 0x1F945}, + {0x1F947, 0x1FFFD}, +}; + +#endif /* HB_UNICODE_EMOJI_TABLE_HH */ + +/* == End of generated table == */ diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index 2d16c2e..4ac521d 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -28,11 +28,25 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-unicode-private.hh" +#include "hb-unicode.hh" +/** + * SECTION: hb-unicode + * @title: hb-unicode + * @short_description: Unicode character property access + * @include: hb.h + * + * Unicode functions are used to access Unicode character properties. + * Client can pass its own Unicode functions to HarfBuzz, or access + * the built-in Unicode functions that come with HarfBuzz. + * + * With the Unicode functions, one can query variour Unicode character + * properties, such as General Category, Script, Combining Class, etc. + **/ + /* * hb_unicode_funcs_t @@ -109,40 +123,23 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } -#define HB_UNICODE_FUNCS_IMPLEMENT_SET \ - HB_UNICODE_FUNCS_IMPLEMENT (glib) \ - HB_UNICODE_FUNCS_IMPLEMENT (icu) \ - HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \ - HB_UNICODE_FUNCS_IMPLEMENT (nil) \ - /* ^--- Add new callbacks before nil */ - -#define hb_nil_get_unicode_funcs hb_unicode_funcs_get_empty - -/* Prototype them all */ -#define HB_UNICODE_FUNCS_IMPLEMENT(set) \ -extern "C" hb_unicode_funcs_t *hb_##set##_get_unicode_funcs (void); -HB_UNICODE_FUNCS_IMPLEMENT_SET -#undef HB_UNICODE_FUNCS_IMPLEMENT - +extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); +extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); +extern "C" hb_unicode_funcs_t *hb_ucdn_get_unicode_funcs (); hb_unicode_funcs_t * -hb_unicode_funcs_get_default (void) +hb_unicode_funcs_get_default () { -#define HB_UNICODE_FUNCS_IMPLEMENT(set) \ - return hb_##set##_get_unicode_funcs (); - #if defined(HAVE_UCDN) - HB_UNICODE_FUNCS_IMPLEMENT(ucdn) + return hb_ucdn_get_unicode_funcs (); #elif defined(HAVE_GLIB) - HB_UNICODE_FUNCS_IMPLEMENT(glib) + return hb_glib_get_unicode_funcs (); #elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) - HB_UNICODE_FUNCS_IMPLEMENT(icu) + return hb_icu_get_unicode_funcs (); #else #define HB_UNICODE_FUNCS_NIL 1 - HB_UNICODE_FUNCS_IMPLEMENT(nil) + return hb_unicode_funcs_get_empty (); #endif - -#undef HB_UNICODE_FUNCS_IMPLEMENT } #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL) @@ -154,7 +151,7 @@ hb_unicode_funcs_get_default (void) * hb_unicode_funcs_create: (Xconstructor) * @parent: (nullable): * - * + * * * Return value: (transfer full): * @@ -185,11 +182,11 @@ hb_unicode_funcs_create (hb_unicode_funcs_t *parent) } -const hb_unicode_funcs_t _hb_unicode_funcs_nil = { +DEFINE_NULL_INSTANCE (hb_unicode_funcs_t) = +{ HB_OBJECT_HEADER_STATIC, nullptr, /* parent */ - true, /* immutable */ { #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil, HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS @@ -200,23 +197,23 @@ const hb_unicode_funcs_t _hb_unicode_funcs_nil = { /** * hb_unicode_funcs_get_empty: * - * + * * * Return value: (transfer full): * * Since: 0.9.2 **/ hb_unicode_funcs_t * -hb_unicode_funcs_get_empty (void) +hb_unicode_funcs_get_empty () { - return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil); + return const_cast<hb_unicode_funcs_t *> (&Null(hb_unicode_funcs_t)); } /** * hb_unicode_funcs_reference: (skip) * @ufuncs: Unicode functions. * - * + * * * Return value: (transfer full): * @@ -232,7 +229,7 @@ hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs) * hb_unicode_funcs_destroy: (skip) * @ufuncs: Unicode functions. * - * + * * * Since: 0.9.2 **/ @@ -254,14 +251,14 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs) /** * hb_unicode_funcs_set_user_data: (skip) * @ufuncs: Unicode functions. - * @key: - * @data: - * @destroy: - * @replace: + * @key: + * @data: + * @destroy: + * @replace: + * * - * * - * Return value: + * Return value: * * Since: 0.9.2 **/ @@ -278,9 +275,9 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_get_user_data: (skip) * @ufuncs: Unicode functions. - * @key: + * @key: + * * - * * * Return value: (transfer none): * @@ -298,42 +295,42 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, * hb_unicode_funcs_make_immutable: * @ufuncs: Unicode functions. * - * + * * * Since: 0.9.2 **/ void hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs) { - if (unlikely (hb_object_is_inert (ufuncs))) + if (hb_object_is_immutable (ufuncs)) return; - ufuncs->immutable = true; + hb_object_make_immutable (ufuncs); } /** * hb_unicode_funcs_is_immutable: * @ufuncs: Unicode functions. * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ hb_bool_t hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs) { - return ufuncs->immutable; + return hb_object_is_immutable (ufuncs); } /** * hb_unicode_funcs_get_parent: * @ufuncs: Unicode functions. * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -352,7 +349,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (ufuncs->immutable) \ + if (hb_object_is_immutable (ufuncs)) \ return; \ \ if (ufuncs->destroy.name) \ @@ -387,13 +384,13 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE /** * hb_unicode_compose: * @ufuncs: Unicode functions. - * @a: - * @b: + * @a: + * @b: * @ab: (out): * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -409,13 +406,13 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_decompose: * @ufuncs: Unicode functions. - * @ab: + * @ab: * @a: (out): * @b: (out): * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 **/ @@ -431,14 +428,15 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_decompose_compatibility: * @ufuncs: Unicode functions. - * @u: + * @u: * @decomposed: (out): * - * * - * Return value: + * + * Return value: * * Since: 0.9.2 + * Deprecated: 2.0.0 **/ unsigned int hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, @@ -449,7 +447,7 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, } -/* See hb-unicode-private.hh for details. */ +/* See hb-unicode.hh for details. */ const uint8_t _hb_modified_combining_class[256] = { @@ -561,3 +559,19 @@ _hb_modified_combining_class[256] = 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* HB_UNICODE_COMBINING_CLASS_INVALID */ }; + + +/* + * Emoji + */ + +#include "hb-unicode-emoji-table.hh" + +bool +_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp) +{ + return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table, + ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table), + sizeof (hb_unicode_range_t), + hb_unicode_range_t::cmp); +} diff --git a/src/hb-unicode.h b/src/hb-unicode.h index 2657f48..df0b91f 100644 --- a/src/hb-unicode.h +++ b/src/hb-unicode.h @@ -40,6 +40,14 @@ HB_BEGIN_DECLS +/** + * HB_UNICODE_MAX + * + * Since: 1.9.0 + **/ +#define HB_UNICODE_MAX 0x10FFFFu + + /* hb_unicode_general_category_t */ /* Unicode Character Database property: General_Category (gc) */ @@ -222,9 +230,6 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs); typedef hb_unicode_combining_class_t (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); -typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode, - void *user_data); typedef hb_unicode_general_category_t (*hb_unicode_general_category_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); @@ -246,32 +251,6 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *b, void *user_data); -/** - * hb_unicode_decompose_compatibility_func_t: - * @ufuncs: a Unicode function structure - * @u: codepoint to decompose - * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into - * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() - * - * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed. - * The complete length of the decomposition will be returned. - * - * If @u has no compatibility decomposition, zero should be returned. - * - * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any - * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations - * of this function type must ensure that they do not write past the provided array. - * - * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available. - */ -typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data); - -/* See Unicode 6.1 for details on the maximum decomposition length. */ -#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */ - /* setters */ /** @@ -291,22 +270,6 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, void *user_data, hb_destroy_func_t destroy); /** - * hb_unicode_funcs_set_eastasian_width_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * - * - * - * Since: 0.9.2 - **/ -HB_EXTERN void -hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_eastasian_width_func_t func, - void *user_data, hb_destroy_func_t destroy); - -/** * hb_unicode_funcs_set_general_category_func: * @ufuncs: a Unicode function structure * @func: (closure user_data) (destroy destroy) (scope notified): @@ -386,22 +349,6 @@ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs, hb_unicode_decompose_func_t func, void *user_data, hb_destroy_func_t destroy); -/** - * hb_unicode_funcs_set_decompose_compatibility_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * - * - * - * Since: 0.9.2 - **/ -HB_EXTERN void -hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_decompose_compatibility_func_t func, - void *user_data, hb_destroy_func_t destroy); - /* accessors */ /** @@ -414,15 +361,6 @@ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode); /** - * hb_unicode_eastasian_width: - * - * Since: 0.9.2 - **/ -HB_EXTERN unsigned int -hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode); - -/** * hb_unicode_general_category: * * Since: 0.9.2 @@ -461,11 +399,6 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *a, hb_codepoint_t *b); -HB_EXTERN unsigned int -hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t u, - hb_codepoint_t *decomposed); - HB_END_DECLS #endif /* HB_UNICODE_H */ diff --git a/src/hb-unicode-private.hh b/src/hb-unicode.hh index 5472ece..82ebb10 100644 --- a/src/hb-unicode-private.hh +++ b/src/hb-unicode.hh @@ -28,11 +28,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_UNICODE_PRIVATE_HH -#define HB_UNICODE_PRIVATE_HH +#ifndef HB_UNICODE_HH +#define HB_UNICODE_HH -#include "hb-private.hh" -#include "hb-object-private.hh" +#include "hb.hh" extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256]; @@ -61,36 +60,34 @@ extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256]; HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \ /* ^--- Add new simple callbacks here */ -struct hb_unicode_funcs_t { +struct hb_unicode_funcs_t +{ hb_object_header_t header; - ASSERT_POD (); hb_unicode_funcs_t *parent; - bool immutable; - #define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \ - inline return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); } + return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); } HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE #undef HB_UNICODE_FUNC_IMPLEMENT - inline hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b, - hb_codepoint_t *ab) + hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b, + hb_codepoint_t *ab) { *ab = 0; if (unlikely (!a || !b)) return false; return func.compose (this, a, b, ab, user_data.compose); } - inline hb_bool_t decompose (hb_codepoint_t ab, - hb_codepoint_t *a, hb_codepoint_t *b) + hb_bool_t decompose (hb_codepoint_t ab, + hb_codepoint_t *a, hb_codepoint_t *b) { *a = ab; *b = 0; return func.decompose (this, ab, a, b, user_data.decompose); } - inline unsigned int decompose_compatibility (hb_codepoint_t u, - hb_codepoint_t *decomposed) + unsigned int decompose_compatibility (hb_codepoint_t u, + hb_codepoint_t *decomposed) { unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility); if (ret == 1 && u == decomposed[0]) { @@ -101,34 +98,33 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE return ret; } - - inline unsigned int - modified_combining_class (hb_codepoint_t unicode) + unsigned int + modified_combining_class (hb_codepoint_t u) { /* XXX This hack belongs to the Myanmar shaper. */ - if (unlikely (unicode == 0x1037u)) unicode = 0x103Au; + if (unlikely (u == 0x1037u)) u = 0x103Au; /* XXX This hack belongs to the USE shaper (for Tai Tham): * Reorder SAKOT to ensure it comes after any tone marks. */ - if (unlikely (unicode == 0x1A60u)) return 254; + if (unlikely (u == 0x1A60u)) return 254; /* XXX This hack belongs to the Tibetan shaper: * Reorder PADMA to ensure it comes after any vowel marks. */ - if (unlikely (unicode == 0x0FC6u)) return 254; + if (unlikely (u == 0x0FC6u)) return 254; /* Reorder TSA -PHRU to reorder before U+0F74 */ - if (unlikely (unicode == 0x0F39u)) return 127; + if (unlikely (u == 0x0F39u)) return 127; - return _hb_modified_combining_class[combining_class (unicode)]; + return _hb_modified_combining_class[combining_class (u)]; } - static inline hb_bool_t + static hb_bool_t is_variation_selector (hb_codepoint_t unicode) { /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the * Arabic shaper. No need to match them here. */ return unlikely (hb_in_ranges<hb_codepoint_t> (unicode, - 0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */ - 0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */ + 0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */ + 0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */ } /* Default_Ignorable codepoints: @@ -168,7 +164,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 * E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> */ - static inline hb_bool_t + static hb_bool_t is_default_ignorable (hb_codepoint_t ch) { hb_codepoint_t plane = ch >> 16; @@ -220,7 +216,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE SPACE_PUNCTUATION, SPACE_NARROW, }; - static inline space_t + static space_t space_fallback_type (hb_codepoint_t u) { switch (u) @@ -264,12 +260,12 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE #undef HB_UNICODE_FUNC_IMPLEMENT } destroy; }; +DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); -extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil; - - -/* Modified combining marks */ +/* + * Modified combining marks + */ /* Hebrew * @@ -362,10 +358,37 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil; FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) -#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \ - (FLAG_UNSAFE (gen_cat) & \ - (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \ - FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \ - FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL))) -#endif /* HB_UNICODE_PRIVATE_HH */ +/* + * Ranges, used for bsearch tables. + */ + +struct hb_unicode_range_t +{ + static int + cmp (const void *_key, const void *_item) + { + hb_codepoint_t cp = *((hb_codepoint_t *) _key); + const hb_unicode_range_t *range = (hb_unicode_range_t *) _item; + + if (cp < range->start) + return -1; + else if (cp <= range->end) + return 0; + else + return +1; + } + + hb_codepoint_t start; + hb_codepoint_t end; +}; + +/* + * Emoji. + */ + +HB_INTERNAL bool +_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp); + + +#endif /* HB_UNICODE_HH */ diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 6d6afe8..31c50df 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -24,10 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-debug.hh" -#define HB_SHAPER uniscribe -#include "hb-shaper-impl-private.hh" +#include "hb.hh" +#include "hb-shaper-impl.hh" #include <windows.h> #include <usp10.h> @@ -35,9 +33,19 @@ #include "hb-uniscribe.h" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-name-table.hh" -#include "hb-ot-tag.h" +#include "hb-ot-layout.h" + + +/** + * SECTION:hb-uniscribe + * @title: hb-uniscribe + * @short_description: Windows integration + * @include: hb-uniscribe.h + * + * Functions for using HarfBuzz with the Windows fonts. + **/ static inline uint16_t hb_uint16_swap (const uint16_t v) @@ -191,12 +199,13 @@ hb_ScriptPlaceOpenType( } -struct hb_uniscribe_shaper_funcs_t { +struct hb_uniscribe_shaper_funcs_t +{ SIOT ScriptItemizeOpenType; SSOT ScriptShapeOpenType; SPOT ScriptPlaceOpenType; - inline void init (void) + void init () { HMODULE hinstLib; this->ScriptItemizeOpenType = nullptr; @@ -206,9 +215,12 @@ struct hb_uniscribe_shaper_funcs_t { hinstLib = GetModuleHandle (TEXT ("usp10.dll")); if (hinstLib) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType"); this->ScriptShapeOpenType = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType"); this->ScriptPlaceOpenType = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType"); +#pragma GCC diagnostic pop } if (!this->ScriptItemizeOpenType || !this->ScriptShapeOpenType || @@ -221,47 +233,49 @@ struct hb_uniscribe_shaper_funcs_t { } } }; -static hb_uniscribe_shaper_funcs_t *uniscribe_funcs; -#ifdef HB_USE_ATEXIT -static inline void -free_uniscribe_funcs (void) -{ -retry: - hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs = - (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs); - if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, local_uniscribe_funcs, nullptr)) - goto retry; - free (uniscribe_funcs); -} -#endif +static void free_static_uniscribe_shaper_funcs (); -static hb_uniscribe_shaper_funcs_t * -hb_uniscribe_shaper_get_funcs (void) +static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t, + hb_uniscribe_shaper_funcs_lazy_loader_t> { -retry: - hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs); - - if (unlikely (!funcs)) + static hb_uniscribe_shaper_funcs_t *create () { - funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t)); + hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t)); if (unlikely (!funcs)) return nullptr; funcs->init (); - if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) { - free (funcs); - goto retry; - } - -#ifdef HB_USE_ATEXIT - atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */ +#if HB_USE_ATEXIT + atexit (free_static_uniscribe_shaper_funcs); #endif + + return funcs; } + static void destroy (hb_uniscribe_shaper_funcs_t *p) + { + free ((void *) p); + } + static hb_uniscribe_shaper_funcs_t *get_null () + { + return nullptr; + } +} static_uniscribe_shaper_funcs; + +#if HB_USE_ATEXIT +static +void free_static_uniscribe_shaper_funcs () +{ + static_uniscribe_shaper_funcs.free_instance (); +} +#endif - return funcs; +static hb_uniscribe_shaper_funcs_t * +hb_uniscribe_shaper_get_funcs () +{ + return static_uniscribe_shaper_funcs.get_unconst (); } @@ -277,9 +291,8 @@ struct active_feature_t { a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 : 0; } - bool operator== (const active_feature_t *f) { - return cmp (this, f) == 0; - } + bool operator== (const active_feature_t *f) + { return cmp (this, f) == 0; } }; struct feature_event_t { @@ -287,7 +300,8 @@ struct feature_event_t { bool start; active_feature_t feature; - static int cmp (const void *pa, const void *pb) { + static int cmp (const void *pa, const void *pb) + { const feature_event_t *a = (const feature_event_t *) pa; const feature_event_t *b = (const feature_event_t *) pb; return a->index < b->index ? -1 : a->index > b->index ? 1 : @@ -302,15 +316,12 @@ struct range_record_t { unsigned int index_last; /* == end - 1 */ }; -HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, face) -HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font) - /* * shaper face data */ -struct hb_uniscribe_shaper_face_data_t { +struct hb_uniscribe_face_data_t { HANDLE fh; hb_uniscribe_shaper_funcs_t *funcs; wchar_t face_name[LF_FACESIZE]; @@ -359,7 +370,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) * full, PS. All of them point to the same name data with our unique name. */ - blob = OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (blob); + blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (blob); unsigned int length, new_length, name_str_len; const char *orig_sfnt_data = hb_blob_get_data (blob, &length); @@ -384,13 +395,13 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) memcpy(new_sfnt_data, orig_sfnt_data, length); - OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); + OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); name.format.set (0); name.count.set (ARRAY_LENGTH (name_IDs)); name.stringOffset.set (name.get_size ()); for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) { - OT::NameRecord &record = name.nameRecord[i]; + OT::NameRecord &record = name.nameRecordZ[i]; record.platformID.set (3); record.encodingID.set (1); record.languageID.set (0x0409u); /* English */ @@ -400,7 +411,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) } /* Copy string data from new_name, converting wchar_t to UTF16BE. */ - unsigned char *p = &OT::StructAfter<unsigned char> (name); + unsigned char *p = &StructAfter<unsigned char> (name); for (unsigned int i = 0; i < name_str_len; i++) { *p++ = new_name[i] >> 8; @@ -440,10 +451,10 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) HB_MEMORY_MODE_WRITABLE, nullptr, free); } -hb_uniscribe_shaper_face_data_t * +hb_uniscribe_face_data_t * _hb_uniscribe_shaper_face_data_create (hb_face_t *face) { - hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t)); + hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t)); if (unlikely (!data)) return nullptr; @@ -480,7 +491,7 @@ _hb_uniscribe_shaper_face_data_create (hb_face_t *face) } void -_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data) +_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data) { RemoveFontMemResourceEx (data->fh); free (data); @@ -491,11 +502,12 @@ _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data) * shaper font data */ -struct hb_uniscribe_shaper_font_data_t { +struct hb_uniscribe_font_data_t +{ HDC hdc; - LOGFONTW log_font; + mutable LOGFONTW log_font; HFONT hfont; - SCRIPT_CACHE script_cache; + mutable SCRIPT_CACHE script_cache; double x_mult, y_mult; /* From LOGFONT space to HB space. */ }; @@ -508,20 +520,15 @@ populate_log_font (LOGFONTW *lf, lf->lfHeight = - (int) font_size; lf->lfCharSet = DEFAULT_CHARSET; - hb_face_t *face = font->face; - hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); - - memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName)); + memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName)); return true; } -hb_uniscribe_shaper_font_data_t * +hb_uniscribe_font_data_t * _hb_uniscribe_shaper_font_data_create (hb_font_t *font) { - if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return nullptr; - - hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t)); + hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t)); if (unlikely (!data)) return nullptr; @@ -560,7 +567,7 @@ _hb_uniscribe_shaper_font_data_create (hb_font_t *font) } void -_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data) +_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data) { if (data->hdc) ReleaseDC (nullptr, data->hdc); @@ -574,39 +581,15 @@ _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data) LOGFONTW * hb_uniscribe_font_get_logfontw (hb_font_t *font) { - if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr; - hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); - return &font_data->log_font; + const hb_uniscribe_font_data_t *data = font->data.uniscribe; + return data ? &data->log_font : nullptr; } HFONT hb_uniscribe_font_get_hfont (hb_font_t *font) { - if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr; - hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); - return font_data->hfont; -} - - -/* - * shaper shape_plan data - */ - -struct hb_uniscribe_shaper_shape_plan_data_t {}; - -hb_uniscribe_shaper_shape_plan_data_t * -_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, - const hb_feature_t *user_features HB_UNUSED, - unsigned int num_user_features HB_UNUSED, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) -{ - return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; -} - -void -_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED) -{ + const hb_uniscribe_font_data_t *data = font->data.uniscribe; + return data ? data->hfont : nullptr; } @@ -623,19 +606,19 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, unsigned int num_features) { hb_face_t *face = font->face; - hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); - hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + const hb_uniscribe_face_data_t *face_data = face->data.uniscribe; + const hb_uniscribe_font_data_t *font_data = font->data.uniscribe; hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs; /* * Set up features. */ - hb_auto_t<hb_vector_t<OPENTYPE_FEATURE_RECORD> > feature_records; - hb_auto_t<hb_vector_t<range_record_t> > range_records; + hb_vector_t<OPENTYPE_FEATURE_RECORD> feature_records; + hb_vector_t<range_record_t> range_records; if (num_features) { /* Sort features by start/end events. */ - hb_auto_t<hb_vector_t<feature_event_t> > feature_events; + hb_vector_t<feature_event_t> feature_events; for (unsigned int i = 0; i < num_features; i++) { active_feature_t feature; @@ -670,9 +653,9 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, } /* Scan events and save features for each range. */ - hb_auto_t<hb_vector_t<active_feature_t> > active_features; + hb_vector_t<active_feature_t> active_features; unsigned int last_index = 0; - for (unsigned int i = 0; i < feature_events.len; i++) + for (unsigned int i = 0; i < feature_events.length; i++) { feature_event_t *event = &feature_events[i]; @@ -681,26 +664,26 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, /* Save a snapshot of active features and the range. */ range_record_t *range = range_records.push (); - unsigned int offset = feature_records.len; + unsigned int offset = feature_records.length; active_features.qsort (); - for (unsigned int j = 0; j < active_features.len; j++) + for (unsigned int j = 0; j < active_features.length; j++) { - if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature) + if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.length - 1].tagFeature) { feature_records.push (active_features[j].rec); } else { /* Overrides value for existing feature. */ - feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter; + feature_records[feature_records.length - 1].lParameter = active_features[j].rec.lParameter; } } /* Will convert to pointer after all is ready, since feature_records.array * may move as we grow it. */ range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset); - range->props.cotfRecords = feature_records.len - offset; + range->props.cotfRecords = feature_records.length - offset; range->index_first = last_index; range->index_last = event->index - 1; @@ -715,18 +698,18 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, { active_feature_t *feature = active_features.find (&event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove (feature - active_features.arrayZ ()); } } - if (!range_records.len) /* No active feature found. */ + if (!range_records.length) /* No active feature found. */ num_features = 0; /* Fixup the pointers. */ - for (unsigned int i = 0; i < range_records.len; i++) + for (unsigned int i = 0; i < range_records.length; i++) { range_record_t *range = &range_records[i]; - range->props.potfRecords = feature_records.arrayZ + reinterpret_cast<uintptr_t> (range->props.potfRecords); + range->props.potfRecords = (OPENTYPE_FEATURE_RECORD *) feature_records + reinterpret_cast<uintptr_t> (range->props.potfRecords); } } @@ -837,13 +820,19 @@ retry: script_tags, &item_count); if (unlikely (FAILED (hr))) - FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); + FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr); #undef MAX_ITEMS - OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); - hb_auto_t<hb_vector_t<TEXTRANGE_PROPERTIES*> > range_properties; - hb_auto_t<hb_vector_t<int> > range_char_counts; + hb_tag_t lang_tag; + unsigned int lang_count = 1; + hb_ot_tags_from_script_and_language (buffer->props.script, + buffer->props.language, + nullptr, nullptr, + &lang_count, &lang_tag); + OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE); + hb_vector_t<TEXTRANGE_PROPERTIES*> range_properties; + hb_vector_t<int> range_char_counts; unsigned int glyphs_offset = 0; unsigned int glyphs_len; @@ -867,8 +856,8 @@ retry: range--; while (log_clusters[k] > range->index_last) range++; - if (!range_properties.len || - &range->props != range_properties[range_properties.len - 1]) + if (!range_properties.length || + &range->props != range_properties[range_properties.length - 1]) { TEXTRANGE_PROPERTIES **props = range_properties.push (); int *c = range_char_counts.push (); @@ -883,7 +872,7 @@ retry: } else { - range_char_counts[range_char_counts.len - 1]++; + range_char_counts[range_char_counts.length - 1]++; } last_range = range; @@ -900,9 +889,9 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ, - range_properties.arrayZ, - range_properties.len, + range_char_counts.arrayZ (), + range_properties.arrayZ (), + range_properties.length, pchars + chars_offset, item_chars_len, glyphs_size - glyphs_offset, @@ -930,7 +919,7 @@ retry: } if (unlikely (FAILED (hr))) { - FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); + FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr); } for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) @@ -941,9 +930,9 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ, - range_properties.arrayZ, - range_properties.len, + range_char_counts.arrayZ (), + range_properties.arrayZ (), + range_properties.length, pchars + chars_offset, log_clusters + chars_offset, char_props + chars_offset, @@ -956,7 +945,7 @@ retry: offsets + glyphs_offset, nullptr); if (unlikely (FAILED (hr))) - FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); + FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr); if (DEBUG_ENABLED (UNISCRIBE)) fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", @@ -975,13 +964,13 @@ retry: /* Calculate visual-clusters. That's what we ship. */ for (unsigned int i = 0; i < glyphs_len; i++) - vis_clusters[i] = -1; + vis_clusters[i] = (uint32_t) -1; for (unsigned int i = 0; i < buffer->len; i++) { uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; *p = MIN (*p, buffer->info[i].cluster); } for (unsigned int i = 1; i < glyphs_len; i++) - if (vis_clusters[i] == -1) + if (vis_clusters[i] == (uint32_t) -1) vis_clusters[i] = vis_clusters[i - 1]; #undef utf16_index diff --git a/src/hb-utf-private.hh b/src/hb-utf.hh index 211eb4d..59ec75e 100644 --- a/src/hb-utf-private.hh +++ b/src/hb-utf.hh @@ -24,19 +24,21 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_UTF_PRIVATE_HH -#define HB_UTF_PRIVATE_HH +#ifndef HB_UTF_HH +#define HB_UTF_HH -#include "hb-private.hh" +#include "hb.hh" + +#include "hb-open-type.hh" struct hb_utf8_t { typedef uint8_t codepoint_t; - static inline const uint8_t * - next (const uint8_t *text, - const uint8_t *end, + static const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -103,13 +105,13 @@ struct hb_utf8_t return text; } - static inline const uint8_t * - prev (const uint8_t *text, - const uint8_t *start, + static const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start, hb_codepoint_t *unicode, hb_codepoint_t replacement) { - const uint8_t *end = text--; + const codepoint_t *end = text--; while (start < text && (*text & 0xc0) == 0x80 && end - text < 4) text--; @@ -120,21 +122,70 @@ struct hb_utf8_t return end - 1; } - static inline unsigned int - strlen (const uint8_t *text) + static unsigned int + strlen (const codepoint_t *text) + { return ::strlen ((const char *) text); } + + static unsigned int + encode_len (hb_codepoint_t unicode) + { + if (unicode < 0x0080u) return 1; + if (unicode < 0x0800u) return 2; + if (unicode < 0x10000u) return 3; + if (unicode < 0x110000u) return 4; + return 3; + } + + static codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end, + hb_codepoint_t unicode) { - return ::strlen ((const char *) text); + if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + if (unicode < 0x0080u) + *text++ = unicode; + else if (unicode < 0x0800u) + { + if (end - text >= 2) + { + *text++ = 0xC0u + (0x1Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + else if (unicode < 0x10000u) + { + if (end - text >= 3) + { + *text++ = 0xE0u + (0x0Fu & (unicode >> 12)); + *text++ = 0x80u + (0x3Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + else + { + if (end - text >= 4) + { + *text++ = 0xF0u + (0x07u & (unicode >> 18)); + *text++ = 0x80u + (0x3Fu & (unicode >> 12)); + *text++ = 0x80u + (0x3Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + return text; } }; -struct hb_utf16_t +template <typename TCodepoint> +struct hb_utf16_xe_t { - typedef uint16_t codepoint_t; + static_assert (sizeof (TCodepoint) == 2, ""); + typedef TCodepoint codepoint_t; - static inline const uint16_t * - next (const uint16_t *text, - const uint16_t *end, + static const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -164,9 +215,9 @@ struct hb_utf16_t return text; } - static inline const uint16_t * - prev (const uint16_t *text, - const uint16_t *start, + static const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -197,24 +248,52 @@ struct hb_utf16_t } - static inline unsigned int - strlen (const uint16_t *text) + static unsigned int + strlen (const codepoint_t *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static unsigned int + encode_len (hb_codepoint_t unicode) + { + return unicode < 0x10000 ? 1 : 2; + } + + static codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + if (unicode < 0x10000u) + *text++ = unicode; + else if (end - text >= 2) + { + unicode -= 0x10000u; + *text++ = 0xD800u + (unicode >> 10); + *text++ = 0xDC00u + (unicode & 0x03FFu); + } + return text; + } }; +typedef hb_utf16_xe_t<uint16_t> hb_utf16_t; +typedef hb_utf16_xe_t<OT::HBUINT16> hb_utf16_be_t; + -template <bool validate=true> -struct hb_utf32_t +template <typename TCodepoint, bool validate=true> +struct hb_utf32_xe_t { - typedef uint32_t codepoint_t; + static_assert (sizeof (TCodepoint) == 4, ""); + typedef TCodepoint codepoint_t; - static inline const uint32_t * - next (const uint32_t *text, - const uint32_t *end HB_UNUSED, + static const TCodepoint * + next (const TCodepoint *text, + const TCodepoint *end HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -224,9 +303,9 @@ struct hb_utf32_t return text; } - static inline const uint32_t * - prev (const uint32_t *text, - const uint32_t *start HB_UNUSED, + static const TCodepoint * + prev (const TCodepoint *text, + const TCodepoint *start HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -236,23 +315,43 @@ struct hb_utf32_t return text; } - static inline unsigned int - strlen (const uint32_t *text) + static unsigned int + strlen (const TCodepoint *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (validate && unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + *text++ = unicode; + return text; + } }; +typedef hb_utf32_xe_t<uint32_t> hb_utf32_t; +typedef hb_utf32_xe_t<uint32_t, false> hb_utf32_novalidate_t; + struct hb_latin1_t { typedef uint8_t codepoint_t; - static inline const uint8_t * - next (const uint8_t *text, - const uint8_t *end HB_UNUSED, + static const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement HB_UNUSED) { @@ -260,23 +359,95 @@ struct hb_latin1_t return text; } - static inline const uint8_t * - prev (const uint8_t *text, - const uint8_t *start HB_UNUSED, + static const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start HB_UNUSED, + hb_codepoint_t *unicode, + hb_codepoint_t replacement HB_UNUSED) + { + *unicode = *--text; + return text; + } + + static unsigned int + strlen (const codepoint_t *text) + { + unsigned int l = 0; + while (*text++) l++; + return l; + } + + static unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0x0100u)) + unicode = '?'; + *text++ = unicode; + return text; + } +}; + + +struct hb_ascii_t +{ + typedef uint8_t codepoint_t; + + static const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t *unicode, + hb_codepoint_t replacement HB_UNUSED) + { + *unicode = *text++; + if (*unicode >= 0x0080u) + *unicode = replacement; + return text; + } + + static const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement) { *unicode = *--text; + if (*unicode >= 0x0080u) + *unicode = replacement; return text; } - static inline unsigned int - strlen (const uint8_t *text) + static unsigned int + strlen (const codepoint_t *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0x0080u)) + unicode = '?'; + *text++ = unicode; + return text; + } }; -#endif /* HB_UTF_PRIVATE_HH */ +#endif /* HB_UTF_HH */ diff --git a/src/hb-vector.hh b/src/hb-vector.hh new file mode 100644 index 0000000..2fd739b --- /dev/null +++ b/src/hb-vector.hh @@ -0,0 +1,260 @@ +/* + * Copyright © 2017,2018 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): Behdad Esfahbod + */ + +#ifndef HB_VECTOR_HH +#define HB_VECTOR_HH + +#include "hb.hh" +#include "hb-array.hh" +#include "hb-null.hh" + + +template <typename Type> +struct hb_vector_t +{ + typedef Type item_t; + static constexpr unsigned item_size = hb_static_size (Type); + + HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type); + hb_vector_t () { init (); } + ~hb_vector_t () { fini (); } + + unsigned int length; + private: + int allocated; /* == -1 means allocation failed. */ + Type *arrayZ_; + public: + + void init () + { + allocated = length = 0; + arrayZ_ = nullptr; + } + + void fini () + { + if (arrayZ_) + free (arrayZ_); + init (); + } + void fini_deep () + { + Type *array = arrayZ(); + unsigned int count = length; + for (unsigned int i = 0; i < count; i++) + array[i].fini (); + fini (); + } + + const Type * arrayZ () const { return arrayZ_; } + Type * arrayZ () { return arrayZ_; } + + Type& operator [] (int i_) + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= length)) + return Crap (Type); + return arrayZ()[i]; + } + const Type& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= length)) + return Null(Type); + return arrayZ()[i]; + } + + explicit_operator bool () const { return length; } + + hb_array_t<Type> as_array () + { return hb_array (arrayZ(), length); } + hb_array_t<const Type> as_array () const + { return hb_array (arrayZ(), length); } + + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) + { return as_array ().sub_array (start_offset, count);} + hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + { return as_array ().sub_array (start_offset, count);} + + hb_sorted_array_t<Type> as_sorted_array () + { return hb_sorted_array (arrayZ(), length); } + hb_sorted_array_t<const Type> as_sorted_array () const + { return hb_sorted_array (arrayZ(), length); } + + hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int count) const + { return as_sorted_array ().sorted_sub_array (start_offset, count);} + hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + { return as_sorted_array ().sorted_sub_array (start_offset, count);} + hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int count) + { return as_sorted_array ().sorted_sub_array (start_offset, count);} + hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + { return as_sorted_array ().sorted_sub_array (start_offset, count);} + + template <typename T> explicit_operator T * () { return arrayZ(); } + template <typename T> explicit_operator const T * () const { return arrayZ(); } + operator hb_array_t<Type> () { return as_array (); } + operator hb_array_t<const Type> () const { return as_array (); } + + Type * operator + (unsigned int i) { return arrayZ() + i; } + const Type * operator + (unsigned int i) const { return arrayZ() + i; } + + Type *push () + { + if (unlikely (!resize (length + 1))) + return &Crap(Type); + return &arrayZ()[length - 1]; + } + Type *push (const Type& v) + { + Type *p = push (); + *p = v; + return p; + } + + bool in_error () const { return allocated < 0; } + + /* Allocate for size but don't adjust length. */ + bool alloc (unsigned int size) + { + if (unlikely (allocated < 0)) + return false; + + if (likely (size <= (unsigned) allocated)) + return true; + + /* Reallocate */ + + unsigned int new_allocated = allocated; + while (size >= new_allocated) + new_allocated += (new_allocated >> 1) + 8; + + Type *new_array = nullptr; + bool overflows = + (int) new_allocated < 0 || + (new_allocated < (unsigned) allocated) || + hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); + if (likely (!overflows)) + new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type)); + + if (unlikely (!new_array)) + { + allocated = -1; + return false; + } + + arrayZ_ = new_array; + allocated = new_allocated; + + return true; + } + + bool resize (int size_) + { + unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; + if (!alloc (size)) + return false; + + if (size > length) + memset (arrayZ() + length, 0, (size - length) * sizeof (*arrayZ())); + + length = size; + return true; + } + + void pop () + { + if (!length) return; + length--; + } + + void remove (unsigned int i) + { + if (unlikely (i >= length)) + return; + Type *array = arrayZ(); + memmove (static_cast<void *> (&array[i]), + static_cast<void *> (&array[i + 1]), + (length - i - 1) * sizeof (Type)); + length--; + } + + void shrink (int size_) + { + unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; + if (size < length) + length = size; + } + + template <typename T> + Type *find (T v) + { + Type *array = arrayZ(); + for (unsigned int i = 0; i < length; i++) + if (array[i] == v) + return &array[i]; + return nullptr; + } + template <typename T> + const Type *find (T v) const + { + const Type *array = arrayZ(); + for (unsigned int i = 0; i < length; i++) + if (array[i] == v) + return &array[i]; + return nullptr; + } + + void qsort (int (*cmp)(const void*, const void*)) + { as_array ().qsort (cmp); } + void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) + { as_array ().qsort (start, end); } + + template <typename T> + Type *lsearch (const T &x, Type *not_found = nullptr) + { return as_array ().lsearch (x, not_found); } + template <typename T> + const Type *lsearch (const T &x, const Type *not_found = nullptr) const + { return as_array ().lsearch (x, not_found); } + + template <typename T> + Type *bsearch (const T &x, Type *not_found = nullptr) + { return as_sorted_array ().bsearch (x, not_found); } + template <typename T> + const Type *bsearch (const T &x, const Type *not_found = nullptr) const + { return as_sorted_array ().bsearch (x, not_found); } + template <typename T> + bool bfind (const T &x, unsigned int *i = nullptr, + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_sorted_array ().bfind (x, i, not_found, to_store); } +}; + + +#endif /* HB_VECTOR_HH */ diff --git a/src/hb-version.h b/src/hb-version.h index 2180d84..13db8ce 100644 --- a/src/hb-version.h +++ b/src/hb-version.h @@ -36,11 +36,11 @@ HB_BEGIN_DECLS -#define HB_VERSION_MAJOR 1 -#define HB_VERSION_MINOR 8 +#define HB_VERSION_MAJOR 2 +#define HB_VERSION_MINOR 3 #define HB_VERSION_MICRO 1 -#define HB_VERSION_STRING "1.8.1" +#define HB_VERSION_STRING "2.3.1" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ diff --git a/src/hb-warning.cc b/src/hb-warning.cc index 8f322bc..9fb4100 100644 --- a/src/hb-warning.cc +++ b/src/hb-warning.cc @@ -24,16 +24,14 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-atomic-private.hh" -#include "hb-mutex-private.hh" - +#include "hb.hh" #if defined(HB_ATOMIC_INT_NIL) #error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe" -#error "Check hb-atomic-private.hh for possible resolutions." +#error "Check hb-atomic.hh for possible resolutions." #endif #if defined(HB_MUTEX_IMPL_NIL) #error "Could not find any system to define mutex macros, library WILL NOT be thread-safe" -#error "Check hb-mutex-private.hh for possible resolutions." +#error "Check hb-mutex.hh for possible resolutions." #endif @@ -28,10 +28,6 @@ #define HB_H #define HB_H_IN -#ifndef HB_EXTERN -#define HB_EXTERN extern -#endif - #include "hb-blob.h" #include "hb-buffer.h" #include "hb-common.h" diff --git a/src/hb.hh b/src/hb.hh new file mode 100644 index 0000000..5b66ba8 --- /dev/null +++ b/src/hb.hh @@ -0,0 +1,658 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_HH +#define HB_HH + +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC +#if defined(_MSC_VER) +#pragma warning( disable: 4068 ) /* Unknown pragma */ +#endif +#if defined(__GNUC__) || defined(__clang__) +/* Rules: + * + * - All pragmas are declared GCC even if they are clang ones. Otherwise GCC + * nags, even though we instruct it to ignore -Wunknown-pragmas. ¯\_(ツ)_/¯ + * + * - Within each category, keep sorted. + * + * - Warnings whose scope can be expanded in future compiler versions shall + * be declared as "warning". Otherwise, either ignored or error. + */ + +/* Setup. Don't sort order within this category. */ +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING +#pragma GCC diagnostic warning "-Wall" +#pragma GCC diagnostic warning "-Wextra" +#endif +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#endif +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING +//#pragma GCC diagnostic warning "-Weverything" +#endif + +/* Error. Should never happen. */ +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR +#pragma GCC diagnostic error "-Wc++11-narrowing" +#pragma GCC diagnostic error "-Wcast-align" +#pragma GCC diagnostic error "-Wcast-function-type" +#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic error "-Wformat-security" +#pragma GCC diagnostic error "-Wimplicit-function-declaration" +#pragma GCC diagnostic error "-Winit-self" +#pragma GCC diagnostic error "-Wmissing-braces" +#pragma GCC diagnostic error "-Wmissing-declarations" +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wnested-externs" +#pragma GCC diagnostic error "-Wold-style-definition" +#pragma GCC diagnostic error "-Wpointer-arith" +#pragma GCC diagnostic error "-Wredundant-decls" +#pragma GCC diagnostic error "-Wreorder" +#pragma GCC diagnostic error "-Wsign-compare" +#pragma GCC diagnostic error "-Wstrict-prototypes" +#pragma GCC diagnostic error "-Wstring-conversion" +#pragma GCC diagnostic error "-Wswitch-enum" +#pragma GCC diagnostic error "-Wtautological-overlap-compare" +#pragma GCC diagnostic error "-Wunneeded-internal-declaration" +#pragma GCC diagnostic error "-Wunused" +#pragma GCC diagnostic error "-Wunused-local-typedefs" +#pragma GCC diagnostic error "-Wunused-value" +#pragma GCC diagnostic error "-Wunused-variable" +#pragma GCC diagnostic error "-Wvla" +#pragma GCC diagnostic error "-Wwrite-strings" +#endif + +/* Warning. To be investigated if happens. */ +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING +#pragma GCC diagnostic warning "-Wbuiltin-macro-redefined" +#pragma GCC diagnostic warning "-Wdisabled-optimization" +#pragma GCC diagnostic warning "-Wformat=2" +#pragma GCC diagnostic warning "-Wignored-pragma-optimize" +#pragma GCC diagnostic warning "-Wlogical-op" +#pragma GCC diagnostic warning "-Wmaybe-uninitialized" +#pragma GCC diagnostic warning "-Wmissing-format-attribute" +#pragma GCC diagnostic warning "-Wundef" +#endif + +/* Ignored currently, but should be fixed at some point. */ +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED +#pragma GCC diagnostic ignored "-Wconversion" // TODO fix +#pragma GCC diagnostic ignored "-Wformat-signedness" // TODO fix +#pragma GCC diagnostic ignored "-Wshadow" // TODO fix +#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" // TODO fix +#pragma GCC diagnostic ignored "-Wunused-parameter" // TODO fix +#endif + +/* Ignored intentionally. */ +#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#pragma GCC diagnostic ignored "-Wformat-zero-length" +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +#endif +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Following added based on what AC_USE_SYSTEM_EXTENSIONS adds to + * config.h.in. Copied here for the convenience of those embedding + * HarfBuzz and not using our build system. + */ +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + +#if defined (_MSC_VER) && defined (HB_DLL_EXPORT) +#define HB_EXTERN __declspec (dllexport) extern +#endif + +#include "hb.h" +#define HB_H_IN +#include "hb-ot.h" +#define HB_OT_H_IN +#include "hb-aat.h" +#define HB_AAT_H_IN + +#include "hb-aat.h" + +#include <math.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> + +#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) +#include <intrin.h> +#endif + +#define HB_PASTE1(a,b) a##b +#define HB_PASTE(a,b) HB_PASTE1(a,b) + + +/* Compile-time custom allocator support. */ + +#if defined(hb_malloc_impl) \ + && defined(hb_calloc_impl) \ + && defined(hb_realloc_impl) \ + && defined(hb_free_impl) +extern "C" void* hb_malloc_impl(size_t size); +extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); +extern "C" void* hb_realloc_impl(void *ptr, size_t size); +extern "C" void hb_free_impl(void *ptr); +#define malloc hb_malloc_impl +#define calloc hb_calloc_impl +#define realloc hb_realloc_impl +#define free hb_free_impl + +#if defined(hb_memalign_impl) +extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size); +#define posix_memalign hb_memalign_impl +#else +#undef HAVE_POSIX_MEMALIGN +#endif + +#endif + + +/* + * Compiler attributes + */ + +#if __cplusplus < 201103L + +#ifndef nullptr +#define nullptr NULL +#endif + +#ifndef constexpr +#define constexpr const +#endif + +#ifndef static_assert +#define static_assert(e, msg) \ + HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1] +#endif // static_assert + +#if defined(__GNUC__) +#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) +#define thread_local __thread +#endif +#else +#define thread_local +#endif + +template <typename T> +struct _hb_alignof +{ + struct s + { + char c; + T t; + }; + static constexpr size_t value = offsetof (s, t); +}; +#ifndef alignof +#define alignof(x) (_hb_alignof<x>::value) +#endif + +/* https://github.com/harfbuzz/harfbuzz/issues/1127 */ +#ifndef explicit_operator +#define explicit_operator operator +#endif + +#else /* __cplusplus >= 201103L */ + +/* https://github.com/harfbuzz/harfbuzz/issues/1127 */ +#ifndef explicit_operator +#define explicit_operator explicit operator +#endif + +#endif /* __cplusplus < 201103L */ + + +#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__) +#define likely(expr) (__builtin_expect (!!(expr), 1)) +#define unlikely(expr) (__builtin_expect (!!(expr), 0)) +#else +#define likely(expr) (expr) +#define unlikely(expr) (expr) +#endif + +#if !defined(__GNUC__) && !defined(__clang__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define HB_PURE_FUNC __attribute__((pure)) +#define HB_CONST_FUNC __attribute__((const)) +#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#else +#define HB_PURE_FUNC +#define HB_CONST_FUNC +#define HB_PRINTF_FUNC(format_idx, arg_idx) +#endif +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define HB_UNUSED __attribute__((unused)) +#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */ +#define HB_UNUSED __pragma(warning(suppress: 4100 4101)) +#else +#define HB_UNUSED +#endif + +#ifndef HB_INTERNAL +# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC) +# define HB_INTERNAL __attribute__((__visibility__("hidden"))) +# elif defined(__MINGW32__) + /* We use -export-symbols on mingw32, since it does not support visibility attributes. */ +# define HB_INTERNAL +# elif defined (_MSC_VER) && defined (HB_DLL_EXPORT) + /* We do not try to export internal symbols on Visual Studio */ +# define HB_INTERNAL +#else +# define HB_INTERNAL +# define HB_NO_VISIBILITY 1 +# endif +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define HB_FUNC __PRETTY_FUNCTION__ +#elif defined(_MSC_VER) +#define HB_FUNC __FUNCSIG__ +#else +#define HB_FUNC __func__ +#endif + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140) +/* https://github.com/harfbuzz/harfbuzz/issues/630 */ +#define __restrict +#endif + +/* + * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411 + * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch + * cases that fall through without a break or return statement. HB_FALLTHROUGH + * is only needed on cases that have code: + * + * switch (foo) { + * case 1: // These cases have no code. No fallthrough annotations are needed. + * case 2: + * case 3: + * foo = 4; // This case has code, so a fallthrough annotation is needed: + * HB_FALLTHROUGH; + * default: + * return foo; + * } + */ +#if defined(__clang__) && __cplusplus >= 201103L + /* clang's fallthrough annotations are only available starting in C++11. */ +# define HB_FALLTHROUGH [[clang::fallthrough]] +#elif defined(__GNUC__) && (__GNUC__ >= 7) + /* GNU fallthrough attribute is available from GCC7 */ +# define HB_FALLTHROUGH __attribute__((fallthrough)) +#elif defined(_MSC_VER) + /* + * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): + * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx + */ +# include <sal.h> +# define HB_FALLTHROUGH __fallthrough +#else +# define HB_FALLTHROUGH /* FALLTHROUGH */ +#endif + +#if defined(__clang__) +/* Disable certain sanitizer errors. */ +/* https://github.com/harfbuzz/harfbuzz/issues/1247 */ +#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow"))) +#else +#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW +#endif + + +#ifdef _WIN32 + /* We need Windows Vista for both Uniscribe backend and for + * MemoryBarrier. We don't support compiling on Windows XP, + * though we run on it fine. */ +# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 +# undef _WIN32_WINNT +# endif +# ifndef _WIN32_WINNT +# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# define _WIN32_WINNT 0x0600 +# endif +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# ifndef STRICT +# define STRICT 1 +# endif + +# if defined(_WIN32_WCE) + /* Some things not defined on Windows CE. */ +# define vsnprintf _vsnprintf +# define getenv(Name) nullptr +# if _WIN32_WCE < 0x800 +# define setlocale(Category, Locale) "C" +static int errno = 0; /* Use something better? */ +# endif +# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# define getenv(Name) nullptr +# endif +# if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +# endif +#endif + +#if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT) +/* atexit() is only safe to be called from shared libraries on certain + * platforms. Whitelist. + * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */ +# if defined(__linux) && defined(__GLIBC_PREREQ) +# if __GLIBC_PREREQ(2,3) +/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */ +# define HB_USE_ATEXIT 1 +# endif +# elif defined(_MSC_VER) || defined(__MINGW32__) +/* For MSVC: + * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx + * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx + * mingw32 headers say atexit is safe to use in shared libraries. + */ +# define HB_USE_ATEXIT 1 +# elif defined(__ANDROID__) +/* This is available since Android NKD r8 or r8b: + * https://issuetracker.google.com/code/p/android/issues/detail?id=6455 + */ +# define HB_USE_ATEXIT 1 +# elif defined(__APPLE__) +/* For macOS and related platforms, the atexit man page indicates + * that it will be invoked when the library is unloaded, not only + * at application exit. + */ +# define HB_USE_ATEXIT 1 +# endif +#endif +#ifdef HB_NO_ATEXIT +# undef HB_USE_ATEXIT +#endif +#ifndef HB_USE_ATEXIT +# define HB_USE_ATEXIT 0 +#endif + +#define HB_STMT_START do +#define HB_STMT_END while (0) + +/* Static-assert as expression. */ +template <unsigned int cond> class hb_assert_constant_t; +template <> class hb_assert_constant_t<1> {}; +#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>)) + +/* Lets assert int types. Saves trouble down the road. */ +static_assert ((sizeof (int8_t) == 1), ""); +static_assert ((sizeof (uint8_t) == 1), ""); +static_assert ((sizeof (int16_t) == 2), ""); +static_assert ((sizeof (uint16_t) == 2), ""); +static_assert ((sizeof (int32_t) == 4), ""); +static_assert ((sizeof (uint32_t) == 4), ""); +static_assert ((sizeof (int64_t) == 8), ""); +static_assert ((sizeof (uint64_t) == 8), ""); +static_assert ((sizeof (hb_codepoint_t) == 4), ""); +static_assert ((sizeof (hb_position_t) == 4), ""); +static_assert ((sizeof (hb_mask_t) == 4), ""); +static_assert ((sizeof (hb_var_int_t) == 4), ""); + + +#if __cplusplus >= 201103L + +/* We only enable these with C++11 or later, since earlier language + * does not allow structs with constructors in unions, and we need + * those. */ + +#define HB_NO_COPY_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) \ + TypeName(const TypeName<T>&); \ + void operator=(const TypeName<T>&) +#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ + TypeName(const TypeName<T1, T2>&); \ + void operator=(const TypeName<T1, T2>&) +#define HB_NO_CREATE_COPY_ASSIGN(TypeName) \ + TypeName(); \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) \ + TypeName(); \ + TypeName(const TypeName<T>&); \ + void operator=(const TypeName<T>&) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ + TypeName(); \ + TypeName(const TypeName<T1, T2>&); \ + void operator=(const TypeName<T1, T2>&) + +#else /* __cpluspplus >= 201103L */ + +#define HB_NO_COPY_ASSIGN(TypeName) static_assert (true, "") +#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "") +#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "") +#define HB_NO_CREATE_COPY_ASSIGN(TypeName) static_assert (true, "") +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "") +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "") + +#endif /* __cpluspplus >= 201103L */ + + +/* + * Compiler-assisted vectorization parameters. + */ + +/* + * Disable vectorization for now. To correctly use them, we should + * use posix_memalign() to allocate in hb_vector_t. Otherwise, can + * cause misaligned access. + * + * https://bugs.chromium.org/p/chromium/issues/detail?id=860184 + */ +#if !defined(HB_VECTOR_SIZE) +# define HB_VECTOR_SIZE 0 +#endif + +/* The `vector_size' attribute was introduced in gcc 3.1. */ +#if !defined(HB_VECTOR_SIZE) +# if defined( __GNUC__ ) && ( __GNUC__ >= 4 ) +# define HB_VECTOR_SIZE 128 +# else +# define HB_VECTOR_SIZE 0 +# endif +#endif +static_assert (0 == (HB_VECTOR_SIZE & (HB_VECTOR_SIZE - 1)), "HB_VECTOR_SIZE is not power of 2."); +static_assert (0 == (HB_VECTOR_SIZE % 64), "HB_VECTOR_SIZE is not multiple of 64."); +#if HB_VECTOR_SIZE +typedef uint64_t hb_vector_size_impl_t __attribute__((vector_size (HB_VECTOR_SIZE / 8))); +#else +typedef uint64_t hb_vector_size_impl_t; +#endif + + +/* HB_NDEBUG disables some sanity checks that are very safe to disable and + * should be disabled in production systems. If NDEBUG is defined, enable + * HB_NDEBUG; but if it's desirable that normal assert()s (which are very + * light-weight) to be enabled, then HB_DEBUG can be defined to disable + * the costlier checks. */ +#ifdef NDEBUG +#define HB_NDEBUG 1 +#endif + + +/* Flags */ + +/* Enable bitwise ops on enums marked as flags_t */ +/* To my surprise, looks like the function resolver is happy to silently cast + * one enum to another... So this doesn't provide the type-checking that I + * originally had in mind... :(. + * + * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163 + */ +#ifdef _MSC_VER +# pragma warning(disable:4200) +# pragma warning(disable:4800) +#endif +#define HB_MARK_AS_FLAG_T(T) \ + extern "C++" { \ + static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ + static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ + static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ + static inline T operator ~ (T r) { return T (~(unsigned int) r); } \ + static inline T& operator |= (T &l, T r) { l = l | r; return l; } \ + static inline T& operator &= (T& l, T r) { l = l & r; return l; } \ + static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ + } \ + static_assert (true, "") + +/* Useful for set-operations on small enums. + * For example, for testing "x ∈ {x1, x2, x3}" use: + * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) + */ +#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x))) +#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0) +#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x)) +#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x))) +#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0) + + +/* Size signifying variable-sized array */ +#define VAR 1 + + +/* fallback for round() */ +static inline double +_hb_round (double x) +{ + if (x >= 0) + return floor (x + 0.5); + else + return ceil (x - 0.5); +} +#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND) +#define round(x) _hb_round(x) +#endif + + +/* fallback for posix_memalign() */ +static inline int +_hb_memalign(void **memptr, size_t alignment, size_t size) +{ + if (unlikely (0 != (alignment & (alignment - 1)) || + !alignment || + 0 != (alignment & (sizeof (void *) - 1)))) + return EINVAL; + + char *p = (char *) malloc (size + alignment - 1); + if (unlikely (!p)) + return ENOMEM; + + size_t off = (size_t) p & (alignment - 1); + if (off) + p += alignment - off; + + *memptr = (void *) p; + + return 0; +} +#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN) +#define posix_memalign _hb_memalign +#endif + + +/* + * For lack of a better place, put Zawgyi script hack here. + * https://github.com/harfbuzz/harfbuzz/issues/1162 + */ + +#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g')) + + +/* Some really basic things everyone wants. */ +template <typename T> struct hb_remove_const { typedef T value; }; +template <typename T> struct hb_remove_const<const T> { typedef T value; }; +#define hb_remove_const(T) hb_remove_const<T>::value +template <typename T> struct hb_remove_reference { typedef T value; }; +template <typename T> struct hb_remove_reference<T &> { typedef T value; }; +#define hb_remove_reference(T) hb_remove_reference<T>::value +template <typename T> struct hb_remove_pointer { typedef T value; }; +template <typename T> struct hb_remove_pointer<T *> { typedef T value; }; +#define hb_remove_pointer(T) hb_remove_pointer<T>::value + + +/* Headers we include for everyone. Keep topologically sorted by dependency. + * They express dependency amongst themselves, but no other file should include + * them directly.*/ +#include "hb-atomic.hh" +#include "hb-mutex.hh" +#include "hb-null.hh" +#include "hb-dsalgs.hh" // Requires: hb-null +#include "hb-iter.hh" // Requires: hb-null +#include "hb-debug.hh" // Requires: hb-atomic hb-dsalgs +#include "hb-array.hh" // Requires: hb-dsalgs hb-iter hb-null +#include "hb-vector.hh" // Requires: hb-array hb-null +#include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector + +#endif /* HB_HH */ diff --git a/src/main.cc b/src/main.cc index ca0fcc5..490b76e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -25,9 +25,9 @@ */ #include "hb-static.cc" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-layout-gdef-table.hh" -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" #ifdef HAVE_GLIB #include <glib.h> @@ -51,10 +51,9 @@ main (int argc, char **argv) const char *font_data = hb_blob_get_data (blob, &len); printf ("Opened font file %s: %d bytes long\n", argv[1], len); - Sanitizer<OpenTypeFontFile> sanitizer; - hb_blob_t *font_blob = sanitizer.sanitize (blob); + hb_blob_t *font_blob = hb_sanitize_context_t().sanitize_blob<OpenTypeFontFile> (blob); const OpenTypeFontFile* sanitized = font_blob->as<OpenTypeFontFile> (); - if (sanitized == &Null(OpenTypeFontFile)) + if (!font_blob->data) { printf ("Sanitization of the file wasn't successful. Exit"); return 1; @@ -78,6 +77,9 @@ main (int argc, char **argv) case OpenTypeFontFile::Typ1Tag: printf ("Obsolete Apple Type1 font in SFNT container\n"); break; + case OpenTypeFontFile::DFontTag: + printf ("DFont Mac Resource Fork\n"); + break; default: printf ("Unknown font format\n"); break; diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc index 39eb13d..a91f4f7 100644 --- a/src/test-buffer-serialize.cc +++ b/src/test-buffer-serialize.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" diff --git a/src/test-iter.cc b/src/test-iter.cc new file mode 100644 index 0000000..05430b0 --- /dev/null +++ b/src/test-iter.cc @@ -0,0 +1,84 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#include "hb.hh" +#include "hb-iter.hh" + +#include "hb-array.hh" +#include "hb-set.hh" + + +template <typename T> +struct array_iter_t : hb_iter_t<array_iter_t<T>, T>, hb_iter_mixin_t<array_iter_t<T>, T> +{ + array_iter_t (hb_array_t<T> arr_) : arr (arr_) {} + + typedef T __item_type__; + T& __item_at__ (unsigned i) const { return arr[i]; } + void __forward__ (unsigned n) { arr += n; } + void __rewind__ (unsigned n) { arr -= n; } + unsigned __len__ () const { return arr.length; } + bool __random_access__ () const { return true; } + + private: + hb_array_t<T> arr; +}; + +template <typename T> +struct some_array_t +{ + some_array_t (hb_array_t<T> arr_) : arr (arr_) {} + + typedef array_iter_t<T> iter_t; + array_iter_t<T> iter () { return array_iter_t<T> (arr); } + operator array_iter_t<T> () { return iter (); } + operator hb_iter_t<array_iter_t<T> > () { return iter (); } + + private: + hb_array_t<T> arr; +}; + +int +main (int argc, char **argv) +{ + const int src[10] = {}; + int dst[20]; + hb_vector_t<int> v; + + array_iter_t<const int> s (src); /* Implicit conversion from static array. */ + array_iter_t<const int> s2 (v); /* Implicit conversion from vector. */ + array_iter_t<int> t (dst); + + some_array_t<const int> a (src); + + s2 = s; + + hb_fill (t, 42); + hb_copy (t, s); + // hb_copy (t, a.iter ()); + + return 0; +} diff --git a/src/test-name-table.cc b/src/test-name-table.cc new file mode 100644 index 0000000..518e4eb --- /dev/null +++ b/src/test-name-table.cc @@ -0,0 +1,69 @@ +/* + * Copyright © 2018 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): Behdad Esfahbod + */ + +#include "hb.hh" +#include "hb-ot.h" + +#include <stdlib.h> +#include <stdio.h> + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_blob_destroy (blob); + blob = nullptr; + + unsigned int count; + const hb_ot_name_entry_t *entries = hb_ot_name_list_names (face, &count); + + for (unsigned int i = 0; i < count; i++) + { + printf ("%u %s ", + entries[i].name_id, + hb_language_to_string (entries[i].language)); + + char buf[64]; + unsigned int buf_size = sizeof (buf); + hb_ot_name_get_utf8 (face, + entries[i].name_id, + entries[i].language, + &buf_size, + buf); + + printf ("%s\n", buf); + } + + hb_face_destroy (face); + + return count ? 0 : 1; +} diff --git a/src/test-ot-color.cc b/src/test-ot-color.cc new file mode 100644 index 0000000..4050a66 --- /dev/null +++ b/src/test-ot-color.cc @@ -0,0 +1,336 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018 Khaled Hosny + * + * 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. + */ + +#include "hb.h" +#include "hb-ot.h" + +#include "hb-ft.h" + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include <cairo.h> +#include <cairo-ft.h> +#include <cairo-svg.h> + +#include <stdlib.h> +#include <stdio.h> + +static void +svg_dump (hb_face_t *face, unsigned int face_index) +{ + unsigned glyph_count = hb_face_get_glyph_count (face); + + for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/svg-%u-%u.svg%s", + glyph_id, + face_index, + // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405 + (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : ""); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); + } +} + +/* _png API is so easy to use unlike the below code, don't get confused */ +static void +png_dump (hb_face_t *face, unsigned int face_index) +{ + unsigned glyph_count = hb_face_get_glyph_count (face); + hb_font_t *font = hb_font_create (face); + + /* scans the font for strikes */ + unsigned int sample_glyph_id; + /* we don't care about different strikes for different glyphs at this point */ + for (sample_glyph_id = 0; sample_glyph_id < glyph_count; sample_glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned int blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (blob_length != 0) + break; + } + + unsigned int upem = hb_face_get_upem (face); + unsigned int blob_length = 0; + unsigned int strike = 0; + for (unsigned int ppem = 1; ppem < upem; ppem++) + { + hb_font_set_ppem (font, ppem, ppem); + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned int new_blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (new_blob_length != blob_length) + { + for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); + } + + strike++; + blob_length = new_blob_length; + } + } + + hb_font_destroy (font); +} + +static void +layered_glyph_dump (hb_face_t *face, cairo_font_face_t *cairo_face, unsigned int face_index) +{ + unsigned int upem = hb_face_get_upem (face); + + unsigned glyph_count = hb_face_get_glyph_count (face); + for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid) + { + unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, NULL, NULL); + if (!num_layers) + continue; + + hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t)); + + hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers); + if (num_layers) + { + // Measure + cairo_text_extents_t extents; + { + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cairo_t *cr = cairo_create (surface); + cairo_set_font_face (cr, cairo_face); + cairo_set_font_size (cr, upem); + + cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t)); + for (unsigned int j = 0; j < num_layers; ++j) + glyphs[j].index = layers[j].glyph; + cairo_glyph_extents (cr, glyphs, num_layers, &extents); + free (glyphs); + cairo_surface_destroy (surface); + cairo_destroy (cr); + } + + // Add a slight margin + extents.width += extents.width / 10; + extents.height += extents.height / 10; + extents.x_bearing -= extents.width / 20; + extents.y_bearing -= extents.height / 20; + + // Render + unsigned int palette_count = hb_ot_color_palette_get_count (face); + for (unsigned int palette = 0; palette < palette_count; palette++) + { + unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, NULL, NULL); + if (!num_colors) + continue; + + hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t)); + hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors); + if (num_colors) + { + char output_path[255]; + sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index); + + cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); + cairo_t *cr = cairo_create (surface); + cairo_set_font_face (cr, cairo_face); + cairo_set_font_size (cr, upem); + + for (unsigned int layer = 0; layer < num_layers; ++layer) + { + hb_color_t color = 0x000000FF; + if (layers[layer].color_index != 0xFFFF) + color = colors[layers[layer].color_index]; + cairo_set_source_rgba (cr, + hb_color_get_red (color) / 255., + hb_color_get_green (color) / 255., + hb_color_get_blue (color) / 255., + hb_color_get_alpha (color) / 255.); + + cairo_glyph_t glyph; + glyph.index = layers[layer].glyph; + glyph.x = -extents.x_bearing; + glyph.y = -extents.y_bearing; + cairo_show_glyphs (cr, &glyph, 1); + } + + cairo_surface_destroy (surface); + cairo_destroy (cr); + } + free (colors); + } + } + + free (layers); + } +} + +static void +dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, + unsigned int num_glyphs, unsigned int face_index) +{ + for (unsigned int i = 0; i < num_glyphs; ++i) + { + cairo_text_extents_t extents; + cairo_glyph_t glyph = {0}; + glyph.index = i; + + // Measure + { + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cairo_t *cr = cairo_create (surface); + cairo_set_font_face (cr, cairo_face); + cairo_set_font_size (cr, upem); + + cairo_glyph_extents (cr, &glyph, 1, &extents); + cairo_surface_destroy (surface); + cairo_destroy (cr); + } + + // Add a slight margin + extents.width += extents.width / 10; + extents.height += extents.height / 10; + extents.x_bearing -= extents.width / 20; + extents.y_bearing -= extents.height / 20; + + // Render + { + char output_path[255]; + sprintf (output_path, "out/%u-%u.svg", face_index, i); + cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); + cairo_t *cr = cairo_create (surface); + cairo_set_font_face (cr, cairo_face); + cairo_set_font_size (cr, upem); + glyph.x = -extents.x_bearing; + glyph.y = -extents.y_bearing; + cairo_show_glyphs (cr, &glyph, 1); + cairo_surface_destroy (surface); + cairo_destroy (cr); + } + } +} + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file.ttf\n" + "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n", + argv[0], argv[0]); + exit (1); + } + + + FILE *font_name_file = fopen ("out/.dumped_font_name", "r"); + if (font_name_file != NULL) + { + fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n"); + exit (1); + } + + font_name_file = fopen ("out/.dumped_font_name", "w"); + if (font_name_file == NULL) + { + fprintf (stderr, "./out is not accessible as a folder, create it please\n"); + exit (1); + } + fwrite (argv[1], 1, strlen (argv[1]), font_name_file); + fclose (font_name_file); + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + unsigned int num_faces = hb_face_count (blob); + if (num_faces == 0) + { + fprintf (stderr, "error: The file (%s) was corrupted, empty or not found", argv[1]); + exit (1); + } + + for (unsigned int face_index = 0; face_index < hb_face_count (blob); face_index++) + { + hb_face_t *face = hb_face_create (blob, face_index); + hb_font_t *font = hb_font_create (face); + + if (hb_ot_color_has_png (face)) printf ("Dumping png (cbdt/sbix)...\n"); + png_dump (face, face_index); + + if (hb_ot_color_has_svg (face)) printf ("Dumping svg...\n"); + svg_dump (face, face_index); + + cairo_font_face_t *cairo_face; + { + FT_Library library; + FT_Init_FreeType (&library); + FT_Face ft_face; + FT_New_Face (library, argv[1], 0, &ft_face); + cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + } + if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face)) + printf ("Dumping layered color glyphs...\n"); + layered_glyph_dump (face, cairo_face, face_index); + + unsigned int num_glyphs = hb_face_get_glyph_count (face); + unsigned int upem = hb_face_get_upem (face); + + // disabled when color font as cairo rendering of NotoColorEmoji is soooo slow + if (!hb_ot_color_has_layers (face) && + !hb_ot_color_has_png (face) && + !hb_ot_color_has_svg (face)) + dump_glyphs (cairo_face, upem, num_glyphs, face_index); + + hb_font_destroy (font); + hb_face_destroy (face); + } + + hb_blob_destroy (blob); + + return 0; +} diff --git a/src/test-size-params.cc b/src/test-size-params.cc index 3c43852..12eec61 100644 --- a/src/test-size-params.cc +++ b/src/test-size-params.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" @@ -46,7 +46,7 @@ main (int argc, char **argv) blob = nullptr; unsigned int p[5]; - bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4); + bool ret = hb_ot_layout_get_size_params (face, p, p+1, (p+2), p+3, p+4); printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.); diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc index dbc5fa4..0eef8c2 100644 --- a/src/test-unicode-ranges.cc +++ b/src/test-unicode-ranges.cc @@ -24,25 +24,24 @@ * Google Author(s): Garret Rieger */ -#include "hb-private.hh" - +#include "hb.hh" #include "hb-ot-os2-unicode-ranges.hh" -void +static void test (hb_codepoint_t cp, unsigned int bit) { - if (OT::hb_get_unicode_range_bit (cp) != bit) + if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit) { fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.", - OT::hb_get_unicode_range_bit (cp), + OT::_hb_ot_os2_get_unicode_range_bit (cp), cp, bit); abort(); } } -void -test_get_unicode_range_bit (void) +static void +test_get_unicode_range_bit () { test (0x0000, 0); test (0x0042, 0); @@ -60,7 +59,7 @@ test_get_unicode_range_bit (void) } int -main (void) +main () { test_get_unicode_range_bit (); return 0; diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc index 1836d72..268f7db 100644 --- a/src/test-would-substitute.cc +++ b/src/test-would-substitute.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" diff --git a/src/test.cc b/src/test.cc index cf59e00..f0eace8 100644 --- a/src/test.cc +++ b/src/test.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" |