summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBowon Ryu <bowon.ryu@samsung.com>2019-02-14 17:33:09 +0900
committerBowon Ryu <bowon.ryu@samsung.com>2019-02-14 17:33:09 +0900
commit1baac414088e430483b85f702898c8448083bfc2 (patch)
tree59799dda277ac726617ff1b6ffb4747e775f551a /src
parentb9f425ddd6223cd82b3d35f13fbd060d3c0c0e38 (diff)
downloadharfbuzz-1baac414088e430483b85f702898c8448083bfc2.tar.gz
harfbuzz-1baac414088e430483b85f702898c8448083bfc2.tar.bz2
harfbuzz-1baac414088e430483b85f702898c8448083bfc2.zip
Imported Upstream version 2.3.1upstream/2.3.1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am134
-rw-r--r--src/Makefile.in1892
-rw-r--r--src/Makefile.sources266
-rwxr-xr-xsrc/check-includes.sh8
-rwxr-xr-xsrc/check-static-inits.sh4
-rwxr-xr-xsrc/check-symbols.sh2
-rw-r--r--src/dump-emoji.cc263
-rw-r--r--src/dump-fon.cc555
-rw-r--r--src/dump-indic-data.cc4
-rw-r--r--src/dump-khmer-data.cc12
-rw-r--r--src/dump-myanmar-data.cc4
-rw-r--r--src/dump-use-data.cc4
-rwxr-xr-xsrc/gen-def.py19
-rwxr-xr-xsrc/gen-emoji-table.py67
-rwxr-xr-xsrc/gen-indic-table.py5
-rw-r--r--src/gen-os2-unicode-ranges.py57
-rwxr-xr-xsrc/gen-tag-table.py1126
-rwxr-xr-xsrc/gen-use-table.py60
-rwxr-xr-xsrc/gen-vowel-constraints.py219
-rw-r--r--src/harfbuzz-config.cmake.in4
-rw-r--r--src/hb-aat-fdsc-table.hh126
-rw-r--r--src/hb-aat-fmtx-table.hh67
-rw-r--r--src/hb-aat-gcid-table.hh73
-rw-r--r--src/hb-aat-layout-ankr-table.hh33
-rw-r--r--src/hb-aat-layout-bsln-table.hh17
-rw-r--r--src/hb-aat-layout-common-private.hh644
-rw-r--r--src/hb-aat-layout-common.hh845
-rw-r--r--src/hb-aat-layout-feat-table.hh133
-rw-r--r--src/hb-aat-layout-just-table.hh417
-rw-r--r--src/hb-aat-layout-kerx-table.hh1019
-rw-r--r--src/hb-aat-layout-lcar-table.hh93
-rw-r--r--src/hb-aat-layout-morx-table.hh770
-rw-r--r--src/hb-aat-layout-trak-table.hh182
-rw-r--r--src/hb-aat-layout.cc416
-rw-r--r--src/hb-aat-layout.h486
-rw-r--r--src/hb-aat-layout.hh85
-rw-r--r--src/hb-aat-ltag-table.hh25
-rw-r--r--src/hb-aat-map.cc68
-rw-r--r--src/hb-aat-map.hh91
-rw-r--r--src/hb-aat.h (renamed from src/hb-ot-tag.h)37
-rw-r--r--src/hb-array.hh277
-rw-r--r--src/hb-atomic-private.hh182
-rw-r--r--src/hb-atomic.hh300
-rw-r--r--src/hb-blob.cc228
-rw-r--r--src/hb-blob.hh (renamed from src/hb-blob-private.hh)61
-rw-r--r--src/hb-buffer-deserialize-json.hh2
-rw-r--r--src/hb-buffer-deserialize-json.rl2
-rw-r--r--src/hb-buffer-deserialize-text.hh2
-rw-r--r--src/hb-buffer-deserialize-text.rl2
-rw-r--r--src/hb-buffer-serialize.cc24
-rw-r--r--src/hb-buffer.cc272
-rw-r--r--src/hb-buffer.h29
-rw-r--r--src/hb-buffer.hh (renamed from src/hb-buffer-private.hh)179
-rw-r--r--src/hb-cache.hh80
-rw-r--r--src/hb-cff-interp-common.hh725
-rw-r--r--src/hb-cff-interp-cs-common.hh905
-rw-r--r--src/hb-cff-interp-dict-common.hh294
-rw-r--r--src/hb-cff1-interp-cs.hh161
-rw-r--r--src/hb-cff2-interp-cs.hh271
-rw-r--r--src/hb-common.cc199
-rw-r--r--src/hb-common.h90
-rw-r--r--src/hb-coretext.cc382
-rw-r--r--src/hb-debug.hh99
-rw-r--r--src/hb-deprecated.h165
-rw-r--r--src/hb-directwrite.cc351
-rw-r--r--src/hb-dsalgs.hh494
-rw-r--r--src/hb-face.cc329
-rw-r--r--src/hb-face.h49
-rw-r--r--src/hb-face.hh (renamed from src/hb-face-private.hh)76
-rw-r--r--src/hb-fallback-shape.cc45
-rw-r--r--src/hb-font.cc578
-rw-r--r--src/hb-font.h114
-rw-r--r--src/hb-font.hh (renamed from src/hb-font-private.hh)290
-rw-r--r--src/hb-ft.cc271
-rw-r--r--src/hb-glib.cc108
-rw-r--r--src/hb-gobject-enums.cc.tmpl4
-rw-r--r--src/hb-gobject-enums.h.tmpl2
-rw-r--r--src/hb-gobject-structs.cc21
-rw-r--r--src/hb-gobject-structs.h4
-rw-r--r--src/hb-graphite2.cc119
-rw-r--r--src/hb-graphite2.h2
-rw-r--r--src/hb-icu.cc145
-rw-r--r--src/hb-iter.hh153
-rw-r--r--src/hb-kern.hh139
-rw-r--r--src/hb-machinery.hh931
-rw-r--r--src/hb-map.cc23
-rw-r--r--src/hb-map.hh (renamed from src/hb-map-private.hh)69
-rw-r--r--src/hb-mutex.hh (renamed from src/hb-mutex-private.hh)26
-rw-r--r--src/hb-null.hh204
-rw-r--r--src/hb-object.hh (renamed from src/hb-object-private.hh)201
-rw-r--r--src/hb-open-file.hh (renamed from src/hb-open-file-private.hh)267
-rw-r--r--src/hb-open-type-private.hh1299
-rw-r--r--src/hb-open-type.hh1008
-rw-r--r--src/hb-ot-cff-common.hh713
-rw-r--r--src/hb-ot-cff1-table.cc385
-rw-r--r--src/hb-ot-cff1-table.hh1299
-rw-r--r--src/hb-ot-cff2-table.cc136
-rw-r--r--src/hb-ot-cff2-table.hh566
-rw-r--r--src/hb-ot-cmap-table.hh734
-rw-r--r--src/hb-ot-color-cbdt-table.hh291
-rw-r--r--src/hb-ot-color-colr-table.hh122
-rw-r--r--src/hb-ot-color-cpal-table.hh211
-rw-r--r--src/hb-ot-color-sbix-table.hh209
-rw-r--r--src/hb-ot-color-svg-table.hh99
-rw-r--r--src/hb-ot-color.cc300
-rw-r--r--src/hb-ot-color.h139
-rw-r--r--src/hb-ot-deprecated.h107
-rw-r--r--src/hb-ot-face.cc61
-rw-r--r--src/hb-ot-face.hh120
-rw-r--r--src/hb-ot-font.cc289
-rw-r--r--src/hb-ot-gasp-table.hh84
-rw-r--r--src/hb-ot-glyf-table.hh342
-rw-r--r--src/hb-ot-hdmx-table.hh129
-rw-r--r--src/hb-ot-head-table.hh25
-rw-r--r--src/hb-ot-hhea-table.hh8
-rw-r--r--src/hb-ot-hmtx-table.hh158
-rw-r--r--src/hb-ot-kern-table.hh456
-rw-r--r--src/hb-ot-layout-base-table.hh677
-rw-r--r--src/hb-ot-layout-common.hh (renamed from src/hb-ot-layout-common-private.hh)1035
-rw-r--r--src/hb-ot-layout-gdef-table.hh214
-rw-r--r--src/hb-ot-layout-gpos-table.hh556
-rw-r--r--src/hb-ot-layout-gsub-table.hh874
-rw-r--r--src/hb-ot-layout-gsubgpos.hh (renamed from src/hb-ot-layout-gsubgpos-private.hh)1071
-rw-r--r--src/hb-ot-layout-jstf-table.hh48
-rw-r--r--src/hb-ot-layout.cc1229
-rw-r--r--src/hb-ot-layout.h118
-rw-r--r--src/hb-ot-layout.hh (renamed from src/hb-ot-layout-private.hh)245
-rw-r--r--src/hb-ot-map.cc79
-rw-r--r--src/hb-ot-map.hh (renamed from src/hb-ot-map-private.hh)107
-rw-r--r--src/hb-ot-math-table.hh237
-rw-r--r--src/hb-ot-math.cc66
-rw-r--r--src/hb-ot-maxp-table.hh30
-rw-r--r--src/hb-ot-name-language.cc457
-rw-r--r--src/hb-ot-name-language.hh40
-rw-r--r--src/hb-ot-name-table.hh239
-rw-r--r--src/hb-ot-name.cc224
-rw-r--r--src/hb-ot-name.h129
-rw-r--r--src/hb-ot-os2-table.hh183
-rw-r--r--src/hb-ot-os2-unicode-ranges.hh52
-rw-r--r--src/hb-ot-post-macroman.hh2
-rw-r--r--src/hb-ot-post-table.hh138
-rw-r--r--src/hb-ot-shape-complex-arabic-fallback.hh59
-rw-r--r--src/hb-ot-shape-complex-arabic-win1256.hh2
-rw-r--r--src/hb-ot-shape-complex-arabic.cc75
-rw-r--r--src/hb-ot-shape-complex-arabic.hh (renamed from src/hb-ot-shape-complex-arabic-private.hh)10
-rw-r--r--src/hb-ot-shape-complex-default.cc4
-rw-r--r--src/hb-ot-shape-complex-hangul.cc28
-rw-r--r--src/hb-ot-shape-complex-hebrew.cc18
-rw-r--r--src/hb-ot-shape-complex-indic-machine.hh1638
-rw-r--r--src/hb-ot-shape-complex-indic-machine.rl24
-rw-r--r--src/hb-ot-shape-complex-indic-table.cc5
-rw-r--r--src/hb-ot-shape-complex-indic.cc197
-rw-r--r--src/hb-ot-shape-complex-indic.hh (renamed from src/hb-ot-shape-complex-indic-private.hh)24
-rw-r--r--src/hb-ot-shape-complex-khmer-machine.hh310
-rw-r--r--src/hb-ot-shape-complex-khmer-machine.rl52
-rw-r--r--src/hb-ot-shape-complex-khmer-private.hh124
-rw-r--r--src/hb-ot-shape-complex-khmer.cc552
-rw-r--r--src/hb-ot-shape-complex-khmer.hh114
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.hh24
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.rl10
-rw-r--r--src/hb-ot-shape-complex-myanmar.cc108
-rw-r--r--src/hb-ot-shape-complex-myanmar.hh (renamed from src/hb-ot-shape-complex-myanmar-private.hh)58
-rw-r--r--src/hb-ot-shape-complex-thai.cc10
-rw-r--r--src/hb-ot-shape-complex-tibetan.cc63
-rw-r--r--src/hb-ot-shape-complex-use-machine.hh526
-rw-r--r--src/hb-ot-shape-complex-use-machine.rl40
-rw-r--r--src/hb-ot-shape-complex-use-table.cc111
-rw-r--r--src/hb-ot-shape-complex-use.cc147
-rw-r--r--src/hb-ot-shape-complex-use.hh (renamed from src/hb-ot-shape-complex-use-private.hh)15
-rw-r--r--src/hb-ot-shape-complex-vowel-constraints.cc437
-rw-r--r--src/hb-ot-shape-complex-vowel-constraints.hh (renamed from src/hb-aat-layout-private.hh)22
-rw-r--r--src/hb-ot-shape-complex.hh (renamed from src/hb-ot-shape-complex-private.hh)106
-rw-r--r--src/hb-ot-shape-fallback.cc164
-rw-r--r--src/hb-ot-shape-fallback.hh (renamed from src/hb-ot-shape-fallback-private.hh)23
-rw-r--r--src/hb-ot-shape-normalize.cc226
-rw-r--r--src/hb-ot-shape-normalize.hh (renamed from src/hb-ot-shape-normalize-private.hh)15
-rw-r--r--src/hb-ot-shape-private.hh112
-rw-r--r--src/hb-ot-shape.cc722
-rw-r--r--src/hb-ot-shape.hh129
-rw-r--r--src/hb-ot-stat-table.hh280
-rw-r--r--src/hb-ot-tag-table.hh2064
-rw-r--r--src/hb-ot-tag.cc1124
-rw-r--r--src/hb-ot-var-avar-table.hh21
-rw-r--r--src/hb-ot-var-fvar-table.hh202
-rw-r--r--src/hb-ot-var-hvar-table.hh40
-rw-r--r--src/hb-ot-var-mvar-table.hh25
-rw-r--r--src/hb-ot-var.cc122
-rw-r--r--src/hb-ot-var.h89
-rw-r--r--src/hb-ot-vorg-table.hh181
-rw-r--r--src/hb-ot.h4
-rw-r--r--src/hb-private.hh1241
-rw-r--r--src/hb-set-digest.hh (renamed from src/hb-set-digest-private.hh)59
-rw-r--r--src/hb-set.cc19
-rw-r--r--src/hb-set.hh (renamed from src/hb-set-private.hh)242
-rw-r--r--src/hb-shape-plan.cc435
-rw-r--r--src/hb-shape-plan.hh (renamed from src/hb-shape-plan-private.hh)63
-rw-r--r--src/hb-shape.cc94
-rw-r--r--src/hb-shaper-impl.hh (renamed from src/hb-shaper-impl-private.hh)23
-rw-r--r--src/hb-shaper-list.hh10
-rw-r--r--src/hb-shaper-private.hh124
-rw-r--r--src/hb-shaper.cc83
-rw-r--r--src/hb-shaper.hh134
-rw-r--r--src/hb-static.cc49
-rw-r--r--src/hb-string-array.hh2
-rw-r--r--src/hb-subset-cff-common.cc226
-rw-r--r--src/hb-subset-cff-common.hh990
-rw-r--r--src/hb-subset-cff1.cc1103
-rw-r--r--src/hb-subset-cff1.hh38
-rw-r--r--src/hb-subset-cff2.cc624
-rw-r--r--src/hb-subset-cff2.hh38
-rw-r--r--src/hb-subset-glyf.cc201
-rw-r--r--src/hb-subset-glyf.hh10
-rw-r--r--src/hb-subset-input.cc66
-rw-r--r--src/hb-subset-input.hh (renamed from src/hb-subset-private.hh)26
-rw-r--r--src/hb-subset-plan.cc100
-rw-r--r--src/hb-subset-plan.hh39
-rw-r--r--src/hb-subset.cc316
-rw-r--r--src/hb-subset.h43
-rw-r--r--src/hb-subset.hh59
-rw-r--r--src/hb-ucdn.cc85
-rw-r--r--src/hb-ucdn/Makefile.in5
-rw-r--r--src/hb-ucdn/ucdn.h4
-rw-r--r--src/hb-unicode-emoji-table.hh110
-rw-r--r--src/hb-unicode.cc140
-rw-r--r--src/hb-unicode.h83
-rw-r--r--src/hb-unicode.hh (renamed from src/hb-unicode-private.hh)99
-rw-r--r--src/hb-uniscribe.cc237
-rw-r--r--src/hb-utf.hh (renamed from src/hb-utf-private.hh)257
-rw-r--r--src/hb-vector.hh260
-rw-r--r--src/hb-version.h6
-rw-r--r--src/hb-warning.cc8
-rw-r--r--src/hb.h4
-rw-r--r--src/hb.hh658
-rw-r--r--src/main.cc12
-rw-r--r--src/test-buffer-serialize.cc2
-rw-r--r--src/test-iter.cc84
-rw-r--r--src/test-name-table.cc69
-rw-r--r--src/test-ot-color.cc336
-rw-r--r--src/test-size-params.cc4
-rw-r--r--src/test-unicode-ranges.cc15
-rw-r--r--src/test-would-substitute.cc2
-rw-r--r--src/test.cc2
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 &not_found = Crap (Type))
+ { return *as_array (len).lsearch (x, &not_found); }
+ template <typename T>
+ const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
+ { return *as_array (len).lsearch (x, &not_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 &not_found = Crap (Type))
+ { return *as_array (len).bsearch (x, &not_found); }
+ template <typename T>
+ const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
+ { return *as_array (len).bsearch (x, &not_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 &not_found = Crap (Type))
+ { return *as_array ().lsearch (x, &not_found); }
+ template <typename T>
+ const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
+ { return *as_array ().lsearch (x, &not_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 &not_found = Crap (Type))
+ { return *as_array ().bsearch (x, &not_found); }
+ template <typename T>
+ const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
+ { return *as_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_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 &param1,
+ const PARAM2 &param2)
+ {
+ 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 &param)
+ {
+ /* 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 &regions) 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 &regions,
+ 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 &param, 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 &param, 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 &param)
+ {
+ 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 &param)
+ {
+ 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
diff --git a/src/hb.h b/src/hb.h
index fc75a69..c5e7072 100644
--- a/src/hb.h
+++ b/src/hb.h
@@ -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"